文章目录
20240723笔记-一种多报表平台的通用模式
1背景
实际业务会存在,一个业务场景,多个相关Tcode。因此,对于具体的用户来讲,一个多报表平台是很有必要的。
限制于作者的项目经验不多,有不完善的可以补充。
备注:后面的更新(如有),只更新源码,中间的那一块太散了,不想更新。
2已有的案例
作者已知的多报表平台分为两种实现方式,一种是dialog屏幕按钮点击跳转,一种是选择屏幕AT SELECTION-SCREEN OUTPUT跳转。描述的不是很清晰,看下面效果截图。
2.1方案1dialog屏幕跳转
单击按钮,执行SUBMIT xxx VIA SELECTION-SCREEN AND RETURN。
SUBMIT (lv_programname) VIA SELECTION-SCREEN AND RETURN.
2.2方案2AT SELECTION-SCREEN OUTPUT
在用户点击不同的RADIOBUTTON GROUP的时候,触发事件AT SELECTION-SCREEN OUTPUT,更新选择屏幕下侧内容为实际指向程序的选择屏幕。
2.3优缺点
优点 | 缺点 | |
---|---|---|
方案1 | 开发速度快,只需要简单了解dialog绘制屏幕 | 无法直观查看到选择屏幕 |
新增或减少子功能几乎无开发量 | ||
方案2 | 可以通过单选按钮,快速查阅选择屏幕 | 开发量大 |
要求对选择屏幕非常熟悉,各种事件,以及更改screen属性 | ||
新增很麻烦,与子功能程序的选择屏幕复杂程度成正比 |
我就不说为啥会出现方案2了,都是泪。
3新方案
3.1需求背景
在项目推进过程中,经常需要在报表平台新增子功能。开发量非常大,因此作者想设计一个便于移植的,快速配置的模式。当然,是达不到方案1的程度。
3.2方案3基于内存的循环submit跳转方案
名字没想好,就这样。
需要增加配置表
准备好include文件(下附代码),准备好RADIOBUTTON GROUP。
*======================================================================*
* Input Selection Screen
*======================================================================*
SELECTION-SCREEN BEGIN OF BLOCK zcommon_head WITH FRAME TITLE text998.
SELECTION-SCREEN:BEGIN OF LINE.
PARAMETERS:p_zzz RADIOBUTTON GROUP rg1 MODIF ID md USER-COMMAND uc1 DEFAULT 'X'.
SELECTION-SCREEN: COMMENT 3(35) text999.
SELECTION-SCREEN:END OF LINE.
SELECTION-SCREEN:BEGIN OF LINE.
PARAMETERS:p_e067 RADIOBUTTON GROUP rg1 MODIF ID a01. "
SELECTION-SCREEN: COMMENT 3(35) text029 MODIF ID a01.
PARAMETERS:p_e068 RADIOBUTTON GROUP rg1 MODIF ID a02. "
SELECTION-SCREEN: COMMENT 43(79) text030 MODIF ID a02.
SELECTION-SCREEN:END OF LINE.
SELECTION-SCREEN END OF BLOCK zcommon_head.
注意COMMENT 3(35) text999,没有使用文本元素。考虑到子功能程序可能是不同的开发做的,所以头文件不使用文本元素防止冲突。
参考SAP标准范例,文本赋值在AT SELECTION-SCREEN OUTPUT.
平台程序代码,只用到两个事件。
AT SELECTION-SCREEN OUTPUT用于获取用户选择的RADIOBUTTON GROUP,判断是否跳转子程序。
INITIALIZATION,获取配置表信息。
REPORT ytest_kevin5.
INCLUDE zcommon_head.
"平台程序自开发模板
AT SELECTION-SCREEN OUTPUT.
PERFORM frm_get_selectscreen_comment."获取选择屏幕的字段值
PERFORM frm_common_head_modify_screen."是否隐藏选择屏幕
PERFORM frm_common_head_jumpto."平台跳转子功能程序
INITIALIZATION.
PERFORM frm_common_head_init."获取平台程序配置表
PERFORM frm_common_head_init."获取平台程序配置表
FORM frm_common_head_init.
IF sy-tcode = 'SE38'."如果用户手动执行,找当前程序名的tcode
"1个程序可能对应多个Tcode,如果遇到这种情况,打一顿开发。打不过开发就把测试的人打一顿。
SELECT SINGLE tcode FROM tstc
WHERE pgmna = @sy-repid
INTO @gv_zcommon_head_tcode.
ELSE.
gv_zcommon_head_tcode = sy-tcode.
ENDIF.
"DEV-test-----这是因为测试程序,没包Tcode,上一步获取不到gv_zcommon_head_tcode
IF sy-sysid = 'EWD'.
gv_zcommon_head_tcode = 'YTEST_KEVIN5'.
ELSEIF AND sy-sysid = 'EWQ'.
BREAK-POINT.
ELSE.
ENDIF.
IF gv_zcommon_head_tcode IS NOT INITIAL.
CLEAR:gt_zewmtplatform.
SELECT *
FROM zewmtplatform
WHERE programkey = @gv_zcommon_head_tcode
INTO TABLE @gt_zewmtplatform.
ENDIF.
ENDFORM.
PERFORM frm_get_selectscreen_comment."获取选择屏幕的字段值
缺变量定义看后面的源码
FORM frm_get_selectscreen_comment.
LOOP AT gt_zewmtplatform INTO gs_zewmtplatform ."遍历配置表
UNASSIGN <fs_zcommon_head_linetext>.
ASSIGN (gs_zewmtplatform-linetext) TO <fs_zcommon_head_linetext>."DEMO:assign 'TEXT029' to
IF <fs_zcommon_head_linetext> IS ASSIGNED.
<fs_zcommon_head_linetext> = gs_zewmtplatform-linetextvalue."选择屏幕的文本 DEMO:ZEWM***
ENDIF.
ENDLOOP.
* text001 = 'XXXX'.
* text002 = 'XXXX'.
ENDFORM.
PERFORM frm_common_head_modify_screen."是否隐藏选择屏幕
快速减少子功能
FORM frm_common_head_modify_screen.
LOOP AT SCREEN.
READ TABLE gt_zewmtplatform INTO gs_zewmtplatform WITH KEY linekey = screen-name."linekey举例P_E067"
IF sy-subrc = 0.
IF gs_zewmtplatform-zactive = abap_true.
screen-active = '1'."显示
ELSE.
screen-active = '0'.
ENDIF.
MODIFY SCREEN.
ENDIF.
READ TABLE gt_zewmtplatform INTO gs_zewmtplatform WITH KEY linetext = screen-name."linetext举例TEXT029"
IF sy-subrc = 0.
IF gs_zewmtplatform-zactive = abap_true.
screen-active = '1'."显示
ELSE.
screen-active = '0'.
ENDIF.
MODIFY SCREEN.
ENDIF.
ENDLOOP.
ENDFORM .
PERFORM frm_common_head_jumpto."平台跳转子功能程序
内存ID建议使用类的常量,方便找引用。直接偷懒写固定文本的,打开发一顿。
FORM frm_common_head_jumpto.
LOOP AT gt_zewmtplatform INTO gs_zewmtplatform WHERE zactive = abap_true."初始化,通过用户在平台程序点击决定跳转到哪个程序
UNASSIGN <fs_zcommon_head_linekey>.
ASSIGN (gs_zewmtplatform-linekey) TO <fs_zcommon_head_linekey>.
IF <fs_zcommon_head_linekey> IS ASSIGNED.
IF <fs_zcommon_head_linekey> = abap_true.
gv_zcommon_head_program = gs_zewmtplatform-linevalue."获取程序名
ENDIF.
ENDIF.
ENDLOOP.
EXPORT gv_zcommon_head_program = gv_zcommon_head_program TO MEMORY ID 'KW20240723'."写入内存--因为下面是do循环,所以配合一下写入内存
IF gv_zcommon_head_program IS NOT INITIAL ."点击了屏幕按钮
DO.
CLEAR:gv_zcommon_head_program.
IMPORT gv_zcommon_head_program = gv_zcommon_head_program FROM MEMORY ID 'KW20240723'."读取内存
IF gv_zcommon_head_program IS NOT INITIAL.
SUBMIT (gv_zcommon_head_program) VIA SELECTION-SCREEN
AND RETURN.
ELSE.
EXIT.
ENDIF.
ENDDO.
LEAVE PROGRAM.
ENDIF.
ENDFORM.
自此,平台程序结束。
子程序改造开始。
INITIALIZATION.
PERFORM frm_common_head_init."获取全局参数
PERFORM frm_common_line_init."根据程序名,更新选择屏幕值
AT SELECTION-SCREEN OUTPUT.
PERFORM frm_get_selectscreen_comment."手动更新选择屏幕的文本
PERFORM frm_common_head_modify_screen."是否隐藏选择屏幕
PERFORM frm_common_head_leaveprog."判断是否退出程序
PERFORM frm_common_head_init."获取全局参数
略
PERFORM frm_common_line_init."根据程序名,更新选择屏幕值
FORM frm_common_line_init .
IMPORT gv_zcommon_head_program = gv_zcommon_head_program FROM MEMORY ID 'KW20240723'."读取内存
IF gv_zcommon_head_program IS NOT INITIAL ."点击了屏幕按钮
LOOP AT gt_zewmtplatform INTO gs_zewmtplatform WHERE zactive = abap_true.
UNASSIGN <fs_zcommon_head_linekey>.
ASSIGN (gs_zewmtplatform-linekey) TO <fs_zcommon_head_linekey>.
IF <fs_zcommon_head_linekey> IS ASSIGNED.
IF gs_zewmtplatform-linevalue = gv_zcommon_head_program."如果程序名和配置一致,那么单选打勾"
<fs_zcommon_head_linekey> = abap_true.
ELSE.
<fs_zcommon_head_linekey> = abap_false.
ENDIF.
ENDIF.
ENDLOOP.
FREE MEMORY ID 'KW20240723'.
ENDIF.
ENDFORM.
PERFORM frm_get_selectscreen_comment."手动更新选择屏幕的文本
略
PERFORM frm_common_head_leaveprog."判断是否退出程序
FORM frm_common_head_leaveprog .
LOOP AT gt_zewmtplatform INTO gs_zewmtplatform WHERE zactive = abap_true.
UNASSIGN <fs_zcommon_head_linekey>.
ASSIGN (gs_zewmtplatform-linekey) TO <fs_zcommon_head_linekey>.
IF <fs_zcommon_head_linekey> IS ASSIGNED.
IF <fs_zcommon_head_linekey> = abap_true.
gv_zcommon_head_program = gs_zewmtplatform-linevalue.
ENDIF.
ENDIF.
ENDLOOP.
IF gv_zcommon_head_program IS NOT INITIAL AND gv_zcommon_head_program <> sy-repid ."点击了屏幕按钮
FREE MEMORY ID 'KW20240723'.
EXPORT gv_zcommon_head_program = gv_zcommon_head_program TO MEMORY ID 'KW20240723'."写入内存
LEAVE PROGRAM.
ENDIF.
ENDFORM.
推出后,会进入平台程序的DO循环。
综上,实际堆栈只有两层,一层平台程序,一层子功能程序。
3.3当前存在问题
目前拿测试环境试了部分功能。有以下的几个问题。
- 屏幕操作涉及子功能程序的屏幕,也就是,尽量不要使用必填等强制校验,建议使用screen-required来实现伪必填。
- 一个通用子功能程序,需要在多个平台程序复用。这个我正在思考怎么处理。
- 调用标准功能,多次进入返回会出现,超过内部会话。
4源码
平台程序20240815
REPORT ytest_kevin5.
INCLUDE zcommon_head.
"平台程序自开发模板
AT SELECTION-SCREEN OUTPUT.
PERFORM frm_get_selectscreen_comment."获取选择屏幕的字段值
PERFORM frm_common_head_modify_screen."是否隐藏选择屏幕
PERFORM frm_common_head_jumpto."平台跳转子功能程序
INITIALIZATION.
PERFORM frm_common_head_init."获取平台程序配置表
包含文件
*&---------------------------------------------------------------------*
*& 包含 ZEWME101_HEAD
*&---------------------------------------------------------------------*
DATA:
gt_zewmtplatform TYPE TABLE OF zewmtplatform, "程序使用的配置表内表
gs_zewmtplatform TYPE zewmtplatform, "程序使用的配置表结构
gv_zcommon_head_tcode TYPE tcode, "程序使用的tcode,包含文件的变量要怪一点,一定不要和其他程序重复
gv_zcommon_head_program TYPE reposrc-progname, "子功能的程序tcode
gv_zcommon_head_programname TYPE reposrc-progname, "子功能的程序名称
gv_zcommon_head_standardtcode TYPE c, "标准程序准备推出
gggggggggg TYPE c. "瞎写的,懒得空行改标点符号,看不过去的自行调整
FIELD-SYMBOLS:<fs_zcommon_head_linekey> TYPE c, "子功能缩写在具体程序中,是否选中的标识
<fs_zcommon_head_linetext> TYPE zewmtplatform-linetextvalue, "子功能文本在程序中显示的描述
<hhhhhhhhhhhhhh> TYPE c. "瞎写的,懒得空行改标点符号,看不过去的自行调整
*======================================================================*
* Input Selection Screen
*======================================================================*
SELECTION-SCREEN BEGIN OF BLOCK zcommon_head WITH FRAME TITLE text998.
SELECTION-SCREEN:BEGIN OF LINE.
PARAMETERS:p_zzz RADIOBUTTON GROUP rg1 MODIF ID md USER-COMMAND uc1 DEFAULT 'X'.
SELECTION-SCREEN: COMMENT 3(35) text999.
SELECTION-SCREEN:END OF LINE.
SELECTION-SCREEN:BEGIN OF LINE.
PARAMETERS:p_exx1 RADIOBUTTON GROUP rg1 MODIF ID a01. "
SELECTION-SCREEN: COMMENT 3(35) text029 MODIF ID a01.
PARAMETERS:p_exx2 RADIOBUTTON GROUP rg1 MODIF ID a02. "
SELECTION-SCREEN: COMMENT 43(79) text030 MODIF ID a02.
SELECTION-SCREEN:END OF LINE.
SELECTION-SCREEN END OF BLOCK zcommon_head.
FORM frm_get_selectscreen_comment.
LOOP AT gt_zewmtplatform INTO gs_zewmtplatform ."遍历配置表
UNASSIGN <fs_zcommon_head_linetext>.
ASSIGN (gs_zewmtplatform-linetext) TO <fs_zcommon_head_linetext>."DEMO:assign 'TEXT029' to
IF <fs_zcommon_head_linetext> IS ASSIGNED.
<fs_zcommon_head_linetext> = gs_zewmtplatform-linetextvalue."选择屏幕的文本 DEMO:ZEWM***
ENDIF.
ENDLOOP.
ENDFORM.
FORM frm_common_head_init.
IF sy-tcode = 'SE38'."如果用户手动执行,找当前程序名的tcode
"1个程序可能对应多个Tcode,如果遇到这种情况,打一顿开发。打不过开发就把测试的人打一顿。
SELECT SINGLE tcode FROM tstc
WHERE pgmna = @sy-repid
INTO @gv_zcommon_head_tcode.
ELSE.
gv_zcommon_head_tcode = sy-tcode.
ENDIF.
* "DEV-test
* IF sy-uname = '00104423' AND sy-sysid = 'EWD'.
* gv_zcommon_head_tcode = 'YTEST_KEVIN5'.
* ELSEIF sy-uname = '00104423' AND sy-sysid = 'EWQ'.
* BREAK-POINT.
* ELSE.
* ENDIF.
IF gv_zcommon_head_tcode IS NOT INITIAL.
CLEAR:gt_zewmtplatform.
SELECT *
FROM zewmtplatform
WHERE programkey = @gv_zcommon_head_tcode
INTO TABLE @gt_zewmtplatform.
ENDIF.
* BREAK-POINT.
ENDFORM.
FORM frm_common_head_modify_screen.
LOOP AT SCREEN.
READ TABLE gt_zewmtplatform INTO gs_zewmtplatform WITH KEY linekey = screen-name.
IF sy-subrc = 0.
IF gs_zewmtplatform-zactive = abap_true.
screen-active = '1'."显示
ELSE.
screen-active = '0'.
ENDIF.
MODIFY SCREEN.
ENDIF.
READ TABLE gt_zewmtplatform INTO gs_zewmtplatform WITH KEY linetext = screen-name.
IF sy-subrc = 0.
IF gs_zewmtplatform-zactive = abap_true.
screen-active = '1'."显示
ELSE.
screen-active = '0'.
ENDIF.
MODIFY SCREEN.
ENDIF.
ENDLOOP.
ENDFORM .
FORM frm_common_head_jumpto.
LOOP AT gt_zewmtplatform INTO gs_zewmtplatform WHERE zactive = abap_true."初始化,通过用户在平台程序点击决定跳转到哪个程序
UNASSIGN <fs_zcommon_head_linekey>.
ASSIGN (gs_zewmtplatform-linekey) TO <fs_zcommon_head_linekey>.
IF <fs_zcommon_head_linekey> IS ASSIGNED.
IF <fs_zcommon_head_linekey> = abap_true.
gv_zcommon_head_program = gs_zewmtplatform-linevalue."获取程序名
ENDIF.
ENDIF.
ENDLOOP.
EXPORT gv_zcommon_head_program = gv_zcommon_head_program TO MEMORY ID 'KW20240723'."写入内存--因为下面是do循环,所以配合一下写入内存
IF gv_zcommon_head_program IS NOT INITIAL ."点击了屏幕按钮
DO.
CLEAR:gv_zcommon_head_program.
IMPORT gv_zcommon_head_program = gv_zcommon_head_program FROM MEMORY ID 'KW20240723'."读取内存
IF gv_zcommon_head_program IS NOT INITIAL.
SELECT SINGLE pgmna
FROM tstc
WHERE tcode = @gv_zcommon_head_program
INTO @gv_zcommon_head_programname.
IF sy-subrc = 0.
IF gv_zcommon_head_program+0(1) CA 'ZY' ."如果是自建程序
ELSE.
gv_zcommon_head_standardtcode = abap_true.
ENDIF.
SUBMIT (gv_zcommon_head_programname) VIA SELECTION-SCREEN
AND RETURN.
IF gv_zcommon_head_standardtcode = abap_true.
CLEAR gv_zcommon_head_standardtcode.
LEAVE TO SCREEN 0.
EXPORT gv_zcommon_head_program = sy-tcode TO MEMORY ID 'KW20240723'.
ENDIF.
ENDIF.
ELSE.
EXIT.
ENDIF.
ENDDO.
LEAVE PROGRAM.
ENDIF.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form FRM_COMMON_LINE_INIT
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* --> p1 text
* <-- p2 text
*----------------------------------------------------------------------*
FORM frm_common_line_init .
IMPORT gv_zcommon_head_program = gv_zcommon_head_program FROM MEMORY ID 'KW20240723'."读取内存
IF gv_zcommon_head_program IS NOT INITIAL ."点击了屏幕按钮
LOOP AT gt_zewmtplatform INTO gs_zewmtplatform WHERE zactive = abap_true.
UNASSIGN <fs_zcommon_head_linekey>.
ASSIGN (gs_zewmtplatform-linekey) TO <fs_zcommon_head_linekey>.
IF <fs_zcommon_head_linekey> IS ASSIGNED.
IF gs_zewmtplatform-linevalue = gv_zcommon_head_program.
<fs_zcommon_head_linekey> = abap_true.
ELSE.
<fs_zcommon_head_linekey> = abap_false.
ENDIF.
ENDIF.
ENDLOOP.
FREE MEMORY ID 'KW20240723'.
ENDIF.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form FRM_COMMON_HEAD_LEAVEPROG
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* --> p1 text
* <-- p2 text
*----------------------------------------------------------------------*
FORM frm_common_head_leaveprog .
LOOP AT gt_zewmtplatform INTO gs_zewmtplatform WHERE zactive = abap_true.
UNASSIGN <fs_zcommon_head_linekey>.
ASSIGN (gs_zewmtplatform-linekey) TO <fs_zcommon_head_linekey>.
IF <fs_zcommon_head_linekey> IS ASSIGNED.
IF <fs_zcommon_head_linekey> = abap_true.
gv_zcommon_head_program = gs_zewmtplatform-linevalue.
ENDIF.
ENDIF.
ENDLOOP.
IF gv_zcommon_head_program IS NOT INITIAL AND gv_zcommon_head_program <> sy-repid ."点击了屏幕按钮
FREE MEMORY ID 'KW20240723'.
EXPORT gv_zcommon_head_program = gv_zcommon_head_program TO MEMORY ID 'KW20240723'."写入内存
LEAVE PROGRAM.
ENDIF.
ENDFORM.
子功能程序略,添加下面代码片段即可
INITIALIZATION.
PERFORM frm_common_head_init."获取全局参数
PERFORM frm_common_line_init."根据程序名,更新选择屏幕值
AT SELECTION-SCREEN OUTPUT.
PERFORM frm_get_selectscreen_comment."手动更新选择屏幕的文本
PERFORM frm_common_head_modify_screen."是否隐藏选择屏幕
PERFORM frm_common_head_leaveprog."判断是否退出程序
效果图
ID ‘KW20240723’.
EXPORT gv_zcommon_head_program = gv_zcommon_head_program TO MEMORY ID ‘KW20240723’."写入内存
LEAVE PROGRAM.
ENDIF.
ENDFORM.
子功能程序略,添加下面代码片段即可
```abap
INITIALIZATION.
PERFORM frm_common_head_init."获取全局参数
PERFORM frm_common_line_init."根据程序名,更新选择屏幕值
AT SELECTION-SCREEN OUTPUT.
PERFORM frm_get_selectscreen_comment."手动更新选择屏幕的文本
PERFORM frm_common_head_modify_screen."是否隐藏选择屏幕
PERFORM frm_common_head_leaveprog."判断是否退出程序