上一章讲了 RAP开发中,New Service Definition,Metadata Extension,在Metadata 文件中 复习了 lineItem,selectionField,Search,ObjectModel,Value Help,headerInfo 等内容。
SAP学习笔记 - 开发45 - RAP开发 Managed App New Service Definition,Metadata Extension-CSDN博客
本章继续学习RAP相关的知识,将其他两个表的Metadata 也做一下:
- Booking_M
- BookSuppl_M
目录
1-1,New Metadata Extension - Z04_PV_Booking_M
1-2,@Metadata.allowExtensions: true - Z04_PV_Booking_M
1-3,@UI.facet - Z04_PV_Travel_M
1-4,@UI:{ lineItem / identification - Z04_PV_Booking_M
1-5,@UI.headerInfo / @UI.facet - Z04_PV_Booking_M
2-1, New Metadata Extension - Z04_PV_BookSuppl_M
2-2,@UI.headerInfo / @UI.facet - Z04_PV_BookSuppl_M
4-1,@UI.textArrangement: #TEXT_ONLY - Z04_PV_Travel_M_MD
5-2,@UI.textArrangement: #TEXT_ONLY - Z04_PV_Booking_M_MD
以下是详细内容。
1,Booking_M
上一章做了Travel_M 的开发,本章继续做剩下两个表的开发。
- New Service Definition
- Metadata Extension:lineItem,identification,Value Help,headerInfo 等
这一章想要干啥呢?
- 显示 Travel 一览
这个上一章已经做好了
- 点任意行,显示Object Page
在这个位置,将会显示Booking 列表,因为Travel - Booking 是1:N的关系
- 点击 上图Booking 列表里的任意一行,显示 Booking的Object Page
- Booking的Object Page 里面,将会显示Booking的明细,以及 1:N的Booking Supplement 列表
- 点击Booking Supplement 列表的任意一行,将会显示 Object Page
- Object Page里面,将会显示 Booking Supplement详细内容
也就是把咱之前做的3个表给串起来,一层一层的都可以参考。
(Metadata的代码,后面一并附上,可以拖到后面参考)
1-1,New Metadata Extension - Z04_PV_Booking_M
输入Name,Description,Extended Entity,然后按Next
选模板,然后点Finish
里面先不加任何东西,这样就会显示为空,然后我们后面再慢慢加
1-2,@Metadata.allowExtensions: true - Z04_PV_Booking_M
加了这行才会允许使用Metadata文件
1-3,@UI.facet - Z04_PV_Travel_M
刷新一下,就是下面这个样子
1-4,@UI:{ lineItem / identification - Z04_PV_Booking_M
设定列表中的显示项目,以及Object Page显示项目
TODO: 出了个Blocker错误,说Bookings 那块儿没数据可以显示,找了半天也没看出出来为啥
No items available.
If any exist, they will be displayed here.
利用可能なアイテムがありません
存在する場合は、ここに表示されます。
如果单独看 Booking_M 的话,是可以查出来数据的呀
查了半天,我发现了确实是数据问题,好像用错表了😓。
这也是往新建的表里插入数据的方法不同导致的。
-1 我用的方法:参照下面这种,直接把数据放内表里, 然后Insert
DATA itab TYPE TABLE OF zt04_travel_m.
itab = VALUE #(
( CLIENT = '100' TRAVEL_ID = '00005172' BOOKING_ID = '0001' BOOKING_DATE = '20250703' CUSTOMER_ID = '000563' CARRIER_ID = 'LH' CONNECTION_ID = '0400' FLIGHT_DATE = '20250712' FLIGHT_PRICE = '1540.00 ' CURRENCY_CODE = 'EUR' BOOKING_STATUS = 'N'
LAST_CHANGED_AT = '20250625051010.0000000 ' )
( 第二条数据 )
...
) ##NO_TEXT .
DELETE FROM zt04_travel_m.
INSERT zt04_travel_m FROM TABLE @itab.
-2 这次因为是从/DMO 中的表,原封不动拷贝过来,数据也要拷过来,所以用下面这种较好
DELETE FROM zt04_Travel_m.
DELETE FROM zt04_booking_m.
DELETE FROM zt04_bookSuppl_m.
INSERT zt04_Travel_m FROM ( SELECT * FROM /dmo/travel_m ).
INSERT zt04_booking_m FROM ( SELECT * FROM /dmo/booking_m ).
INSERT zt04_Booksuppl_m FROM ( SELECT * FROM /dmo/booksuppl_m ).
Commit work.
那么 第1种有啥问题呢?/DMO里除了 /dmo/travel_m 以外,还有/dmo/travel,那可不容易用错
而要是用SQL,那基本上不会错,而且简单:)
大念三遍【所有事情的发生都必然有其目的,并且有利于我!】,洗脑完毕,咱们继续话题啊。
这样 Bookings列表 就会显示出来。
1-5,@UI.headerInfo / @UI.facet - Z04_PV_Booking_M
这样就可以显示Booking_M 的Object Page页面,以及显示明细,和 BookSuppl_M的列表
其实 BookSuppl_M 列表应该显示不出来,我上面为了调查数据显示不出来,先把Metadata 做了
2,BookSuppl_M
2-1, New Metadata Extension - Z04_PV_BookSuppl_M
这个配合1-5,显示出了 BookSuppl_M 列表。
2-2,@UI.headerInfo / @UI.facet - Z04_PV_BookSuppl_M
这样就可以显示BookSuppl_M 的Object Page页面,以及显示明细
BookSuppl_M 的Object Page页面就显示出来了。
3,完整的代码(Metadata)和页面截图
3-1,Travel_M_MD
@Metadata.layer: #CORE
@Search.searchable: true
@UI.headerInfo: {
typeName: 'Travel',
typeNamePlural: 'Travels',
title: {
type: #STANDARD,
label: 'Travel',
value: 'TravelId'
}
}
annotate view Z04_PV_Travel_M with
{
@UI.facet: [
{
id: 'TravelDetail',
purpose: #STANDARD,
parentId: '',
position: 10,
label: 'Travel Detail',
type: #IDENTIFICATION_REFERENCE
},
{
id: 'Booking',
purpose: #STANDARD,
parentId: '',
position: 20,
label: 'Bookings',
targetElement: '_Booking',
type: #LINEITEM_REFERENCE
}
]
@UI:{ lineItem:[{ position: 10 }],
identification: [{ position: 10 }]
}
@Search.defaultSearchElement: true
TravelId;
@UI:{ lineItem:[{ position: 20 }],
selectionField: [{ position: 20 }],
identification: [{ position: 20 }]
}
@Search.defaultSearchElement: true
@Consumption.valueHelpDefinition: [{ entity: {
name: '/DMO/I_Agency',
element: 'AgencyID'
},
label: 'Agency'
}]
AgencyId;
// AgencyName;
@UI:{ lineItem:[{ position: 30 }],
selectionField: [{ position: 30 }],
identification: [{ position: 30 }]
}
@Search.defaultSearchElement: true
@Consumption.valueHelpDefinition: [{
entity: {
name: '/DMO/I_Customer',
element: 'CustomerID'
},
label: 'Customer'
}]
CustomerId;
// CustomerName;
@UI:{ lineItem:[{ position: 40 }],
identification: [{ position: 40 }]
}
BeginDate;
@UI:{ lineItem:[{ position: 50 }],
identification: [{ position: 50 }]
}
EndDate;
@UI:{identification: [{ position: 55 }]
}
BookingFee;
@UI:{ lineItem:[{ position: 60 }],
identification: [{ position: 60 }]
}
TotalPrice;
@Consumption.valueHelpDefinition: [{
entity: {
name: 'I_Currency',
element: 'Currency'
},
label: 'Currency'
}]
CurrencyCode;
@UI:{identification: [{ position: 65 }]
}
Description;
@UI:{ lineItem:[{ position: 70 }],
selectionField: [{ position: 70 }],
identification: [{ position: 70 }]
}
@Search.defaultSearchElement: true
@Consumption.valueHelpDefinition: [{
entity: {
name: '/DMO/I_Overall_Status_VH',
element: 'OverallStatus'
},
label: 'Overall Status'
}]
OverallStatus;
// OverallStatusText;
// CreatedBy;
// CreatedAt;
// LastChangedBy;
@UI.hidden: true
LastChangedAt;
// /* Associations */
// _Agency;
// _Booking;
// _Currency;
// _Customer;
// _Status;
}
点 开始
3-2,Booking_M_MD
@Metadata.layer: #CORE
@UI.headerInfo: {
typeName: 'Booking',
typeNamePlural: 'Bookings',
title: {
type: #STANDARD,
label: 'Booking',
value: 'BookingId'
}
}
annotate view Z04_PV_Booking_M with
{
@UI.facet: [
{
id: 'BookingDetail',
purpose: #STANDARD,
parentId: '',
position: 10,
label: 'Booking Detail',
type: #IDENTIFICATION_REFERENCE
},
{
id: 'BookSuppl',
purpose: #STANDARD,
position: 20,
label: 'Booking Supplment',
type: #LINEITEM_REFERENCE,
targetElement: '_BookingSupplement'
}
]
// TravelId;
@UI:{ lineItem:[{ position: 20 }],
identification: [{ position: 20 }]
}
BookingId;
@UI:{ lineItem:[{ position: 30 }],
identification: [{ position: 30 }]
}
BookingDate;
@UI:{ lineItem:[{ position: 40 }],
identification: [{ position: 40 }]
}
CustomerId;
@UI:{ lineItem:[{ position: 50 }],
identification: [{ position: 50 }]
}
CarrierId;
@UI:{ lineItem:[{ position: 60 }],
identification: [{ position: 60 }]
}
ConnectionId;
@UI:{ lineItem:[{ position: 70 }],
identification: [{ position: 70 }]
}
FlightDate;
@UI:{ lineItem:[{ position: 80 }],
identification: [{ position: 80 }]
}
FlightPrice;
// CurrencyCode;
@UI:{ lineItem:[{ position: 90 }],
identification: [{ position: 90 }]
}
BookingStatus;
@UI.hidden: true
LastChangedAt;
}
3-1 中 Travel_M 列表点任意一条,显示Travel_M的明细(Object Page)
3-3,BookSuppl_M_MD
@Metadata.layer: #CORE
@UI.headerInfo: {
typeName: 'Booking Supplement',
typeNamePlural: 'Booking Supplements',
title: {
type: #STANDARD,
label: 'Booking Supplement',
value: 'BookingSupplementId'
}
}
annotate view Z04_PV_BookSuppl_M with
{
@UI.facet: [{
id: 'BookSuppl',
purpose: #STANDARD,
position: 10,
label: 'Booking Supplment',
type: #IDENTIFICATION_REFERENCE
}]
// TravelId;
// BookingId;
@UI:{ lineItem:[{ position: 10 }],
identification: [{ position: 10 }]
}
BookingSupplementId;
@UI:{ lineItem:[{ position: 20 }],
identification: [{ position: 20 }]
}
SupplementId;
@UI:{ lineItem:[{ position: 30 }],
identification: [{ position: 30 }]
}
Price;
// CurrencyCode;
@UI.hidden: true
LastChangedAt;
// /* Associations */
// _Booking;
// _Supplement;
// _SupplementText;
// _Travel;
}
3-2 中 Booking_M 列表点任意一条,显示Booking_M的明细(Object Page)
然后点 Booking Supplement 列表中的任意一项,会显示其 Object Page页面
上面是我们想实现的主要功能。
除此之外,还有一些功能也想加上,比如Search,ObjectModel 等等。
4,Travel_M_MD 其他功能
4-1,@UI.textArrangement: #TEXT_ONLY - Z04_PV_Travel_M_MD
这个是啥呢?
其实就是 Key - Value 值的显示方式设定。
比如OverallStatus 在Projection View里用 @ObjectModel.text.element: [ 'OverallStatusText' ]显示名称,默认是 Value(Key) 的形式。
多数情况下客户也喜欢这种方式,但是也不总是如此,比如这里的Status,就不想显示Key,只要Value,那该怎么办呢?
就是用这个@UI.textArrangement: #TEXT_ONLY。
深入看一下各个选项:
在 SAP RAP (ABAP RESTful Application Programming) 和 Fiori Elements 中,@UI.textArrangement
注解用于控制字段文本的显示方式,特别是在表格列或表单中。以下是该注解的可用选项及其含义:
a,@UI.textArrangement
的选项
选项值 | 说明 | 适用场景 | 示例 |
---|---|---|---|
#TEXT_ONLY | 仅显示文本值,不显示图标或附加信息 | 纯文本字段(如名称、描述) | Name: John |
#TEXT_FIRST | 文本在前,图标或其他元素在后 | 带状态图标的文本(如状态+文本) | Completed ✅ |
#TEXT_LAST | 文本在后,图标或其他元素在前 | 图标优先的显示(如货币符号+金额) | $ 100.00 |
#TEXT_SEPARATE | 文本与图标/附加信息分开显示(通常分行) | 需要清晰分隔的复杂字段 | Status: ✅ Approved |
#ICON_ONLY | 仅显示图标,隐藏文本 | 空间有限时(如操作栏图标) | 🛑 (无文本) |
#ICON_FIRST | 图标在前,文本在后 | 状态指示(如错误图标+消息) | ⚠️ Warning |
#ICON_LAST | 图标在文本后 | 次要图标补充(如链接后的外部图标) | Details ↗ |
b,使用示例
1. 在 CDS View 中定义
abap
@UI: {
lineItem: [{
position: 10,
label: 'Status',
// 文本在前,状态图标在后
textArrangement: #TEXT_FIRST
}],
identification: [{
position: 20,
label: 'Price',
// 货币符号在前,金额在后
textArrangement: #TEXT_LAST
}]
}
define view Z_MyEntity {
@UI.hidden: true
key id,
@Consumption.valueHelpDefinition: [{ entity: { name: 'I_StatusIcon' } }]
status,
@Semantics.amount.currencyCode: 'CurrencyCode'
price,
CurrencyCode
}
2. 效果对比
-
#TEXT_FIRST
:
Completed ✅
-
#ICON_FIRST
:
⚠️ Error
-
#TEXT_SEPARATE
:
Status:
✅ Approved
c,注意事项
-
依赖字段类型:
-
如果字段没有关联图标(如通过
@UI.statusIcon
或值帮助定义),#ICON_*
选项可能无效。
-
-
Fiori Elements 兼容性:
-
部分选项可能因 Fiori 版本不同而表现略有差异(建议测试目标版本)。
-
-
组合使用:
-
常与以下注解配合使用:
abap
-
-
-
@UI.statusIcon: // 定义状态图标 @UI.dataPoint: // 控制数据点样式
-
d,常见问题
Q:为什么设置了 #ICON_FIRST
却不显示图标?
A:检查是否缺少图标定义(如 @UI.statusIcon
或值帮助实体未提供图标元数据)。
如果需要更具体的场景示例,可以提供您的字段类型和预期效果!
画面效果如下:
Object Page页面:
5,Booking_M_MD 其他功能
5-1,Search
- @Search.searchable: true:显示检索框
- @Search.defaultSearchElement: true:定义检索框对应的检索对象
- TravelId;
- BookingId;
- CustomerId;
画面效果就是这个搜索框
TODO:不知为啥,这个搜索框好像不太好用
5-2,@UI.textArrangement: #TEXT_ONLY - Z04_PV_Booking_M_MD
先给几个字段加上Name/or Text - Z04_PV_Booking_M
- CustomerId ,CustomerName
- CarrierId,CarrierName
- BookingStatus,BookingStatusText
然后再到 Z04_PV_Booking_M_MD 里面,给BookingStatus 字段加上下面annotation:
- textArrangement: #TEXT_ONLY
运行看效果:
- 列表中 Booking Status项目只显示名称
还有些需要添加的内容,尤其是Value Help 部分,放到下一章说。
现在文章是越写越长了😓
以上就是本篇的全部内容。
更多SAP顾问业务知识请点击下面目录链接或东京老树根的博客主页
https://blog.csdn.net/shi_ly/category_12216766.html