递归函数实现省市区多级联动搜索帮助

发布时间 2023-11-01 18:09:59作者: 斌将军

1、需求背景

当程序中有互为层级的字段,需要使用搜索帮助时,可以通过多次调用搜索帮助来实现。比如在程序中需要填写省市区三级地址

2、实现方式

2.1、平铺直叙

程序的搜索帮助,通常使用F4IF_INT_TABLE_VALUE_REQUEST来实现。多级的搜索帮助,可以简单的通过多次调用F4函数来实现。

点击省字段,弹出省搜索帮助,根据选择的省份,查询对应的市,弹出市搜索帮助,根据选择的市,查询对应的区县,弹出区县搜索帮助,选择后更新到ALV报表。

同理,点击市则弹出市和区的搜索帮助;点击区则只弹出区的搜索帮助

如图所示:

点击省字段代码示例,省需要写三遍F4:

"--------------------@斌将军--------------------
READ TABLE gt_cjso_alv ASSIGNING <fs_cjso_alv> INDEX pv_row_no-row_id.
  "获取对应数据集
  CASE lv_fieldname1.
    WHEN 'ZZDEADREGION'."送货地址-省
      SELECT
        land1,
        bland AS zzdeadregion,
        bezei
      FROM t005u
      INTO TABLE @DATA(lt_t005u)
      WHERE land1 EQ 'CN'
        AND spras EQ @sy-langu.

      ASSIGN lt_t005u TO <lt_f4table>.

      REFRESH gt_return.
      CALL FUNCTION 'F4IF_INT_TABLE_VALUE_REQUEST'
        EXPORTING
          retfield        = lv_fieldname1
          dynpprog        = sy-repid
          dynpnr          = sy-dynnr
          dynprofield     = lv_fieldname2
          value_org       = 'S'
          display         = 'F'
        TABLES
          value_tab       = <lt_f4table>
          return_tab      = gt_return
        EXCEPTIONS
          parameter_error = 1
          no_values_found = 2
          OTHERS          = 3.

      IF sy-subrc =  0.
        READ TABLE gt_return INTO gs_return INDEX 1.
        IF sy-subrc = 0.
          ASSIGN COMPONENT lv_fieldname1 OF STRUCTURE <fs_cjso_alv> TO <lv_field>.
          <lv_field> = gs_return-fieldval.

          SELECT
            country,
            region,
            city_code AS zzdeadcity,
            city_name
          FROM v_adrcity
          INTO TABLE @DATA(lt_v_adrcity)
          WHERE country EQ 'CN'
            AND langu  EQ @sy-langu
            AND region EQ @<fs_cjso_alv>-zzdeadregion.
          ASSIGN lt_v_adrcity TO <lt_f4table>.

          lv_fieldname = 'ZZDEADCITY'.
          lv_dynprofld = 'ZZDEADCITY'.
          REFRESH gt_return.
          CALL FUNCTION 'F4IF_INT_TABLE_VALUE_REQUEST'
            EXPORTING
              retfield        = lv_fieldname
              dynpprog        = sy-repid
              dynpnr          = sy-dynnr
              dynprofield     = lv_dynprofld
              value_org       = 'S'
              display         = 'F'
            TABLES
              value_tab       = <lt_f4table>
              return_tab      = gt_return
            EXCEPTIONS
              parameter_error = 1
              no_values_found = 2
              OTHERS          = 3.

          IF sy-subrc =  0.
            READ TABLE gt_return INTO gs_return INDEX 1.
            IF sy-subrc = 0.
              ASSIGN COMPONENT 'ZZDEADCITY' OF STRUCTURE <fs_cjso_alv> TO <lv_field>.
              <lv_field> = gs_return-fieldval.

              lv_zzdeadcity = |{ <fs_cjso_alv>-zzdeadcity ALPHA = IN }|.
              SELECT
                country,
                city_code,
                city_name,
                strt_code AS zzdeadstreet,
                street
              FROM m_strta
              INTO TABLE @DATA(lt_m_strta)
              WHERE country EQ 'CN'
                AND langu  EQ @sy-langu
                AND region EQ @<fs_cjso_alv>-zzdeadregion
                AND city_code EQ @lv_zzdeadcity.

              ASSIGN lt_m_strta TO <lt_f4table>.

              lv_fieldname = 'ZZDEADSTREET'.
              lv_dynprofld = 'ZZDEADSTREET'.
              REFRESH gt_return.
              CALL FUNCTION 'F4IF_INT_TABLE_VALUE_REQUEST'
                EXPORTING
                  retfield        = lv_fieldname
                  dynpprog        = sy-repid
                  dynpnr          = sy-dynnr
                  dynprofield     = lv_dynprofld
                  value_org       = 'S'
                  display         = 'F'
                TABLES
                  value_tab       = <lt_f4table>
                  return_tab      = gt_return
                EXCEPTIONS
                  parameter_error = 1
                  no_values_found = 2
                  OTHERS          = 3.

              IF sy-subrc =  0.
                READ TABLE gt_return INTO gs_return INDEX 1.
                IF sy-subrc = 0.
                  ASSIGN COMPONENT 'ZZDEADSTREET' OF STRUCTURE <fs_cjso_alv> TO <lv_field>.
                  <lv_field> = gs_return-fieldval.
                ENDIF.
              ENDIF.
            ENDIF.
          ENDIF.
        ENDIF.
      ENDIF.
    WHEN 'ZZDEADCITY'."送货地址-市
    ……
    WHEN 'ZZDEADSTREET'."送货地址-区县
    ……
    WHEN OTHERS.
  ENDCASE.

  PERFORM frm_refresh_alv USING g_grid_9001.
"--------------------@斌将军--------------------

2.2、简洁递归

