前言
ERP项目上线后,标准的系统配置,我们很少去做改动了,随着使用的逐渐深入,自开发的功能会越来越多,需要运维顾问进行管理的自定义配置也会越来越多。为此,我提供了一个类似于SPRO的配置工具,用来管理自定义的配置项。
说明:这个配置工具里,也可以将标准的视图维护进来,比如:配置公司代码的维护视图V_T001。
1/6.效果展示
之前做了一个模块自定义配置项的管理工具,比较low一些。
现在做了一下升级,效果如下:
上面展示的层级结构,通过自定义表进行配置,配置内容大概如下图:
2/6.使用说明
1.需要创建Z+模块+CONFIG的事务代码,事务代码对应的REPORT程序都是一个,即:ZCUSTOM_CONFIG(代码在最后),如下图:
2.需要按照下面的步骤,依次创建数据库表、视图、视图簇(SE54,不会的请百度)、程序。
3.最后的程序里,有一个管理增强有效性的配置项,这个是我这边项目上跟另外一个开发管理的工具关联在一起的,各位部署完程序后,可自行修改代码,屏蔽此配置项。
4.点击配置项的执行按钮时,支持跳转到SM30、SM34,以及无比灵活的某程序的某个FORM。
3/6.数据字典
为实现上述效果,需要自己创建两张表,如下图:
4/6.视图
创建两个视图
5/6.视图簇
创建视图簇如下:
6/6.代码
*&---------------------------------------------------------------------*
*& 程序名称:ZCUSTOM_CONFIG
*& 程序描述:各模块通用配置程序
*&===============================*
*&创建日期:2021.06.21 程序员:孙亮
*&===============================*
*&修改日期 请求号 修改人 业务提交人 修改描述 *
*&---------------------------------------------------------------------*
REPORT zcustom_config.
CLASS lcl_tree_event_receiver DEFINITION.
PUBLIC SECTION.
METHODS:
handle_tree_link_click FOR EVENT link_click OF cl_gui_column_tree IMPORTING node_key item_name.
ENDCLASS.
TYPES:BEGIN OF ty_item,
dir_no TYPE zcus_conf_dir-dir_no,
dir_text TYPE zcus_conf_dir-dir_text,
item_no TYPE zcus_conf_item-item_no,
item_text TYPE zcus_conf_item-item_text,
tabname TYPE zcus_conf_item-tabname,
ztype TYPE zcus_conf_item-ztype,
progname TYPE zcus_conf_item-progname,
formname TYPE zcus_conf_item-formname,
END OF ty_item.
CONSTANTS:
gc_enh_conf TYPE string VALUE 'ENH_CONF',
gc_cus_conf TYPE string VALUE 'CUS_CONF',
gc_column_btn TYPE tv_itmname VALUE 'BUTTON',
gc_column_item TYPE tv_itmname VALUE 'ITEM'.
DATA: gv_module TYPE string,
gt_item TYPE SORTED TABLE OF ty_item WITH UNIQUE KEY dir_no item_no,
go_tree TYPE REF TO cl_gui_column_tree,
go_docking_tree TYPE REF TO cl_gui_docking_container,
go_event_tree TYPE REF TO lcl_tree_event_receiver,
gt_exclude TYPE TABLE OF sy-ucomm,
gt_sel_condition TYPE TABLE OF vimsellist WITH HEADER LINE.
CLASS lcl_tree_event_receiver IMPLEMENTATION.
METHOD handle_tree_link_click.
PERFORM handle_tree_link_click USING node_key item_name.
ENDMETHOD.
ENDCLASS.
SELECTION-SCREEN PUSHBUTTON 1(20) refresh USER-COMMAND refresh.
INITIALIZATION.
refresh = '刷新'.
DATA(lv_tcode) = sy-tcode+1.
REPLACE FIRST OCCURRENCE OF 'CONFIG' IN lv_tcode WITH ''.
IF lv_tcode = 'FI'.
gv_module = 'FICO'.
ELSE.
gv_module = lv_tcode.
ENDIF.
sy-title = |{ gv_module }自定义配置|.
PERFORM get_data.
AT SELECTION-SCREEN OUTPUT.
CLEAR gt_exclude.
APPEND 'ONLI' TO gt_exclude.
APPEND 'SPOS' TO gt_exclude.
CALL FUNCTION 'RS_SET_SELSCREEN_STATUS'
EXPORTING
p_status = sy-pfkey
p_program = sy-cprog
TABLES
p_exclude = gt_exclude.
PERFORM create_tree.
PERFORM display_data.
AT SELECTION-SCREEN.
IF sy-ucomm = 'REFRESH'.
PERFORM get_data.
PERFORM display_data.
ENDIF.
FORM get_data.
SELECT
a~dir_no
a~dir_text
b~item_no
b~item_text
b~tabname
b~ztype
b~progname
b~formname
INTO TABLE gt_item
FROM zcus_conf_dir AS a
LEFT JOIN zcus_conf_item AS b ON b~zmodule = a~zmodule AND b~dir_no = a~dir_no
WHERE a~zmodule = gv_module.
ENDFORM.
FORM create_tree.
DATA: ls_header TYPE treev_hhdr,
lt_events TYPE cntl_simple_events.
CHECK go_docking_tree IS INITIAL.
CREATE OBJECT go_docking_tree
EXPORTING
ratio = 93
side = cl_gui_docking_container=>dock_at_bottom.
ls_header-heading = |{ gv_module }自定义配置项|.
ls_header-width = 50.
"创建树
CREATE OBJECT go_tree
EXPORTING
parent = go_docking_tree
node_selection_mode = cl_gui_column_tree=>node_sel_mode_single
item_selection = abap_true
hierarchy_column_name = gc_column_item
hierarchy_header = ls_header.
"获取事件并添加事件
go_tree->get_registered_events( IMPORTING events = lt_events ).
APPEND VALUE #( eventid = cl_gui_column_tree=>eventid_link_click appl_event = 'X' ) TO lt_events.
go_tree->set_registered_events( events = lt_events ).
"创建事件处理类
CREATE OBJECT go_event_tree.
SET HANDLER go_event_tree->handle_tree_link_click FOR go_tree.
"在树中增加一列按钮
go_tree->insert_hierarchy_column( name = gc_column_btn ).
ENDFORM.
FORM display_data.
DATA: lt_nodes TYPE treev_ntab,
lt_items TYPE STANDARD TABLE OF streeitm WITH DEFAULT KEY,
lv_node_key TYPE tv_nodekey.
DEFINE macro_append_node.
IF &2 IS INITIAL.
APPEND VALUE #( node_key = &1
n_image = &3
isfolder = &4 ) TO lt_nodes.
ELSE.
APPEND VALUE #( node_key = &1
relatkey = &2
relatship = cl_gui_column_tree=>relat_last_child
n_image = &3
isfolder = &4 ) TO lt_nodes.
ENDIF.
END-OF-DEFINITION.
DEFINE macro_append_btn.
APPEND VALUE #( node_key = &1
item_name = gc_column_btn
class = cl_gui_column_tree=>item_class_link
t_image = icon_execute_object ) TO lt_items.
END-OF-DEFINITION.
DEFINE macro_append_item.
APPEND VALUE #( node_key = &1
item_name = gc_column_item
text = &2
disabled = 'X' ) TO lt_items.
END-OF-DEFINITION.
go_tree->delete_all_nodes( ).
"增加两个固定项
macro_append_node gc_enh_conf '' icon_space ''.
macro_append_btn gc_enh_conf.
macro_append_item gc_enh_conf '增强有效性配置'.
macro_append_node gc_cus_conf '' icon_space ''.
macro_append_btn gc_cus_conf.
macro_append_item gc_cus_conf '管理自定义配置项'.
LOOP AT gt_item ASSIGNING FIELD-SYMBOL(<ls_item>).
AT NEW dir_no.
macro_append_node <ls_item>-dir_no '' '' 'X'.
macro_append_item <ls_item>-dir_no <ls_item>-dir_text.
ENDAT.
IF <ls_item>-item_no IS NOT INITIAL OR <ls_item>-item_text IS NOT INITIAL.
lv_node_key = |{ <ls_item>-dir_no }-{ <ls_item>-item_no }|.
macro_append_node lv_node_key <ls_item>-dir_no icon_space ''.
macro_append_btn lv_node_key.
macro_append_item lv_node_key <ls_item>-item_text.
ENDIF.
ENDLOOP.
CALL METHOD go_tree->add_nodes_and_items
EXPORTING
node_table = lt_nodes
item_table = lt_items
item_table_structure_name = 'STREEITM' "MTREEITM'
EXCEPTIONS
OTHERS = 1.
go_tree->expand_root_nodes( ).
ENDFORM.
FORM handle_tree_link_click USING p_node_key TYPE lvc_nkey
p_item_name TYPE tv_itmname.
CASE p_node_key.
WHEN gc_enh_conf.
SUBMIT zabap_enha_config WITH p_module = gv_module AND RETURN.
WHEN gc_cus_conf.
REFRESH gt_sel_condition.
APPEND VALUE #( viewfield = 'ZMODULE' operator = 'EQ' value = gv_module ) TO gt_sel_condition.
PERFORM call_sm34 USING 'ZVCUS_CONF'.
PERFORM get_data.
PERFORM display_data.
WHEN OTHERS.
CHECK strlen( p_node_key ) > 3.
SPLIT p_node_key AT '-' INTO DATA(lv_dir_no) DATA(lv_item_no).
READ TABLE gt_item WITH KEY dir_no = lv_dir_no item_no = lv_item_no ASSIGNING FIELD-SYMBOL(<ls_item>).
IF <ls_item>-ztype = 'SM30'.
PERFORM call_sm30 USING <ls_item>-tabname.
ELSEIF <ls_item>-ztype = 'SM34'.
PERFORM call_sm34 USING <ls_item>-tabname.
ELSE.
PERFORM (<ls_item>-formname) IN PROGRAM (<ls_item>-progname) IF FOUND.
ENDIF.
ENDCASE.
ENDFORM.
FORM call_sm30 USING p_tablename TYPE dd02v-tabname.
DATA: l_action TYPE c VALUE 'U'.
IF gt_sel_condition[] IS INITIAL.
CALL FUNCTION 'VIEW_MAINTENANCE_CALL'
EXPORTING
action = l_action
view_name = p_tablename.
ELSE.
CALL FUNCTION 'VIEW_MAINTENANCE_CALL'
EXPORTING
action = l_action
view_name = p_tablename
TABLES
dba_sellist = gt_sel_condition[].
REFRESH: gt_sel_condition.
ENDIF.
ENDFORM.
FORM call_sm34 USING p_clustername TYPE vcldir-vclname.
DATA: l_action TYPE c VALUE 'U'.
IF gt_sel_condition[] IS INITIAL.
CALL FUNCTION 'VIEWCLUSTER_MAINTENANCE_CALL'
EXPORTING
maintenance_action = 'U'
viewcluster_name = p_clustername.
ELSE.
CALL FUNCTION 'VIEWCLUSTER_MAINTENANCE_CALL'
EXPORTING
maintenance_action = 'U'
viewcluster_name = p_clustername
TABLES
dba_sellist = gt_sel_condition[].
REFRESH: gt_sel_condition.
ENDIF.
ENDFORM.
最后祝大家中秋快乐!
对了,补充一个自己的想法,以后我写的文章,会分为付费和免费两类。
免费的:
思路性的文章,比如-发票预制增强(链接);
工具类的文章,比如您在读的这篇文章。
付费的:
涉及具体开发工作的代码,比如-分页取数的逻辑(链接);
技巧性的部分代码,比如-管理自定义的配置项(链接)。
我们程序员这个群体,特别是具体到我们ABAP群体,其实是非常没有付费习惯的,很多人可能会花钱去买个游戏皮肤,都不会来付费读一篇文章。
思路性的文章、工具类的文章及代码,我愿意分享出来给大家提供一些可能的帮助,所以设置为免费的。
但是对于非工具类的代码,我不想被人白嫖(比如发票预制的文章,我只提供思路),然后拿走去完成自己的工作。
技巧性的代码,我也希望我的读者愿意自己去动脑思考完成这个技巧,或者花个三五块钱学习这个技巧。
而且,管理自定义的配置项这个技巧,只是个小技巧而已。我上面提供的代码,比管理自定义的配置项的代码,是升级后的版本,比之前的要复杂的多,好用的多。所以我判定一篇文章是否付费,也不是以代码的复杂度来作为依据的。
总结:
免费的思路性的文章,是想帮助一些人拓宽一下思路。
免费的工具类的文章,是想给大家提供一些实用工具。
付费的涉及具体工作的代码,是拒绝白嫖。
付费的技巧性的文章,是想让大家动动脑。
想变的牛逼,你就得学会如何捕鱼,而不是问别人要鱼吃。
如果喜欢,谢谢转发。