Welcome to Jim's Blog

欢迎欢迎


  • 首页

  • 分类

  • 归档

  • 标签

  • 搜索

Sapui5_Project_BP

发表于 2018-02-06 | | 阅读次数

从项目的角度整体的整理一下,将一些认为比较好的点收集一下,以后在开发的时候可以快速借鉴,提高效率

文件结构

一般一个项目会做很多页面,这些页面中会有很多共用的元素,比如共用的view,fragment,CSS,一些共用的处理函数等都可以做成共用的。


上图中的ZSHBZCOMMON就是一个共用的工程,里面有一个common文件夹,里面有共用的view,fragment,controller和css,下面分别用几个例子来依次举例不同的共用元素。
一般可以把共用的内容单独放在一个view里,通过部署后的服务路径来进行引用,就像下面的 "/sap/bc/ui5_ui5/sap/zshbzcommon/common",但是这样写的话在开发过程中是不方便调试的(服务器上的代码不方便随意加端点),所以可以把共用内容先down到本地工程中,做为本工程的文件进行引用,部署后只要注册一下正确的路径就可以了。

共用工程的引用
  1. 在引用工程的Component.js文件中

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    init: function() {
    debugger;
    var commonComponentPath;
    //根据当前URL判断使用
    var loc = location.href.toLowerCase();
    if (loc.indexOf("fiorilaunchpad.html") > 0) {
    commonComponentPath = "/sap/bc/ui5_ui5/sap/zshbzcommon/common";
    } else {
    //本地common组件用来做debug测试
    commonComponentPath = "/webapp/common";
    }
    //注册common地址,以便后面引用
    jQuery.sap.registerModulePath("sh.bz.common", commonComponentPath);
  2. 在rootview就可以使用之前注册的路径来使用共用组件 ,如下面费用申请单应用的rootview FYSQHome.view.xml:

  3. 在引用工程的controller.js文件中

保存草稿


判断OData是否成功并读取到了值if(data.results && data.results.length>0

日期格式化

在Component.js文件中先声明下面代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 对Date的扩展,将 Date 转化为指定格式的String
// 月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q) 可以用 1-2 个占位符,
// 年(y)可以用 1-4 个占位符,毫秒(S)只能用 1 个占位符(是 1-3 位的数字)
// 例子:
// (new Date()).Format("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423
// (new Date()).Format("yyyy-M-d h:m:s.S") ==> 2006-7-2 8:9:4.18
Date.prototype.Format = function (fmt) { //author: meizz
var o = {
"M+": this.getMonth() + 1, //月份
"d+": this.getDate(), //日
"h+": this.getHours(), //小时
"m+": this.getMinutes(), //分
"s+": this.getSeconds(), //秒
"q+": Math.floor((this.getMonth() + 3) / 3), //季度
"S": this.getMilliseconds() //毫秒
};
if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
for (var k in o)
if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
return fmt;
}

调用的时候就可以直接用了

1
2
var time1 = new Date().Format("yyyy-MM-dd");
var time2 = new Date().Format("yyyy-MM-dd HH:mm:ss");

控制参数

在Component.js中定义全局config参数,就可以在程序的各个view的controller中使用,config参数就是一个个的键值对,如下图

1
2
3
4
5
6
7
8
config: {
fullWidth: true,
resourceBundle: "i18n/messageBundle.properties",
serviceConfig: {
name: "",
serviceUrl: "/sap/opu/odata/"
}
},


使用时在页面的init中就可以通过下面的方式取出:

1
this.oConfig = this.oComponent.getMetadata().getConfig().serviceConfig;

输入检查
  1. 必输检查
  2. 输入长度检查
  3. 输入有效性检查
    输入帮助
    得到登录用户和语言

    OData选择确认窗口
    下面是一个挺不错的例子(其中jQuery.sap.syncStyleClass还不理解是什么意思,目测是同步两个view的样式)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    onConfirmReadDraft: function(oEvent,that) {
    //关闭上一级窗口
    that.oDialogReadDraft.close();
    //判断fragment是否已经实例化
    if (!that.oDialogSelectDraft) {
    that.oDialogSelectDraft = sap.ui.xmlfragment("fs.fk.Common.view.expreq.dialogfragment.DialogSelectDraft", that);
    jQuery.sap.syncStyleClass(that.getOwnerComponent().getContentDensityClass(),that.getView(), that.oDialogSelectDraft);
    that.getView().addDependent(that.oDialogSelectDraft);
    }
    //访问odata取数据
    var oDataModel = new sap.ui.model.odata.ODataModel("/sap/opu/odata/sap/YDZODATA_SRV/", true);
    var userId = that._sLogonUserId;
    var sPath = "HeadSet?$filter=Bdtyp eq '"+_bdtyp+"' and Statu eq '0' and Cuser eq '"+userId+"' and Batnr eq '0'";
    var that = that;
    oDataModel.read(sPath, {
    async: false,
    success: function(data, response) {
    //清空model数据
    that.getView().getModel("DraftData").getData().DraftList = []
    //判断是否有数据
    if(data.results && data.results.length>0){
    //依次填充model数据
    for(var i =0;i<data.results.length;i++){
    that.getView().getModel("DraftData").getData().DraftList.push({
    "Number":data.results[i].Dzdnr,//动支单号
    "Batnr":data.results[i].Batnr,//动支批单号
    "Fistl":data.results[i].Fistl,//基金中心
    "Namex":data.results[i].Namex,//基金中心名称
    "Agent":data.results[i].Pernm,//动支人
    "AgentId":data.results[i].Psnid,
    "TotalAmount":Formatter.FloatFormat(parseFloat(data.results[i].Wrbtr)),//动支总金额
    "Currency":data.results[i].Waers,//货币
    "Issue":data.results[i].Title,//动支事项
    "Notes":data.results[i].Cmemo //事项说明
    });
    }
    }
    //刷新model
    that.getView().getModel("DraftData").refresh();
    },
    error: function(error) {}
    });
    that.oDialogSelectDraft.open();
    sap.ui.getCore().byId('idSelectDraftTable').removeSelections();
    },

this that

how to connect multiple backend server

公司的前端fiori server目前只有一个开发机,开发机分两个client 120 130,120是开发环境,130有数据可以进行测试,所以我们就需要让前端这个开发环境连接两个不同的client来分别进行开发和测试,以下是前端的配置过程:

  1. SM59分别创建120和130的RFC连接
  2. 分别为120和130创建别名
  3. 然后就可以在服务中添加系统别名进行连接了,

    不想在这配在SPRO中也可以

    注意这里有两组checkbox

    通过修改这个来确定服务的连接和metadata的连接.
Service Maintenance missing

在做Odata开发时发现SEGW的Sevice Maintenance是空的,每次测试服务的时候都要打开笔记打开那个难记的TCODE/IWFND/MAINT_SERVICE来打开Gateway的客户端。很不方便,下图这个位置,这里是我刚配上的LOCAL,点击SAP Gateway Client就能直接进到服务测试界面了。

配置过程如下:

  1. SM59创建RFC,这个相信大家都知道,不截图了
  2. 创建系统Alias


    3.

Sapui5-Model

发表于 2018-01-15 | | 阅读次数

JSONModel

JsonModel是SapUI5最常用的一种Model。所以必须非常熟练的掌握。

声明(实例化)

controller中应用JsonModel,首先引入modulesap.ui.model.json.JSONModel

1
2
3
4
5
6
7
sap.ui.define(
["sap/ui/model/json/JSONModel"],
function(JSONModel),
{
...
}
);

引入后,就可以使用var aJsonModel = new JSONModel();来声明一个JSONModel,当然不引入也可以,那就需要每次都写完整的路径,var aJsonModel = new sap.ui.model.json.JSONModel()

用法

常用的API有

  1. loadData 通过路径来加载一个Json对象
  2. setData
  3. getData 返回Json对象
  4. getJSON 字符串形式返回Json对象
  5. setProperty 修改Json对象中某一属性值
  6. getProperty 返回Json对象中某一属性值
  7. setDefaultBindMode
赋值
  1. 传入一个JSON数据格式的对象,使用setData()方法:
  2. 直接在setData中写JSON对象({key1:value1,key2:value2…})
绑定

在View中进行绑定:this.getView().setModel(JsonModel,”[别名]”)。绑定后就可以在view中通过{[别名]>/key1}来使用

延伸

OData-filter

发表于 2017-12-27 | | 阅读次数

Gateway的OData不可以直接自定义参数传入,filter可以侧面的解决这个问题,后端的开发也比较简单,它只能用的GET_ENTITYSET中,如下例:

/sap/opu/odata/sap/ZGRC_ROLES_SRV/ZROLESet?$filter= XT eq 'ECTCLNT800' and GS eq '10000001' and MK eq 'FI'
在EntitySet后加’?$filter=’,然后接要传入的filter条件,这时个可以看下图,这个data model的getentity方法中有两个参数IV_FILTER_STRING和IT_FILTER_SELECT_OPTIONS可以捕获到传入的值,可以根据需要使用。



如果输入有'就需要转义,比如要传入 ECTCLNT800's server,就需要写成XT eq 'ECTCLNT800''s server'

需要注意的一点是,如果同一个参数要传入多个值,比如这里要传入GS eq ‘10000001’,GS eq ‘10000002’,GS eq ‘10000003’,简单的这样写$filter= XT eq 'ECTCLNT800' and GS eq '10000001' or GS eq '10000002' or GS eq '10000003' and MK eq 'FI'时IT_FILTER_SELECT_OPTIONS参数是没有值的。用or时只能有一个filter参数,多个参数时不要这样用

虽然IV_FILTER_STRING有值,使用起来也很难受。

那同一个参数传入多个值怎么办?
我的测试是这样的,虽然SAP的Gateway Client不能这样用,但实际在前端的使用中是不受影响的。参照下面的写法,是可以正常传入的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var aFilter = [];
   aFilter.push(new sap.ui.model.Filter("ZMKSel",sap.ui.model.FilterOperator.EQ,"01"));
   aFilter.push(new sap.ui.model.Filter("ZOrgUnitSel",sap.ui.model.FilterOperator.EQ,"A01"));
   aFilter.push(new sap.ui.model.Filter("ZBCSFlag",sap.ui.model.FilterOperator.EQ,""));
   aFilter.push(new sap.ui.model.Filter("ZUser",sap.ui.model.FilterOperator.EQ,"10000006"));
   aFilter.push(new sap.ui.model.Filter("ZUser",sap.ui.model.FilterOperator.EQ,"10000007"));
   
   oModel.read("/ZMKSet",{
    urlParameters: '&$format=json',
    filters: aFilter,
    success: function(oData) {
     alert('success');
    },
    error: function(oData) {
     alert('failed');
    }
   });

GET_ENTITYSET中的写法,可以用IT_FILTER_SELECT_OPTIONS也可以用方法来取,一样的:

1
2
3
DATA: lt_filter_options TYPE /iwbep/t_mgw_select_option.
lt_filter_options = io_tech_request_context->get_filter( )->get_filter_select_options( ).

下面放一个实际的代码例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
METHOD zroleset_get_entityset.
**TRY.
*CALL METHOD SUPER->ZROLESET_GET_ENTITYSET
* EXPORTING
* IV_ENTITY_NAME =
* IV_ENTITY_SET_NAME =
* IV_SOURCE_NAME =
* IT_FILTER_SELECT_OPTIONS =
* IS_PAGING =
* IT_KEY_TAB =
* IT_NAVIGATION_PATH =
* IT_ORDER =
* IV_FILTER_STRING =
* IV_SEARCH_STRING =
** IO_TECH_REQUEST_CONTEXT =
** IMPORTING
** ET_ENTITYSET =
** ES_RESPONSE_CONTEXT =
* .
** CATCH /IWBEP/CX_MGW_BUSI_EXCEPTION .
** CATCH /IWBEP/CX_MGW_TECH_EXCEPTION .
**ENDTRY.
DATA: l_zmk_sel TYPE string,
l_zsys_sel TYPE string,
l_zcomp_sel TYPE string,
l_zroleid_sel TYPE string,
l_zrolems_sel TYPE string,
l_zroleyw_sel TYPE string,
l_zcount_sel TYPE i.
DATA: lt_role TYPE STANDARD TABLE OF zgrc_s_rfc_req_item,
ls_role LIKE LINE OF lt_role,
lt_user TYPE STANDARD TABLE OF zgrc_s_rfc_user_info,
ls_user LIKE LINE OF lt_user.
DATA: lt_filter_options TYPE /iwbep/t_mgw_select_option.
DATA ls_filter TYPE /iwbep/s_mgw_select_option.
DATA ls_filter1 TYPE /iwbep/s_cod_select_option.
DATA:lt_roleinfo TYPE STANDARD TABLE OF zcl_zgrc_roles_mpc=>ts_zrole .
DATA ls_roleinfo LIKE LINE OF lt_roleinfo.
lt_filter_options = io_tech_request_context->get_filter( )->get_filter_select_options( ).
LOOP AT lt_filter_options INTO ls_filter.
CASE ls_filter-property.
WHEN 'ZMK_SEL'.
READ TABLE ls_filter-select_options INTO ls_filter1 INDEX 1.
l_zmk_sel = ls_filter1-low.
WHEN 'ZSYS_SEL'.
READ TABLE ls_filter-select_options INTO ls_filter1 INDEX 1.
l_zsys_sel = ls_filter1-low.
WHEN 'ZCOMP_SEL'.
READ TABLE ls_filter-select_options INTO ls_filter1 INDEX 1.
l_zcomp_sel = ls_filter1-low.
WHEN 'ZROLEID_SEL'.
READ TABLE ls_filter-select_options INTO ls_filter1 INDEX 1.
l_zroleid_sel = ls_filter1-low.
WHEN 'ZROLEMS_SEL'.
READ TABLE ls_filter-select_options INTO ls_filter1 INDEX 1.
l_zrolems_sel = ls_filter1-low.
WHEN 'ZROLEYW_SEL'.
READ TABLE ls_filter-select_options INTO ls_filter1 INDEX 1.
l_zroleyw_sel = ls_filter1-low.
WHEN 'ZUSER'.
LOOP AT ls_filter-select_options INTO ls_filter1.
ls_user-USERID = ls_filter1-low.
APPEND ls_user TO lt_user.
ENDLOOP.
WHEN OTHERS.
ENDCASE.
ENDLOOP.
IF l_zcount_sel = 0.
l_zcount_sel = 99999.
ENDIF.
CALL FUNCTION 'ZGRC_FM_ROLE_GETLIST'
EXPORTING
zmk_sel = l_zmk_sel
zsys_sel = l_zsys_sel
zcomp_sel = l_zcomp_sel
zroleid_sel = l_zroleid_sel
zrolems_sel = l_zrolems_sel
zroleyw_sel = l_zroleyw_sel
zcount_sel = l_zcount_sel
TABLES
mt_role = lt_role
mt_user = lt_user.
IF sy-subrc = 0.
LOOP AT lt_role INTO ls_role .
"过滤‘角色’‘角色描述’‘业务角色’
IF l_zroleyw_sel IS NOT INITIAL.
IF ls_role-funarea_desc CS l_zroleyw_sel.
ELSE.
CONTINUE.
ENDIF.
ENDIF.
IF l_zrolems_sel IS NOT INITIAL.
IF ls_role-role_desc CS l_zrolems_sel.
ELSE.
CONTINUE.
ENDIF.
ENDIF.
IF l_zroleid_sel IS NOT INITIAL.
IF LS_ROLE-ITEM_NAME CS l_zroleid_sel.
ELSE.
CONTINUE.
ENDIF.
ENDIF.
ls_roleinfo-ZROLEID_SEL = ls_role-item_name.
MOVE-CORRESPONDING ls_role TO ls_roleinfo.
APPEND ls_roleinfo TO lt_roleinfo.
ENDLOOP.
ENDIF.
et_entityset = lt_roleinfo[].
ENDMETHOD.

filter的operator可以参考下图:

除了这些operator之外,还可以直接用一些函数来转义:

我没有一一测试,大多是可以用的,像startswith这种还是很好用的,它在后端自动会转变为CP,如and startswith(MK,'FI')

$select

$select可以指定要返回的字段,这个参数不需要在后端指定

这里就返回了指定的ROLE和Funarea两个字段

参考

http://www.odata.org/documentation/odata-version-2-0/uri-conventions/

Odata_expand

发表于 2017-12-16 | | 阅读次数

$expand是一个非常强大的参数,它允许你一次返回多个entityset,而不用多次调用服务。要使用它的话就必须要创建association o或navigation,所在先建一个header和item

Sapui5_Hierarchy

发表于 2017-12-16 | | 阅读次数
参考

SAP Hierarchy Nodes:
https://help.sap.com/saphelp_nw73/helpdata/en/4a/245d72b1160456e10000000a421937/frameset.htm

SAP Annotations for OData Version 2.0:
https://wiki.scn.sap.com/wiki/display/EmTech/SAP+Annotations+for+OData+Version+2.0

TreeTable Odata binding:
https://blogs.sap.com/2015/10/23/treetable-odata-binding/#jive_content_id_2_Hierarchy_using_annotations

12…8
Jim Guo

Jim Guo

Hi~

36 日志
5 分类
22 标签
© 2018 Jim Guo
由 Hexo 强力驱动
主题 - NexT.Mist