上述方法,虽然能够实现,但是三级地址就需要写五遍重复性代码,如果遇到层级更多的搜索帮助,则需要写N(N+1)/2遍代码,所以我们可以使用递归函数,重复调用搜索帮助,使代码更简洁。

这里说明一点,什么是递归函数?

递归函数:在函数内部调用自身的函数被称为递归函数。递归函数可以将复杂问题转化为更简单的子问题来解决。一个经典的递归函数例子是阶乘函数,其中 n! 等于 n 乘以 (n-1)!。在函数内部通过调用自身来计算阶乘。

抽出通用代码,编写递归函数

"--------------------@斌将军--------------------
FORM frm_callback_f4 USING pv_level pv_fieldname CHANGING ps_alv TYPE ty_cjso_alv.

*  DATA:lv_zzdeadcity   TYPE vbak-zzdeadcity. "送货地址-市

  DATA:lt_return TYPE STANDARD TABLE OF ddshretval,
       ls_return TYPE ddshretval.

  DATA:lv_next_field TYPE dfies-fieldname,
       lv_next_level TYPE int4,
       lv_fieldname  TYPE dfies-fieldname,
       lv_dynprofld  TYPE help_info-dynprofld.

  FIELD-SYMBOLS:<lv_field>.

  lv_fieldname = pv_fieldname.
  lv_dynprofld = pv_fieldname.
  CONDENSE:lv_fieldname,lv_dynprofld NO-GAPS.
  lv_next_level = pv_level.
  "根据层级,查询当前层级的数据集,并赋值下一层的字段名
  CASE lv_next_level.
    WHEN 1."第1层 省
      SELECT
        land1,
        bland AS zzdeadregion,
        bezei
      FROM t005u
      INTO TABLE @DATA(lt_t005u)
      WHERE land1 EQ 'CN'
        AND spras EQ @sy-langu.

      UNASSIGN <gt_f4table>.
      ASSIGN lt_t005u TO <gt_f4table>.
      lv_next_field = 'ZZDEADCITY'.
    WHEN 2."第2层 市
      SELECT
        country,
        region,
        city_code AS zzdeadcity,
        city_name
      FROM v_adrcity
      INTO TABLE @DATA(lt_v_adrcity)
      WHERE country EQ 'CN'
        AND langu  EQ @sy-langu
        AND region EQ @ps_alv-zzdeadregion.

      UNASSIGN <gt_f4table>.
      ASSIGN lt_v_adrcity TO <gt_f4table>.
      lv_next_field = 'ZZDEADSTREET'.
    WHEN 3."第3层 区
      DATA(lv_zzdeadcity) = |{ ps_alv-zzdeadcity ALPHA = IN }|.
      SELECT
        country,
        city_code,
        city_name,
        strt_code AS zzdeadstreet,
        street
      FROM m_strta
      INTO TABLE @DATA(lt_m_strta)
      WHERE country EQ 'CN'
        AND langu  EQ @sy-langu
        AND region EQ @ps_alv-zzdeadregion
        AND city_code EQ @lv_zzdeadcity.

      UNASSIGN <gt_f4table>.
      ASSIGN lt_m_strta TO <gt_f4table>.

    WHEN OTHERS.
  ENDCASE.

  "调用搜索帮助函数
  CALL FUNCTION 'F4IF_INT_TABLE_VALUE_REQUEST'
    EXPORTING
      retfield        = lv_fieldname
      dynpprog        = sy-repid
      dynpnr          = sy-dynnr
      dynprofield     = lv_dynprofld
      value_org       = 'S'
      display         = 'F'
    TABLES
      value_tab       = <gt_f4table>
      return_tab      = lt_return
    EXCEPTIONS
      parameter_error = 1
      no_values_found = 2
      OTHERS          = 3.

  IF sy-subrc =  0.
    READ TABLE lt_return INTO ls_return INDEX 1.
    IF sy-subrc = 0.
      ASSIGN COMPONENT lv_fieldname OF STRUCTURE ps_alv TO <lv_field>.
      <lv_field> = ls_return-fieldval.
      IF lv_next_level < 3."第三层查询完退出
        lv_next_level = lv_next_level + 1.
        "调用函数本身,开始下次循环
        PERFORM frm_callback_f4 USING lv_next_level lv_next_field CHANGING ps_alv.
      ENDIF.
    ENDIF.
  ENDIF.
ENDFORM.
"--------------------@斌将军--------------------

在点击字段时调用,通过赋值层级,就可以循环调用多级搜索帮助,且代码更加简洁,复用性更高

"--------------------@斌将军--------------------
FORM frm_alv_on_f4_9001 USING pv_fieldname pv_fieldvalue pv_row_no TYPE lvc_s_roid
      pv_event_data TYPE REF TO cl_alv_event_data
      pv_display.


  READ TABLE gt_cjso_alv ASSIGNING <fs_cjso_alv> INDEX pv_row_no-row_id.
  "获取对应数据集
  CASE pv_fieldname.
    WHEN 'ZZDEADREGION'."送货地址-省
      PERFORM frm_callback_f4 USING 1 'ZZDEADREGION' CHANGING <fs_cjso_alv>.
    WHEN 'ZZDEADCITY'."送货地址-市
      PERFORM frm_callback_f4 USING 2 'ZZDEADCITY' CHANGING <fs_cjso_alv>.
    WHEN 'ZZDEADSTREET'."送货地址-区县
      PERFORM frm_callback_f4 USING 3 'ZZDEADSTREET' CHANGING <fs_cjso_alv>.
    WHEN OTHERS.
  ENDCASE.

  PERFORM frm_refresh_alv USING g_grid_9001.

ENDFORM.
"--------------------@斌将军--------------------

 

定期更文,欢迎关注