系列文章目录
SAP之FPM卷一:FPM是什么
SAP之FPM卷二:FPM开发实例-创建WDA应用
SAP之FPM卷三:FPM开发实例-设想需求与优化
SAP之FPM卷四:FPM开发实例- 创建程序所需表,结构并完成搜索页面主要代码
SAP之FPM卷六:FPM开发实例-完成主页面功能(2)
SAP之FPM卷七:FPM开发实例-完成主页面功能(通过EXCEL上载数据)
前言
紧接上一卷,目前已经完成了搜索页面的功能,现在需要到主页面接收从搜索页面传递过来的值,然后根据搜索页面的事件(EVENT)做出相应处理
上一篇文章中已经设想了几种业务场景,但是还需要根据实际业务完善一些细节:
展示:对选中数据做展示,进入主页面时,默认是仅展示状态,如果是保存状态可以点击编辑按钮,然后对此条数据上锁,直至退出,取消编辑或审批恢复仅展示状态后对该条数据解锁;如果是有效状态(审批通过状态)则提示不允许修改
调整:对选中的最新版的数据进行调整,且必须为有效状态(审批通过状态),否则提示请选择最新生效状态版数据调整;进入主页面后带出上一版数据,版本自动加一,状态设置成保存,并且锁住最新版数据,以GUID为KEY,在新数据未退出编辑状态前不允许再调整,对于明细表直接带出上一版数据
删除:只能删除保存状态的数据!不然提示该状态数据无法删除
之前的设计中主页面有保存,单步审批,上传数据,下载模板这几个按钮,根据现在需要完善的细节添加两个按钮,编辑,取消编辑,在保存之前
创建:搜索页面已完成对项目的校验,主页面方法直接取出楼栋数据
对于抬头一行的按钮,可以设置成全局的,也可以设置在FORM的DEFINITION中
一、添加按钮
- 进入主页面FORM与LIST公用的类(ZCL_TEST_DEMO_MAIN_LIST)中,在FORM~GET_DEFINITION中添加按钮代码 : 编辑,取消编辑,保存,单步审批,返回
因为明细页面与搜索页面在同一个WDA程序中,如果这时候用标准方法去获取全局工具栏,会获取到搜索页面的全局工具栏,而不是明细页面的全局工具栏,所以我把应该放在全局的工具栏放在了抬头里,通过标准方法获取全局工具栏的方法在另外一篇专门介绍,下面是文章链接↓
先定义好需要用到的结构,表类型等
类型中代码
PRIVATE SECTION.
TYPES ts_ldmx TYPE ztest_demo_mx .
TYPES:
tt_ldmx TYPE TABLE OF ts_ldmx .
DATA mt_ldmx TYPE tt_ldmx .
DATA mo_fpm TYPE REF TO if_fpm .
DATA ms_header TYPE ztest_demo_sch .
其中属性
代码
METHOD if_fpm_guibb_form~get_definition.
DATA:
ls_action_def TYPE fpmgb_s_actiondef,
ls_fixed_value TYPE wdr_context_attr_value,
ls_field_descr LIKE LINE OF et_field_description,
lt_component TYPE abap_component_tab,
ls_value TYPE wdr_context_attr_value,
lt_value TYPE wdr_context_attr_value_list.
FIELD-SYMBOLS:
<ls_component> LIKE LINE OF lt_component,
<fs_field_desc> TYPE fpmgb_s_formfield_descr.
eo_field_catalog ?= cl_abap_structdescr=>describe_by_data( ms_header ).
lt_component = eo_field_catalog->get_components( ).
* 为字段设置属性
LOOP AT lt_component ASSIGNING <ls_component>.
CLEAR ls_field_descr.
ls_field_descr-name = <ls_component>-name.
"设置必输
IF <ls_component>-name = 'ZSYBM'.
* 事业部设置成下拉框 所以必须要有fixed_value,除非本身就是一个带值的域
ls_value-value = '01'.
ls_value-text = '北京事业部'.
APPEND ls_value TO lt_value.
ls_value-value = '02'.
ls_value-text = '上海事业部'.
APPEND ls_value TO lt_value.
ls_field_descr-fixed_values = lt_value.
CLEAR:lt_value.
ls_field_descr-mandatory = 'X'.
APPEND ls_field_descr TO et_field_description.
ELSE.
APPEND ls_field_descr TO et_field_description.
ENDIF.
ENDLOOP.
* 添加EVENT(按钮)
* 保存
CLEAR: ls_action_def-extended.
ls_action_def-id = 'FPM_SAVE'.
ls_action_def-imagesrc = '~Icon/Save'.
ls_action_def-text = '保存'.
ls_action_def-enabled = abap_true.
APPEND ls_action_def TO et_action_definition.
* 取消编辑
CLEAR: ls_action_def-extended.
ls_action_def-id = 'FPM_CANCEL'.
ls_action_def-imagesrc = '~Icon/Cancel'.
ls_action_def-text = '取消编辑'.
ls_action_def-enabled = abap_true.
APPEND ls_action_def TO et_action_definition.
* 取消编辑
CLEAR: ls_action_def-extended.
ls_action_def-id = 'FPM_EDIT'.
ls_action_def-imagesrc = '~Icon/Edit'.
ls_action_def-text = '编辑'.
ls_action_def-enabled = abap_true.
APPEND ls_action_def TO et_action_definition.
* 单步审批
CLEAR: ls_action_def-extended.
ls_action_def-id = 'FPM_DBSP'.
ls_action_def-imagesrc = '~Icon/Complete'.
ls_action_def-text = '单步审批'.
ls_action_def-enabled = abap_true.
APPEND ls_action_def TO et_action_definition.
* 返回
CLEAR: ls_action_def-extended.
ls_action_def-id = 'FPM_BACK'.
ls_action_def-imagesrc = '~Icon/Cancelled'.
ls_action_def-text = '返回'.
ls_action_def-enabled = abap_true.
APPEND ls_action_def TO et_action_definition.
ENDMETHOD.
-
进入工作台,抬头的UIBB,添加元素->添加按钮行->在下一级添加按钮,按如图顺序添加
-
添加组,并在其下一级添加元素
出现如图效果,把事业部,状态设置成下拉列表,描述标签改为项目名称,调整位置,保存
-
在LIST~GET_DEFINITION方法中通过代码为明细的UIBB添加两个按钮
LIST~GET_DEFINITION代码:
METHOD if_fpm_guibb_list~get_definition.
DATA:ls_action_def TYPE fpmgb_s_actiondef.
eo_field_catalog ?= cl_abap_structdescr=>describe_by_data( mt_ldmx ).
* 添加EVENT(按钮)
* 上传数据
CLEAR: ls_action_def-extended.
ls_action_def-id = 'UPLOAD_DATA'.
ls_action_def-imagesrc = '~Icon/Upload'.
ls_action_def-text = '上载数据'.
ls_action_def-enabled = abap_true.
APPEND ls_action_def TO et_action_definition.
* 下载模板
CLEAR: ls_action_def-extended.
ls_action_def-id = 'DOWNLOAD_TEMP'.
ls_action_def-imagesrc = '~Icon/Download'.
ls_action_def-text = '下载模板'.
ls_action_def-enabled = abap_true.
APPEND ls_action_def TO et_action_definition.
ENDMETHOD.
- 工作台进入明细的UIBB中,添加工具栏元素,
效果
添加列,并修改属性,记得保存
到此能看得见的按钮(事件)就加完了,接下来结合功能设计完善代码
目前的页面效果:
抬头不使用面板:
效果:
二、优化调整与部分代码
1.优化与调整
搜索页面代码调整
由于我们是应用内页面跳转,所以不需要launch_webdynpro_abap的方法跳转,这种针对的是不同WDA应用之间的跳转,搜索页面与明细页面分开的程序一般都是考虑到某些组件需要复用才分开,这里的DEMO程序不考虑复用,也不用这种方法了,我们需要对搜索页面的跳转方法改造一下。
打开搜索页面的方法ZCL_TEST_DEMO_SCH_HEAD 进入 CREATE_DATA方法,粘贴下方的代码覆盖并激活,屏蔽的代码是之前的,以作对照
METHOD create_data.
DATA:lt_app_params TYPE apb_lpd_t_params,
ls_app_param LIKE LINE OF lt_app_params,
lo_event TYPE REF TO cl_fpm_parameter,
lo_event_data TYPE REF TO if_fpm_parameter.
** Set change mode
* ls_app_param-key = 'CHANGE_MODE'.
* ls_app_param-value = 'C'.
* APPEND ls_app_param TO lt_app_params[].
** Set edit mode
* ls_app_param-key = 'FPM_EDIT_MODE'.
* ls_app_param-value = 'E'.
* APPEND ls_app_param TO lt_app_params[].
*
* ls_app_param-key = 'SKIP_INITIAL_SCREEN'.
* ls_app_param-value = abap_true.
* APPEND ls_app_param TO lt_app_params[].
*
** Transfer division for new create one
* ls_app_param-key = 'ZSYBM'.
* ls_app_param-value = ms_sel-zsybm.
* APPEND ls_app_param TO lt_app_params[].
*
* ls_app_param-key = 'PSPID'.
* ls_app_param-value = ms_sel-pspid.
* APPEND ls_app_param TO lt_app_params[].
*
* ls_app_param-key = 'ACTION'.
* ls_app_param-value = 'CREATE'.
* APPEND ls_app_param TO lt_app_params[].
* zgld_cl_fpm_navigation=>launch_webdynpro_abap(
* iv_wda = 'ZTEST_WDA_APPLICATION'
** iv_wdac = 'ZTEST_WD_APPLICATION'
* it_parameter = lt_app_params ).
IF lo_event_data IS NOT BOUND.
CREATE OBJECT lo_event.
lo_event_data ?= lo_event.
ENDIF.
CALL METHOD mo_fpm->mo_app_parameter->set_value
EXPORTING
iv_key = 'CHANGE_MODE'
iv_value = 'C'
* ir_value =
.
CALL METHOD mo_fpm->mo_app_parameter->set_value
EXPORTING
iv_key = 'FPM_EDIT_MODE'
iv_value = 'E'
* ir_value =
.
CALL METHOD mo_fpm->mo_app_parameter->set_value
EXPORTING
iv_key = 'CHANGE_MODE'
iv_value = 'C'
* ir_value =
.
CALL METHOD mo_fpm->mo_app_parameter->set_value
EXPORTING
iv_key = 'SKIP_INITIAL_SCREEN'
iv_value = abap_true
* ir_value =
.
CALL METHOD mo_fpm->mo_app_parameter->set_value
EXPORTING
iv_key = 'ZSYBM'
iv_value = ms_sel-zsybm
* ir_value =
.
CALL METHOD mo_fpm->mo_app_parameter->set_value
EXPORTING
iv_key = 'PSPID'
iv_value = ms_sel-pspid
* ir_value =
.
CALL METHOD mo_fpm->mo_app_parameter->set_value
EXPORTING
iv_key = 'ACTION'
iv_value = 'CREATE'
* ir_value =
.
* lo_event_data = mo_fpm->mo_app_parameter.
* 唤起标准EVENT : leave_initial_screen 就能进入主页面了 顺便把设置的值带入主页面
CALL METHOD mo_fpm->raise_event_by_id
EXPORTING
iv_event_id = cl_fpm_event=>gc_event_leave_initial_screen
io_event_data = mo_fpm->mo_app_parameter "lo_event_data.不需要再创建对象了,直接使用MO_FPM中的就可以,我写出来为了展示这个对象是怎么创建的,有需要自定义的可以参考
.
ENDMETHOD.
进入LIST~PROCESS_EVENT方法,复制下面的代码替换并激活
METHOD if_fpm_guibb_list~process_event.
DATA:
ls_result TYPE ztest_demo_sch,
ls_message TYPE fpmgb_s_t100_message,
lv_selected_row TYPE int4,
lt_app_params TYPE apb_lpd_t_params,
ls_app_param LIKE LINE OF lt_app_params,
lv_status TYPE zde_apv_status,
lo_event TYPE REF TO cl_fpm_parameter,
lo_event_data TYPE REF TO if_fpm_parameter.
CASE io_event->mv_event_id.
WHEN gc_display_data OR gc_adjust_data OR gc_delete_data.
* 选择数据检查 必须选择一条数据
io_event->mo_event_data->get_value(
EXPORTING
iv_key = if_fpm_guibb_list=>gc_event_par_row
IMPORTING
ev_value = lv_selected_row ).
IF lv_selected_row IS INITIAL OR lv_selected_row < 0.
ls_message-msgid = 'ZTEST'.
ls_message-msgno = '000'.
ls_message-severity = 'E'.
APPEND ls_message TO et_messages.
ev_result = 'FAILED'.
EXIT.
ENDIF.
* 读到了才进行下一步
READ TABLE mt_result INTO ls_result INDEX lv_selected_row.
IF sy-subrc EQ 0.
* 删除按钮
IF io_event->mv_event_id EQ gc_delete_data.
* 读到选取的行数据
CLEAR:ls_result.
* 只有保存状态才能删除
SELECT SINGLE status INTO lv_status
FROM ztest_demo_sch
WHERE guid EQ ls_result-guid
AND status EQ '4'."我设置的4为保存状态
IF sy-subrc EQ 0.
* 把选中数据更新为删除状态
UPDATE ztest_demo_sch SET status = '6' WHERE guid EQ ls_result-guid.
IF sy-subrc EQ 0.
DELETE mt_result INDEX lv_selected_row.
ENDIF.
* 未找到保存状态的数据
ELSE.
ls_message-msgid = 'ZTEST'.
ls_message-msgno = '004'.
ls_message-severity = 'E'.
ls_message-parameter_1 = '选择数据非保存状态,不能删除!'.
APPEND ls_message TO et_messages.
ev_result = 'FAILED'.
EXIT.
ENDIF.
* 展示按钮 调整按钮
ELSE.
* 展示按钮
IF io_event->mv_event_id EQ gc_display_data.
* Set edit mode
CALL METHOD mo_fpm->mo_app_parameter->set_value
EXPORTING
iv_key = 'FPM_EDIT_MODE'
iv_value = 'R'
* ir_value =
.
* 调整按钮 生成新版数据
ELSEIF io_event->mv_event_id EQ gc_adjust_data.
* 由于调整是建立在上一版的基础上 所以当点击调整时,必须以选中项目的最新有效版为数据来源
CALL METHOD me->check_before_adjust
EXPORTING
is_result = ls_result " DEMO底表
CHANGING
cv_result = ev_result " FPM 事件结果
ct_messages = et_messages.
CHECK ev_result NE 'FAILED'.
* Set change mode
CALL METHOD mo_fpm->mo_app_parameter->set_value
EXPORTING
iv_key = 'CHANGE_MODE'
iv_value = 'C'
* ir_value =
.
* Set edit mode
CALL METHOD mo_fpm->mo_app_parameter->set_value
EXPORTING
iv_key = 'FPM_EDIT_MODE'
iv_value = 'E'
* ir_value =
.
ENDIF.
* 设置选中数据的唯一guid,为了使主页面方便获取数据
CALL METHOD mo_fpm->mo_app_parameter->set_value
EXPORTING
iv_key = 'GUID'
iv_value = ls_result-guid
* ir_value =
.
* 当前是什么操作传递给主页面
CALL METHOD mo_fpm->mo_app_parameter->set_value
EXPORTING
iv_key = 'ACTION'
iv_value = io_event->mv_event_id
* ir_value =
.
* 跳过初始界面
CALL METHOD mo_fpm->mo_app_parameter->set_value
EXPORTING
iv_key = 'SKIP_INITIAL_SCREEN'
iv_value = abap_true
* ir_value =
.
CALL METHOD mo_fpm->raise_event_by_id
EXPORTING
iv_event_id = cl_fpm_event=>gc_event_leave_initial_screen
io_event_data = mo_fpm->mo_app_parameter.
ENDIF.
ENDIF.
WHEN OTHERS.
ENDCASE.
ENDMETHOD.
新增的方法:校验点击调整按钮选中数据是否为最新有效数据
参数:
METHOD check_before_adjust.
DATA:ls_result TYPE ts_result,
lt_result TYPE tt_result,
ls_message TYPE fpmgb_s_t100_message.
cv_result = 'FAILED'.
SELECT * INTO CORRESPONDING FIELDS OF TABLE lt_result
FROM ztest_demo_sch
WHERE pspid EQ is_result-pspid
AND status IN ( '4','7' ). "保存与有效
IF sy-subrc EQ 0.
SORT lt_result BY version DESCENDING.
READ TABLE lt_result INTO ls_result INDEX 1.
IF sy-subrc EQ 0.
IF ls_result-status EQ '4'.
CLEAR:ls_message.
ls_message-msgid = 'ZTEST'.
ls_message-msgno = '002'.
ls_message-severity = 'E'.
ls_message-parameter_1 = '最新版未审批,可查看编辑,无法调整新版本'.
APPEND ls_message TO ct_messages.
EXIT.
ELSEIF ls_result-guid NE is_result-guid.
CLEAR:ls_message.
ls_message-msgid = 'ZTEST'.
ls_message-msgno = '002'.
ls_message-severity = 'E'.
ls_message-parameter_1 = '请选择最新版'.
APPEND ls_message TO ct_messages.
EXIT.
ELSEIF ls_result-status EQ '7' AND ls_result-guid EQ is_result-guid.
cv_result = 'OK'.
ELSE.
ENDIF.
ENDIF.
ENDIF.
ENDMETHOD.
2. 结构,表调整
先为底表直接插入一条数据
打开程序,搜索界面查询后点击这条以查看方式进入
细心的朋友可能已经发现了,抬头中事业部字段并没有展示出描述,而是02
这是由于我们抬头参照的底表是INLUDE的搜索结构,ZSYBM这个字段在INCLUDE的搜索结构中,在明细页面的FORM~GET_DEFINITION中get_components( )方法并没有获取到这个字段,因为其在内部INCLUDE的下一层中,不好直接取出,所以需要改造下底表,直接把所有字段放进底表,而不INCLUDE,改完后激活
打断点进入看一下就很清楚了
下面的IF判断就不会进了,所以并没有设置到FIXED_VALUE
所以底表改造成如下
刷新页面,再次进入此条数据就会正常显示了,搜索页面的结果展示也正常显示了
3. 前台页面的调整
明细页面中的抬头只做展示作用,而不能修改,因为其项目相关属性已在底表中存在,数据状态等也不能随意更改,只能随操作而变化,故抬头所有字段不需要编辑
进入工作台,除事业部和状态以外,其他字段均设置为文本视图,事业部和状态到明细页面的FORM~GET_DATA方法中去设置可编辑性,后面会放出来全部代码,可以往后看
4. INITIALIZE获取搜索页面传递过来的数据
其中包含有用户操作,数据,编辑模式等等
代码:
METHOD if_fpm_guibb~initialize.
DATA:lt_app_key TYPE TABLE OF string,
lv_app_key TYPE string,
lv_appvalue TYPE string,
lv_guid TYPE guid,
ls_header TYPE ztest_demo_sch.
mo_fpm ?= cl_fpm=>get_instance( ).
CLEAR:ms_header.
IF mo_fpm IS NOT INITIAL.
* 获取应用的参数
TRY.
lt_app_key = mo_fpm->mo_app_parameter->get_keys( ).
LOOP AT lt_app_key INTO lv_app_key.
CALL METHOD mo_fpm->mo_app_parameter->get_value
EXPORTING
iv_key = lv_app_key
IMPORTING
ev_value = lv_appvalue.
CASE lv_app_key.
WHEN 'ZSYBM'.
ms_header-zsybm = lv_appvalue.
WHEN 'PSPID'.
ms_header-pspid = lv_appvalue.
WHEN 'POST1'.
ms_header-post1 = lv_appvalue.
WHEN 'ACTION'.
mv_curr_action = lv_appvalue.
WHEN 'GUID'.
lv_guid = lv_appvalue.
* WHEN 'SAP-WD-CONFIGID'.
* mv_app_name = lv_appvalue.
ENDCASE.
ENDLOOP.
* 创建
IF mv_curr_action EQ 'CREATE'.
TRY.
ms_header-guid = cl_system_uuid=>create_uuid_x16_static( ).
CATCH cx_uuid_error .
ENDTRY.
* 加锁
CALL FUNCTION 'ENQUEUE_EZDEMOL'
EXPORTING
mode_ztest_demo_sch = 'E'
mandt = sy-mandt
guid = ms_header-guid
x_guid = ' '
_scope = '2'
_wait = ' '
_collect = ' '
EXCEPTIONS
foreign_lock = 1
system_failure = 2
OTHERS = 3.
IF sy-subrc <> 0.
* Implement suitable error handling here
ENDIF.
ms_header-version = 1.
ms_header-status = '4'.
ms_header-zcre_user = sy-uname.
ms_header-zcre_date = sy-datum.
ENDIF.
* 修改
IF mv_curr_action EQ 'ADJUST'.
mv_adjut_guid = ms_header-guid.
SELECT SINGLE * INTO CORRESPONDING FIELDS OF ls_header
FROM ztest_demo_sch
WHERE guid = lv_guid.
IF sy-subrc EQ 0.
TRY.
ms_header-guid = cl_system_uuid=>create_uuid_x16_static( ).
CATCH cx_uuid_error .
ENDTRY.
ms_header-status = '4'.
ms_header-version = ls_header-version + 1.
ms_header-zcre_user = sy-uname.
ms_header-zcre_date = sy-datum.
CLEAR:ms_header-zlch_user,ms_header-zlch_date.
ENDIF.
* 查看
ELSEIF mv_curr_action EQ 'DISPLAY'.
CLEAR:ms_header.
SELECT SINGLE * INTO CORRESPONDING FIELDS OF ms_header
FROM ztest_demo_sch
WHERE guid = lv_guid.
ENDIF.
ENDTRY.
ENDIF.
ENDMETHOD.
总结
页面已经OK,主页面(明细页面)和初始页面(搜索页面)该优化的也优化了,跳转也做好了,下一篇完善其中的主要功能,比如创建如何带出系统中数据展示在页面上,保存或单步审批添加应有校验,调整数据如何带出上一版数据,上载数据或下载模板的实现,以及返回搜索页面的实现