1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 企业微信开发实战(五 自建应用-审批流程引擎之配置可信任域名 创建审批模版 发起

企业微信开发实战(五 自建应用-审批流程引擎之配置可信任域名 创建审批模版 发起

时间:2018-08-16 08:46:37

相关推荐

企业微信开发实战(五 自建应用-审批流程引擎之配置可信任域名 创建审批模版 发起

文章目录

四、自建应用-审批流程引擎1.概述2.创建自建应用审批模板2.1创建自建审批应用2.2配置可信任域名2.3创建审批模版3.自建应用发起审批3.1概述3.2代码实战3.2.1前端代码3.2.2后端代码3.3试错源码赞赏

四、自建应用-审批流程引擎

1.概述

1、企业微信向开发者提供审批流程引擎,此特性可将审批流程相关功能嵌入到自建应用中。

2、开发者可在自建应用中直接调用接口发起审批申请,系统根据审批流程自动通知相关人员进行审批操作。

3、提交申请后审批流程的每次状态变化,都会通知开发者,可按需进行拓展开发。

此套接口在自建应用中闭环,与“企业微信审批应用”相关接口无关。

2.创建自建应用审批模板

2.1创建自建审批应用

1、找到"应用管理"->“自建”->点击"创建应用"。

开发者可在“管理后台-自建应用-审批接口”中,创建审批模板。

2、选择应用logo,应用名称设置为"自建审批应用",可见范围选择某个部门,再点击"创建应用",即可看到出现第"1"步中的带有"柯南"头像的自建审批应用。

3、点击上图带"柯南"头像的自建审批应用,来到该应用的详情页。

(1)点击"查看"获取应用secret。

(2)点击下图应用主页的"修改",设置应用主页的网址(对应你内网穿透的网址),后续在客户端中点击"自建审批应用"时,就会调到该链接指向的主页。

2.2配置可信任域名

1、找到"开发者接口"->“网页授权及JS-SDK”。

2、如下图所示,将内网穿透的域名添加为可信域名(注:这里需要去掉"http://“或"https://”)

3、打开企业微信客户端,进行如下图1、2步操作,可看到出现创建的 Core Web项目的首页,原因是再"2.1创建自建审批应用"步骤是设置了该内网穿透网址对应的应用程序为应用的主页。

2.3创建审批模版

1、找到"开发者接口"->“审批接口”。

2、如下图所示,点击"添加模版",创建一个名为"测试模版"的审批模版。

功能说明:

3.自建应用发起审批

3.1概述

通过JS-SDK,可在自建应用中发起审批。查看JS-SDK调用详细说明

具体步骤:

(1)通过config接口注入权限验证配置。查看

(2)通过agentConfig注入应用的权限。查看

(3)调用审批流程引擎JS-API(如下文请求示例)。

注:企业微信客户端2.5.0及以上版本支持。

3.2代码实战

3.2.1前端代码

1、创建一个名为SelfApprovalController的控制器,并在"Pages"文件夹中创建一个"About.cshtml",并在"_Layout.cshtml"中About菜单项的代码做如下更改:

<li class="nav-item"><a href="/About" class="nav-link">About</a></li>

2、About.cshtml的代码如下(请先阅读"3.1概述"中对应链接的内容后,再看该cshtml中的代码,因为这里的代码主要也是在官方文档中复制的):

@page@using QiYeWeiXinDev.Models<h1>显示Json</h1><pre id="showJson"></pre>@(Html.DevExtreme().Button().Text("测试").Type(ButtonType.Default).Width(100).OnClick("TestFun"))@*引入使用JS-SDK需要用到的js*@<script src="//res./open/js/jweixin-1.2.0.js"></script><script src="https://open.work./wwopen/js/jwxwork-1.0.0.js"></script><script type="text/javascript">function TestFun() {$.ajax({type: "GET",url: "api/SelfApproval/OutputJsApiTicketConfig",//请求后端生成好的配置success: function (res) {console.log(res);wx.config({beta: true,// 必须这么写,否则wx.invoke调用形式的jsapi会有问题debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。appId: res.corpi, // 必填,企业微信的corpIDtimestamp: res.timestamp, // 必填,生成签名的时间戳nonceStr: res.nonceStr, // 必填,生成签名的随机串signature: res.signature,// 必填,签名,见 附录-JS-SDK使用权限签名算法jsApiList: ['agentConfig', 'openUserProfile', 'thirdPartyOpenPage', 'selectExternalContact'] // 必填,需要使用的JS接口列表,凡是要调用的接口都需要传进来});wx.ready(function () {// config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。console.log(" wx.ready");wx.checkJsApi({jsApiList: ['thirdPartyOpenPage'], // 需要检测的JS接口列表,所有JS接口列表见附录2,success: function (res) {console.log(res)// 以键值对的形式返回,可用的api值true,不可用为false// 如:{"checkResult":{"chooseImage":true},"errMsg":"checkJsApi:ok"}},fail: function (res) {console.log(res);}});wx.agentConfig({corpid: res.corpi, // 必填,企业微信的corpid,必须与当前登录的企业一致agentid: res.agentId, // 必填,企业微信的应用id (e.g. 1000247)timestamp: res.timestamp, // 必填,生成签名的时间戳nonceStr: res.nonceStr, // 必填,生成签名的随机串signature: res.agentSignature,// 必填,签名,见附录-JS-SDK使用权限签名算法jsApiList: ['agentConfig', 'openUserProfile', 'thirdPartyOpenPage', 'selectExternalContact'], //必填,传入需要使用的接口名称success: function (res) {console.log("agentConfig");console.log(res);// 回调wx.invoke('thirdPartyOpenPage', {"oaType": "10001",// 操作类型,目前支持:10001-发起审批;10002-查看审批详情"templateId": "1aa556e88991520f9b2477e8f1d3a6e8_852697916",// 发起审批的模板ID,在自建应用-审批接口中创建模板可获取。"thirdNo": "thirdNo" + new Date().getTime(),// 审批单号,由开发者自行定义,不可重复。"extData": {'fieldList': [{'title': '采购类型','type': 'text','value': '市场活动',},{'title': '订单链接','type': 'link','value': 'https://work.',}],}},function (res) {// 输出接口的回调信息console.log("回调的信息");console.log(res);});},fail: function (res) {console.log(res);if (res.errMsg.indexOf('function not exist') > -1) {alert('版本过低请升级')}}});});wx.error(function (res) {// config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。console.log(res)});}})}/*agentConfig的作用config注入的是企业的身份与权限,而agentConfig注入的是应用的身份与权限。尤其是当调用者为第三方服务商时,通过config无法准确区分出调用者是哪个第三方应用,而在部分场景下,又必须严谨区分出第三方应用的身份,此时即需要通过agentConfig来注入应用的身份信息。解释:企业的身份与权限:用于帮助企业微信客户端了解当前是 哪个企业 正在申请接口调用权限应用的身份与权限:用于帮助企业微信客户端了解当前是 哪个第三方应用 正在申请接口调用权限调用agentConfig的注意事项agentConfig与config的签名算法完全一样,但是jsapi_ticket的获取方法不一样,请特别注意,查看”获取应用身份的ticket“.调用wx.agentConfig之前,必须确保先成功调用wx.config. 注意:从企业微信3.0.24及以后版本(可通过企业微信UA判断版本号),无须先调用wx.config,可直接wx.agentConfig.当前页面url中的域名必须是在该应用中设置的可信域名。agentConfig仅在企业微信2.5.0及以后版本支持,微信客户端不支持(微信开发者工具也不支持)仅部分接口才需要调用agentConfig,需注意每个接口的说明*/</script>

3.2.2后端代码

1、获取自建应用的accessToken

(1)控制器中的代码如下:

private MemoryCacheHelper _cahce;private TokenTicketHelper _tokenTicketHelper;private HttpUtils _httpUtils;private JsonXmlHelper _jsonXmlHelper;public SelfApprovalController(MemoryCacheHelper cahce,TokenTicketHelper tokenTicketHelper,HttpUtils httpUtils, JsonXmlHelper jsonXmlHelper){_cahce = cahce;_tokenTicketHelper = tokenTicketHelper;_httpUtils = httpUtils;_jsonXmlHelper = jsonXmlHelper;}#region 1、获取accesstoken/// <summary>/// 请求企业微信自建审批应用accessToken/// </summary>/// <returns></returns>[Route("CacheTryGetAppToken")]public IActionResult CacheTryGetAppToken(){return Json(_tokenTicketHelper.GetSelfApprovalAccessToken());}#endregion

(2)TokenTicketHelper的代码如下:

using Newtonsoft.Json;using QiYeWeiXinDev.Models;using QiYeWeiXinDev.Models.QiYeWX;using QiYeWeiXinDev.Models.QiYeWX.AccessToken;using QiYeWeiXinDev.Utils.Cache;using System;using System.Collections.Generic;using System.Linq;using .Http;using System.Threading.Tasks;namespace QiYeWeiXinDev.Utils{/// <summary>/// token、ticket帮助类/// </summary>public class TokenTicketHelper{private MemoryCacheHelper _cahce;public TokenTicketHelper(MemoryCacheHelper cahce){_cahce = cahce;}#region 1、获取accessToken/// <summary>/// 请求企业微信accessToken/// </summary>/// <param name="accessTokenKey"></param>/// <returns></returns>private async Task<T> RequireAccessToken<T>(RequireTokenModel model) where T : class{T result = null;try{//1、构建请求token的urlstring url = string.Format(model.requireUrl, model.corpi, model.secret);//2、请求using (HttpClient client = new HttpClient()){//3、反序列化为T对应的模型类result = JsonConvert.DeserializeObject<T>(await client.GetStringAsync(url));}}catch (Exception ex){//后面添加日志记录Console.WriteLine(ex);}return result;}/// <summary>/// 获取缓存中的accesstoken/// </summary>/// <param name="accessTokenKey"></param>/// <returns></returns>private AccessTokenModel CacheAccessToken(RequireTokenModel model){var accessToken = _cahce.Get<AccessTokenModel>(model.accessTokenKey);if (accessToken == null){// 往memorycache里面存入数据accessToken = RequireAccessToken<AccessTokenModel>(model).Result;_cahce.Set(model.accessTokenKey, accessToken, TimeSpan.FromSeconds(PublicParam.sleepTime));}return accessToken;}/// <summary>/// 获取审批应用accessToken/// </summary>/// <param name="accessTokenKey"></param>/// <returns></returns>public AccessTokenModel GetApprovalAccessToken(){RequireTokenModel model = new RequireTokenModel(){requireUrl = PublicParam.tokenRequireUrl,accessTokenKey = PublicParam.defaultApprovalAccessTokenKey,corpi = PublicParam.corpi,secret = PublicParam.defaultApprovalSecret};return CacheAccessToken(model);}/// <summary>/// 获取自建审批应用accessToken/// </summary>/// <param name="accessTokenKey"></param>/// <returns></returns>public AccessTokenModel GetSelfApprovalAccessToken(){RequireTokenModel model = new RequireTokenModel(){requireUrl = PublicParam.tokenRequireUrl,accessTokenKey = PublicParam.selfApprovalAccessTokenKey,corpi = PublicParam.corpi,secret = PublicParam.selfApprovalAgentSecret};return CacheAccessToken(model);}#endregion#region 2、获取JSApiTicket/// <summary>/// 请求企业微信JSApiTicket/// </summary>/// <returns></returns>//private async Task<JSApiTicketModel> RequireJSApiTicket()private async Task<T> RequireJSApiTicket<T>(string url) where T : class{T result = null;try{using (HttpClient client = new HttpClient()){result = JsonConvert.DeserializeObject<T>(await client.GetStringAsync(url));}}catch (Exception ex){//后面添加日志记录Console.WriteLine(ex);}return result;}/// <summary>/// 获取缓存中的jsapi_ticket/// </summary>/// <param name="accessTokenKey"></param>/// <returns></returns>private JSApiTicketModel CacheJSApiTicket(string url, string jsApiTicketKey){var jsApiTicket = _cahce.Get<JSApiTicketModel>(jsApiTicketKey);if (jsApiTicket == null){// 往memorycache里面存入数据jsApiTicket = RequireJSApiTicket<JSApiTicketModel>(url).Result;_cahce.Set(jsApiTicketKey, jsApiTicket, TimeSpan.FromSeconds(PublicParam.sleepTime));}return jsApiTicket;}/// <summary>/// 获取企业JSApiTicket/// </summary>/// <returns></returns>public JSApiTicketModel GetCorpApprovalJSApiTicket(){var tokenModel = GetSelfApprovalAccessToken();string accessToken = tokenModel == null ? null : tokenModel.access_token;//构建 获取企业JSApiTicket请求urlstring url = string.Format(PublicParam.jsapiTicketUrl,accessToken);return CacheJSApiTicket(url, PublicParam.jsApiTicketKey);}/// <summary>/// 请求企业微信审批应用JSApiTicket/// </summary>/// <returns></returns>public JSApiTicketModel GetSelfAgentApprovalJSApiTicket(){var tokenModel = GetSelfApprovalAccessToken();string accessToken = tokenModel == null ? null : tokenModel.access_token;//构建 获取企业JSApiTicket请求urlstring url = string.Format(PublicParam.jsapiAgentTicketUrl, accessToken);return CacheJSApiTicket(url, PublicParam.selfAgentJsApiTicket);}#endregion}}#region SHA1/// <summary>/// 基于Sha1的自定义加密字符串方法:输入一个字符串,返回一个由40个字符组成的十六进制的哈希散列(字符串)。/// </summary>/// <param name="str">要加密的字符串</param>/// <returns>加密后的十六进制的哈希散列(字符串)</returns>private string SHA1Encode(string str){var buffer = Encoding.UTF8.GetBytes(str);var data = SHA1.Create().ComputeHash(buffer);var sb = new StringBuilder();foreach (var t in data){sb.Append(t.ToString("X2"));}return sb.ToString().ToLower();}#endregion

2、获取企业的jsapi_ticket

#region 2、获取企业的jsapi_ticket/*jsapi_ticket是H5应用调用企业微信JS接口的临时票据。正常情况下,* jsapi_ticket的有效期为7200秒,通过access_token来获取。* 由于获取jsapi_ticket的api调用次数非常有限(一小时内,一个企业最多可获取400次,且单个应用不能超过100次),* 频繁刷新jsapi_ticket会导致api调用受限,影响自身业务,开发者必须在自己的服务全局缓存jsapi_ticket。*//// <summary>/// 请求企业微信JSApiTicket/// </summary>/// <returns></returns>[Route("CacheTryGetTicket")]public IActionResult CacheTryGetTicket(){return Json(_tokenTicketHelper.GetCorpApprovalJSApiTicket());}#endregion

3、获取应用的jsapi_ticket

#region 3、获取应用的jsapi_ticket/// <summary>/// 请求企业微信审批应用JSApiTicket/// </summary>/// <returns></returns>[Route("CacheTryGetAgentTicket")]public IActionResult CacheTryGetAgentTicket(){return Json(_tokenTicketHelper.GetSelfAgentApprovalJSApiTicket());}#endregion

4、创建JsApiTicketConfig接口供About.cshtml调用

#region 4、输出JsApiTicketConfig给About.cshtml[Route("OutputJsApiTicketConfig")]public IActionResult OutputJsApiTicketConfig(){string nonceStr = "Wm3WZYTPz0wzccnW";//生成签名的随机字符串int timestamp = 1619056870;//时间戳string jsapi_ticket = "", agent_jsapi_ticket = "";string url = PublicParam.jsapiAccessUrl;// url(当前网页的URL, 不包含#及其后面部分)//get ticketvar ticketModel = _tokenTicketHelper.GetCorpApprovalJSApiTicket();var agentTicketModel = _tokenTicketHelper.GetSelfAgentApprovalJSApiTicket();if (ticketModel != null)jsapi_ticket = ticketModel.ticket;if (agentTicketModel != null)agent_jsapi_ticket = agentTicketModel.ticket;//append string string strTicket = $"jsapi_ticket={jsapi_ticket}&noncestr={nonceStr}&timestamp={timestamp}&url={url}";//append agentstring strAgentTicket = $"jsapi_ticket={agent_jsapi_ticket}&noncestr={nonceStr}&timestamp={timestamp}&url={url}";//output sha1 codestring signature = SHA1Encode(strTicket);string agentSignature = SHA1Encode(strAgentTicket);//output config dtoJsApiTicketConfigDTO dto = new JsApiTicketConfigDTO(){corpi = PublicParam.corpi,agentId = PublicParam.selfApprovalAgentId,nonceStr = nonceStr,timestamp = timestamp,signature = signature,agentSignature = agentSignature};return Json(dto);}#endregion

4、运行代码,在客户端中打开"自建审批应用"->“About”。

5、点击该页面的"测试"按钮,会出现一系列弹窗,一直点击"OK"即可,出现弹窗的原因是我们开启在前端代码中开启的debug模式(注:一定要在企业微信客户端访问,否则会出现问题,待会会在"试错"章节说明)。

6、选择"审批人",点击"提交"即可完成一次审批申请的发起

7、此时在"!!!“用户的企业微信账号上可以接收到该审批申请,点击"同意”,刚刚发起申请的用户就会接收到"你的测试模版已通过"的消息,如下图:

8、到这一步,我们就完成了自建应用发起审批的操作了,具体代码可看文末的git仓库地址。

3.3试错

1、在浏览器中打开"About.cshtml",并点击"测试"按钮,会出现 "agentConfig:fail"的错误,这是因为企业微信jssdk运行环境是有限制的,需要在企业微信环境中进行访问(企业微信pc端调试工具)。

{err_Info: "fail", errMsg: "agentConfig:fail", hint: "Hint: '0424164822:yZI2hABGJwWrT7DoZ6xwew:40093'. M…s://open.work./devtool/query?e=40093"}errMsg: "agentConfig:fail"err_Info: "fail"hint: "Hint: '0424164822:yZI2hABGJwWrT7DoZ6xwew:40093'. More info at https://open.work./devtool/query?e=40093"__proto__: Object

2、将代码agentSignature=SHA1Encode(strAgentTicket)更改为agentSignature=SHA1Encode(strTicket),会出现如下错误,原因是我们配置agentConfig的signature需要使用"自建应用jsApiTicket"去构建,而不是"企业的jsApiTicket去构建"。

//string agentSignature = SHA1Encode(strAgentTicket);string agentSignature = SHA1Encode(strTicket);

可将模版id设置为不存在的模版id、设置错误的应用id等情况进行代码的配置,看看会出现什么错误提示。

参数说明:

extData数据说明:

extData在发起时由开发者传入,其中数据将全部展示在审批申请中:

1.开发者可利用此特性,在发起审批时,传入需要申请人、审批人、抄送人看到的信息;

2.若需用户填写数据,可在自行使用表单收集,并传入extData中,用于展示。

{ "extData": {'fieldList': [{'title': '采购类型','type': 'text','value': '市场活动',},{'title': '采购说明','type': 'text','value': '购买个人办公电脑',},{'title': '采购金额','type': 'text','value': '4839.00元',},{'title': '申请时间','type': 'text','value': '/06/20',},{'title': '订单链接','type': 'link', // link类型,用于在审批详情页展示第三方订单跳转地址'value': '',},],},}

参数说明:

错误说明:

源码

地址:/wusuoweixgy/QiYeWeiXinCode

克隆:git clone /wusuoweixgy/QiYeWeiXinCode.git

赞赏

​ 如果您觉得文章还不错,那就请作者喝杯咖啡吧!

企业微信开发实战(五 自建应用-审批流程引擎之配置可信任域名 创建审批模版 发起审批)

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。