SAP 基于VUE的BSP单页移动端Web App开发

背景介绍

在制造业中,一般仓库和物流都会配备扫码枪来进行诸如收货、移库、盘点等操作。
SAP提供了ITS Mobile和RF Framework用来开发能够运行在扫码枪上的应用,但本质还是通过WebGUI技术,让扫码枪通过浏览器来登陆SAP,使用专门为小屏设备开发的Dialog程序。
扫码枪设备长期以来,操作系统一直被WinCE把持,或许是因为微软税的缘故,导致这些扫码枪除了耐操的优点外,别无长处。万年电阻屏、屏幕小、性能孱弱,更要命的是价格奇贵无比。
进入智能机时代,安卓发力,扫码枪系统多了一个选择。安卓扫码枪不仅配置强大,系统先进,而且因为系统免费的缘故,售价远低于搭载Win CE的扫码枪。在这样的背景下,笔者公司已采购安卓扫码枪来替代旧设备。
这时带来一个问题,无论ITS Mobile还是RF Framework,都是根植于Win CE设备,在安卓扫码枪上,体验落后。
为了改善用户体验,笔者起初想通过UI5开发HTML5应用来适配安卓,于是便浏览SCN查找资料。但随着笔者的深入研究,发现论坛上出现了另外一些声音。
虽然UI5是SAP极力推荐的前端框架,但有些资深开发人员(甚至SAP Lab的ABAP)都并不是很推崇使用UI5。主要诟病的地方在于UI5太过于复杂和庞大,学习成本高且极为占用硬件资源。有位ABAP甚至直言,除了SAP外,你找不到第二个公司会使用UI5去开发Web应用。
一位国内的ABAP顾问便提供了另一种思路。他曾参与过国内一家公司的项目,因甲方Manager是一位Vue.js的粉丝,所以他们内部采用Vue.js在BSP上开发了移动端Web App。
相较于UI5,Vue.js是目前极为流行的JS框架,网络资源丰富,还有完整的中文教程。且GitHub上有大量开箱即用的Vue前端框架可以选择,不需要担心界面美化的问题。Vue极为轻量,完整的JS文件大小100K不到,而SAP Open UI5都已经150M起步。另外Vue是MIT协议,不会产生任何费用。更为优秀的一点,是Vue完全基于JS,而不像UI5还须要受制于SAP版本,理论上只要你的SAP版本支持BSP(这要求实在是太低了),就能用Vue.js开发符合潮流的现代化移动端应用。
废话不多说,下面笔者就以一个查询库存的应用来简单介绍下如何在BSP上使用Vue.js搭建Web App。
附:SCN相关链接
如何使用vue.js和axios开发能与SAP交互的Web Appmodern-web-development-with-sap-hands-on-vue.js-axios
如何在BSP上跑vue.js的应用(这个案例使用了webpack打包JS,好处是能够进一步压缩js文件大小,缺点是代码不能直接在SAP中管理,笔者建议无深厚JS功底的读者请暂时不要尝试该博文的方法)step-by-step-to-run-vue-application-in-bsp

需求分析

笔者假定用户现在须要一个移动端Web App,能够查询SAP中的实时库存信息。就像传统的报表一样,我们须要一个界面来给用户提供查询条件,并提供一个按钮,当用户输入查询条件并点击按钮后,查询SAP库存的信息,以表格的形式将结果返回给用户。

资源准备

首先我们须要搭建一个交互式的现代BSP页面,我们须要Vue.js作为引擎来驱动这个页面,右键另存下方的js文件。
vue.js

Vue相当于一个Controller,负责控制前台的渲染和界面事件交互,展现须要另外的前端框架,这里笔者选用的是Buefy,这个框架的优点是极为轻量,这样可以确保在网速不佳的情况下也能较快的获取到js和css文件。右击另存下方的js文件和css文件。
buefy.min.js
buefy.min.css

因为SAP本身限制,MIME资源如果全部放在BSP项目下,读取速度会非常慢,所以除了核心的js文件,其它像是图片一类的文件,建议能不使用尽量不要使用,一定要使用,就优先使用SVG格式的图片,或是干脆引用互联网图片

