基于Vue开发钉钉企业内部应用入门教程

准备工作

了解:在准备开发钉钉企业内部应用之前,你需要了解钉钉不同类别微应用之间区别,钉钉微应用大致分为:企业内部应用,服务窗(外部)应用和ISV服务商应用。
企业内部应用和服务窗应用主要是为自己企业提供相应的服务,而ISV是为不同企业提供通用服务。
开发者可以根据自己企业的开发需求注册成为对应类型的开发者,开发者类型有企业应用开发者和ISV开发者。

注册钉钉企业和申请企业微应用可以参考官方文档。

创建企业微应用时需要填写首页地址,在开发阶段,首页地址一般设为自己应用的测试地址。
钉钉本地开发和测试环境的搭建:
第一种是使用第三方的“内网穿透工具”,在这里使用的国内基于ngrok创建的natapp。两者的使用方式是基本一样,只是natapp做了一些封装,速度、操作上面更符合国人的习惯。这个软件是支持windows、linux、mac不同的操作系统。linux、mac下面使用命令行或者其他的方式运行就可以了。
在Windows直接点击运行natapp.exe,linux、mac下面使用命令行或者其他的方式运行就可以了。

第二种是在局域网内部署DNS服务器,可以使用dnsmasq服务来构建,手机无需修改系统的host来访问测试应用,相对来说,部署本地DNS服务会更复杂一些,但对于团队协作开发、测试会更方便。

另外,在创建企业微应用后,后台会在微应用的配置界面生成一个agentId,这个agentId就是微应用的ID,后面我们在免登、发送工作通知等场景用到。

如果你的微应用仅仅是一个H5的入口,不需要使用钉钉提供的一些原生能力,那么到这里就可以了。但若是使用钉钉自身提供的能力,则通常需要经过钉钉的授权。

(服务端开发内容)企业访问钉钉开放平台接口的全局唯一凭证,调用接口时需携带AccessToken,而获取AccessToken需要用CorpID和CorpSecret来换取,CorpID是企业在钉钉中标识,每个企业拥有唯一的CorpID,CorpSecret是企业每个应用的凭证密钥,参考文档

获取CorpID和CorpSecret的方式可以参考文档。

初始化项目

我们使用Vue作为基础框架来开发我们的钉钉微应用,采用前后端分离的方式,首先使用vue-cli来初始化应用:

$ vue init webpack myapp

初始化完成后,安装项目依赖:

$ npm install

引入dingtalk-sdk
dingtalk-sdk的方式有两种:

第一种是直接通过npm引入依赖包

import dingtalk from 'dingtalk-javascript-sdk'

文档参考https://github.com/open-dingtalk/dingtalk-javascript-sdk

第二种是在index.html页面<header>中引入dingtalk.js
http://g.alicdn.com/dingding/open-develop/1.6.9/dingtalk.js
或者
https://g.alicdn.com/dingding/open-develop/1.6.9/dingtalk.js

然后进入项目根目录下的build文件夹,打开webpack.base.conf.js文件,在

module.exports = {
  ...
  externals: {
      dd: 'dd'  
  }
  ...
}

这样就可以在项目中直接引入dd这个全局变量

import dd from 'dd'

第一种方式和第二种方式在用法上稍微有些区别,js-sdk中ready、config、error等方法在dingtalk-javascript-sdk是直接挂在dingtalk对象上,相应的移动端api则在dingtalk.apis中,但在dingtalk.js中是全部挂在dd全局对象中。可以参考上面两者的文档比较其差别。

配置完成之后,我们就可以开始正式写代码了
JS-API权限配置
我们以第二种引入方式为例,首先在main.js中进行鉴权操作,由于采用前后端分离的方式,我们将相应的参数存储在服务端,在应用初始化的时候向服务端获取这些参数,JS-API鉴权需要agentId、corpId、timeStamp、nonceStr、signature,服务端给出的agentId和corpId从之前钉钉管理后台获取,timeStamp时间戳、签名随机串由服务生成,signature签名由服务端通过sign(ticket, nonceStr, timeStamp, url)计算前端校验需要使用的签名信息,具体参考文档。

这里的url,服务端可以通过调用接口的url来获取。需要和钉钉微应用配置的首页地址一致。
main.js:

import Vue from 'vue'
import dd from 'dd'
import axios from 'axios'

let _config

axios.get('/dingapi')
  .then(function (response) {
     _config = response
     dd.config({    
         agentId: _config.agentId,    
         corpId: _config.corpId,    
         timeStamp: _config.timeStamp,    
         nonceStr: _config.nonceStr,    
         signature: _config.signature,    
         jsApiList: [      
           'biz.contact.departmentsPicker',      
           'biz.contact.choose'    
         ]  })
  })
  .catch(function (error) {
    console.log(error);
  });

new Vue({  
  el: '#app',
  template: '<App/>',  
  components: { App }
})

main.js在实际项目中可能还需要加入vue-router、vuex等插件,请自行参考vue的相应文档。
签名校验完成后我们可以在后续获得相应的免登授权码,在main.js中加入相应代码:

import Vue from 'vue'
import dd from 'dd'
import axios from 'axios'

let _config

axios.get('/dingapi')
  .then(function (response) {
     _config = response
     dd.config({    
         agentId: _config.agentId,    
         corpId: _config.corpId,    
         timeStamp: _config.timeStamp,    
         nonceStr: _config.nonceStr,    
         signature: _config.signature,    
         jsApiList: [      
           'biz.contact.departmentsPicker',      
           'biz.contact.choose'    
         ]  })
  })
  .then(function() {
    dd.ready(function () {    
      dd.runtime.permission.requestAuthCode({      
        corpId: _config.agentId,      
        onSuccess: function (result) {        
          const _code = result.code
          // 如果项目中使用了vuex之类的状态管理插件,可以直接执行相应的action,通过ajax向服务端来获取相应的用户信息,或者这里直接通过ajax调用服务端的免登接口来获取用户信息
          // store.dispatch('login', {code: _code})
        },      
        onFail: function (err) {       
          console.log('dd error' + JSON.stringify(err))      
        }    
      })  
    })  

    dd.error(function (error) {    
      console.log('dd error' + JSON.stringify(error))  
    })
  })
  .catch(function (error) {
    console.log(error);
  });

new Vue({  
  el: '#app',
  template: '<App/>',  
  components: { App }
})

假设项目中使用了vuex,我们可以将相应的用户数据存在store中,以方便各个组件的调用。

在vue应用的组件中,我们调用dd相应的api来获得相应的功能:

<template>
  ....
</template>
<script>
  import dd from 'dd'
  export default {
    name: 'mycomponent',
    mounted () {
      dd.device.notification.alert({
        message: "亲爱的",
        title: "提示",//可传空
        buttonName: "收到",
        onSuccess : function() {
            //onSuccess将在点击button之后回调
            /*回调*/
        },
        onFail : function(err) {}
      })
    },
    mothods: {
      alertMessage (message, title, buttonName) {
        dd.device.notification.alert({
          message: message",
          title: title,
          buttonName: buttonName,
          onSuccess: function() {
              //onSuccess将在点击button之后回调
              /*回调*/
          },
          onFail: function(err) {}
        })
      }
    }
  }
</script>

钉钉移动端JS-API参考官方文档。
dingtalk中还有许多功能没有释放出来,我们期待钉钉官方的后续版本。