需求中涉及与SAP后端交互的功能,笔者这里使用了axios这个HTTP库来实现。同样右键另存到本地先。
axios.min.js

搭建
  • 在SE80中新建一个BSP应用,Y_TUTORIAL_VUE
    SAP 基于VUE的BSP单页移动端Web App开发_第1张图片

  • 在应用下新建一个页面index.htm,并设置其为Start Page,这将是我们Web App的主页面。
    SAP 基于VUE的BSP单页移动端Web App开发_第2张图片SAP 基于VUE的BSP单页移动端Web App开发_第3张图片

  • 继续新建另一个页面process.htm,这个页面并不用于展现,而是用于接收用户前台的查询条件,然后查找库存并将库存结果以json格式的字符串返回。注意,这里我们须要修改process.htm的Mime Type为application/json;charset=utf-8
    SAP 基于VUE的BSP单页移动端Web App开发_第4张图片SAP 基于VUE的BSP单页移动端Web App开发_第5张图片
    建议将Layout中的缺省HTML都删除,并在Page Attributes中定义一个没用的属性DUMMY来避免因为SAP缺少一些必要参数而导致无法激活的情况。
    SAP 基于VUE的BSP单页移动端Web App开发_第6张图片
    SAP 基于VUE的BSP单页移动端Web App开发_第7张图片

  • 将我们之前下载好的js文件和css文件统统上传到应用里。上传结束后,激活整个项目,你的项目下的目录应该如下面第二张图一样:
    SAP 基于VUE的BSP单页移动端Web App开发_第8张图片SAP 基于VUE的BSP单页移动端Web App开发_第9张图片

  • SAP中点击Index.htm的Layout页签,将下面的源码复制进去。(笔者已将具体代码的用途在备注中标明,如果还有不懂的地方可以参考文末的地址,去相关项目的官方文档中了解)

<html>
<head>
    
    <meta charset="utf-8">
    
    <meta name="viewport" content="width=device-width, initial-scale=1">
    
    <link rel="stylesheet" href="./buefy.min.css">
    
    <script src="./vue.js">script>
    
    <script src="./axios.min.js">script>
head>
<body>
    
    <script src="./buefy.min.js">script>
    
    <div id="my_app">
        
        <section class="hero is-dark">
          <div class="hero-body">
            <div class="container">
              <h1 class="title">
                Hello Vue.js
              h1>
              <h2 class="subtitle">
                {{ sap_func }} 
              h2>
            div>
          div>
        section>
        
        
        <section class="section">
          
          <b-field label="Material Number" :label-position="labelPosition">
              
              <b-input type="search" maxlength="18" v-model="matnr" @keyup.enter.native="search">b-input>
              <p class="control">
                  
                  <b-button class="button is-primary" @click="search">Searchb-button>
              p>
          b-field>
          
          
          
          
          <b-table
            :data="tab" 
            :bordered="false"
            :striped="false"
            :narrowed="true"
            :hoverable="false"
            :loading="false"
            :focusable="false"
            :mobile-cards="true"
            :paginated="true" 
            :per-page="2"
            >
            <template slot-scope="tab"> 
              <b-table-column field="id" label="ID">
                  {{ tab.row.id }}
              b-table-column>
              <b-table-column field="matnr" label="Material">
                  {{ tab.row.matnr }}
              b-table-column>
              <b-table-column field="maktx" label="Description">
                  {{ tab.row.maktx }}
              b-table-column>
              <b-table-column field="lgort" label="Location">
                  {{ tab.row.lgort }}
              b-table-column>
              <b-table-column field="labst" label="Quantity">
                <span class="tag is-success"> 
                  {{ tab.row.labst }}
                span>
              b-table-column>
            template>
            
            <template slot="empty">
                <section class="section">
                    <div class="content has-text-grey has-text-centered">
                        <b>No Datab>
                    div>
                section>
            template>
          b-table>
          
          
          <b-loading :is-full-page="true" :active.sync="isLoading" :can-cancel="false">b-loading>
        section>
        
    div>
    
    
    <script>
      // 这是用于处理查询请求,返回查询结果的界面
      const restService = 'process.htm';
      // 初始化我们的应用
      var app = new Vue({
        el: "#my_app", //绑定my_app
        data:{
          sap_func: "Inventory Report",// 应用名是库存报表
          labelPosition: 'on-border',
          isLoading: false, // 初始化不弹出loading界面
          matnr: '', // 初始没有查询条件
          tab: [] // 初始没有查询结果
        },

        // 与SAP交互的核心查询功能
        methods:{
          // 定义search方法,它会在点击查询按钮时被调用
          search: function(){
            // axios会使用HTTP POST方式,将matnr中的值,发送到另一个SAP页面并将返回的JSON值赋给my_app的tab
            axios.post(restService,{
              data:{
                'matnr': this.matnr
              }
            }).then((response) =>{
              this.tab = eval(response.data);
              this.isLoading = false; // 获取到值后关闭遮罩
            });
            this.isLoading = true; // 查询时打开遮罩
          }
        }
      });
    script>
    
body>
html>
  • SAP process.htm页面,点击Type Definitions,定义如下类型:
    09
"axios发过来的json request格式为data-data-matnr这样的数据结构
"我们须要定义相同的类型才能解析request的入参
TYPES:BEGIN OF TY_DATA,
      MATNR TYPE MATNR,
      END OF TY_DATA,
      BEGIN OF TY_JSON,
      DATA TYPE TY_DATA,
      END OF TY_JSON.

"这是我们返回查询结果的表
TYPES:BEGIN OF TY_MARD,
       ID    TYPE SY-TABIX,
       MATNR TYPE MATNR,
       MAKTX TYPE MAKTX,
       LGORT TYPE LGORT_D,
       LABST TYPE LABST,
     END OF TY_MARD.
  • SAP process.htm页面,点击Event Handler页签,我们修改它的OnCreate事件代码,将下面的代码黏贴进去。
    08
DATA:LV_STR  TYPE STRING,
     LS_PARA TYPE TY_JSON.

DATA:LS_MARD        TYPE TY_MARD,
     LT_MARD        TYPE TABLE OF TY_MARD,
     LO_JSON        TYPE REF TO CL_TREX_JSON_SERIALIZER,
     LV_RESULT_JSON TYPE STRING.

"获取用户的查询输入参数
LV_STR = RUNTIME->SERVER->REQUEST->GET_CDATA( ).
CALL METHOD CL_FDT_JSON=>JSON_TO_DATA
  EXPORTING
    IV_JSON = LV_STR
  CHANGING
    CA_DATA = LS_PARA.

TRANSLATE LS_PARA-DATA-MATNR TO UPPER CASE.

"获取库存信息
DO 5 TIMES.
  CLEAR:LS_MARD.
  LS_MARD-ID = SY-INDEX.
  LS_MARD-MATNR = 'MAT'.
  LS_MARD-MAKTX = 'TEST VUE'.
  LS_MARD-LGORT = 'SL01'.
  LS_MARD-LABST = SY-INDEX.
  APPEND LS_MARD TO LT_MARD.
ENDDO.

DELETE LT_MARD WHERE MATNR NE LS_PARA-DATA-MATNR.


"将结果转化为JSON格式返回给客户端
CREATE OBJECT LO_JSON
  EXPORTING
    DATA = LT_MARD.

LO_JSON->SERIALIZE( ).
LV_RESULT_JSON = LO_JSON->GET_DATA( ).
RUNTIME->SERVER->RESPONSE->SET_CDATA( DATA = LV_RESULT_JSON ).
验证结果

完成上述所有步骤后,激活整个BSP项目,并找到index.htm的网页地址。在浏览器中打开。
10如果没有问题,就会看到这样的页面,在Material Number中输入MAT并点击Search按钮或敲击回车。
SAP 基于VUE的BSP单页移动端Web App开发_第10张图片
如果没有问题,你就应该可以看到如下的页面了:
SAP 基于VUE的BSP单页移动端Web App开发_第11张图片

相关参考网站

buefy
vuejs
axios

你可能感兴趣的:(ABAP阿卡姆,ABAP,SAP,VUE)