打开企微聊天工具栏(侧边栏),需要提前配置侧边栏应用页面,添加员工,给员工添加到对应的部门,员工再添加外部联系人(客户)。然后可以在和客户的聊天窗口看到联调工具栏的入口按钮,点击打开侧边栏。
聊天工具栏获取用户信息分两部分:一个是获取当前内部用户的userId,一个是获取外部联系人(客户)的externalUserId。
1.获取当前用户的userId
- 开发前准备: developer.work.weixin.qq.com/tutorial/h5…
- 官方接口调试工具: developer.work.weixin.qq.com/resource/de…
- 企微oAuth2授权官方文档: developer.work.weixin.qq.com/document/pa…
- 客户端网页调试工具: developer.work.weixin.qq.com/document/pa… 获取当前用户userId需要使用企业微信oAuth授权,前端调open.weixin.qq.com/connect/oau… 接口传redirect_uri为encode后的当前页面的地址, 授权后会返回重定向后的url并拼上授权code, 截取这个code调用后台接口获取userId。
// router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import { routes } from './routes'
import { getWxConfig, getUserInfo } from '@/apis/apis';
Vue.use(Router);
function Authorize(to) {
// 先获取企微配置信息
getWxConfig().then((res) => {
let { code, data, message } = res || {};
if (code === 200) {
let corpid = data.corpid;
let originUrl = location.href; originUrl;
let redirectUrl = originUrl.split('?')[0];
let returnUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${corpid}&redirect_uri=${encodeURIComponent(redirectUrl)}&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect`
window.location.href = returnUrl;
} else {
console.log(message);
}
console.log('error', error)
})
}
// 通过oAuth2授权获取当前用户userId
function getWxUserInfo(to, from, next, authCode) {
getUserInfo(authCode).then((res) => {
let { code, data, message } = res || {};
if (code === 200) {
let { userId } = data || {};
if (userId) {
localStorage.setItem('userId', userId);
next();
} else {
Authorize(to)
}
} else {
console.log(message);
// PC端侧边栏tab页面切换后再切回来, 页面地址还是上次重定向后的带code的,此时code已经消费过一次,再调接口获取用户信息会失败, 所以加上重新授权的逻辑
Authorize(to)
}
}).catch(() => {
Authorize(to)
})
}
const router = new Router({
mode: 'history',
scrollBehavior(to, from, savedPosition) {
if (savedPosition) { // 如果savedPosition存在,滚动条自动跳到记录的值的地方
return savedPosition
return { x: 0, y: 0 } // savedPosition也是一个记录x轴和y轴位置的对象
},
routes: routes
})
router.beforeEach((to, from, next) => {
// 判断是否是微信浏览器打开
let ua = navigator.userAgent.toLowerCase();
let isWeixin = ua.indexOf('micromessenger') != -1;
if (!isWeixin) {
next()
return
}
// 不需要授权的页面
if (to.name === 'xxx') {
next()
return
}
// 企微环境获取当前用户userId和外部客户externalUserId
let code = to.query.code || '';
if (code) {
// 有code说明是授权过的,重定向地址, 调接口获取当前用户信息
getWxUserInfo(to, from, next, code);
} else {
// 获取授权
Authorize(to);
}
})
export default router
这里遇到一个坑:在企微刷新当前页面获取userId的接口报400029错误,一开始以为是接口的问题,后面发现第一次接口是调成功的,第二次失败了,因为刷新的时候链接还是第一次授权后带code的链接,这个code已经被消费了,所以需要重新授权获取。
改完又发现另一个问题, 获取userId的接口是调通了, 但是返回了external_userId字段, userId为null, 神马情况, 难道调错接口了。后面各种排查发现,原来我用的这个账号同时被其他人添加为外部客户了,userId为null是因为没有扫码关注企业,啊~
2.获取外部联系人的userId(即下externalUserId)
- 企微官方JS-SDK文档: developer.work.weixin.qq.com/document/pa… 获取外部联系人userId需要调用企微官方JS-SDK, 首先需要引入js-sdk文件。
// index.html
<script src="https://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
<script src="https://open.work.weixin.qq.com/wwopen/js/jwxwork-1.0.0.js"></script>
在侧边栏配置的多个tab页面都需要获取外部联系人externalUserId, 为了方便复用封装了下面的externalUserId.js, 在需要用到外部联系人externalUserId的页面引入。获取外部联系人externalUserId需要后台提供两个签名接口,一个用来获取企业签名信息,一个用来获取应用签名信息,接口入参url是不带#号的url, 接口调用顺序需要是先企业后应用。获取完企业签名信息后,需要添加js-sdk企业验证配置wx.config,使用到的js接口列表都需要添加到jsApiList。验证配置完成会执行 wx.ready,然后获取应用签名并验证应用配置信息,验证完成调用wx.invoke('getCurExternalContact', {}, function (res) {})接口, 即可获取外部联系人externalUserId。
// mixins/externalUserId.js
// 签名获取外部用户externalUserId逻辑
import { getSign, getAgentSign } from '@/apis/apis';
export default {
data() {
return {
externalUserId: ''
};
},
created() {
},
mounted() {
// 获取企业签名信息
localStorage.removeItem('externalUserId');
this.getCompanySign();
},
methods: {
//获取企业签名信息
getCompanySign() {
// let url = "获取config或agentConfig配置的参数接口";
//该paramUrl 为你使用微信sdk-js相关接口的页面地址 该地址需要配置到应用后台的可信域名下
let url = window.location.href.split("#")[0];
let params = { url };
getSign(params).then(res => {
this.companyConfigInit(res.data);
}).catch(err => {
console.log(err);
});
},
//企业验证配置
companyConfigInit(data) {
let that = this;
// noncestr: "ww09b472814e7d260f"
// signature: "442fde92aa1a440e5e9636364378186e6463306c"
// timestamp: "1647912587432
let { timestamp, noncestr, signature } = data || {};
let wxConfig = localStorage.getItem('wxConfig') ? JSON.parse(localStorage.getItem('wxConfig')) : {};
let { corpid } = wxConfig;
// eslint-disable-next-line
wx.config({
beta: true, // 必须这么写,否则wx.invoke调用形式的jsapi会有问题
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: corpid, // 必填,企业微信的corpID
timestamp: timestamp, // 必填,生成签名的时间戳
nonceStr: noncestr, // 必填,生成签名的随机串
signature: signature, // 必填,签名,见 附录-JS-SDK使用权限签名算法
jsApiList: ["getContext", "getCurExternalContact", "invoke"] //你要调用的sdk接口必填,需要使用的JS接口列表,凡是要调用的接口都需要传进来
});
// eslint-disable-next-line
wx.ready(function () {
that.appAgentConfig();
});
// eslint-disable-next-line
wx.error(function (res) {
console.log('config失败了', res)
});
},
//获取应用签名信息
appAgentConfig() {
let url = window.location.href.split("#")[0];
let params = { url };
getAgentSign(params).then((res) => {
let { code, data, message } = res || {};
if (code === 200) {
this.appConfigInit(data);
} else {
console.log(message);
}
})
},
//应用验证配置
appConfigInit(data) {
let that = this;
let { timestamp, noncestr, signature } = data || {};
let wxConfig = localStorage.getItem('wxConfig') ? JSON.parse(localStorage.getItem('wxConfig')) : {};
let { corpid, agentid } = wxConfig;
// eslint-disable-next-line
wx.agentConfig({
corpid,
agentid,
timestamp: timestamp,
nonceStr: noncestr,
signature: signature,
jsApiList: ["getContext", "getCurExternalContact", "invoke"],
success: function () {
// eslint-disable-next-line
wx.invoke('getCurExternalContact', {
}, function (res) {
// alert('invoke成功了')
// alert(JSON.stringify(res),'invokeData数据')
console.log('invoke成功了', res)
if (res.err_msg == "getCurExternalContact:ok") {
localStorage.setItem('externalUserId', res.userId);
// this.$store.dispatch("common/setExternalUserId", res.userId);
that.externalUserId = res.userId; //返回当前外部联系人userId
// alert(that.externalUserId);
} else {
//错误处理
}
//查看相关接口是否可以调用
// that.checkJsApi();
});
},
fail: function (res) {
console.log('invoke失败了', res)
// alert('invoke失败了', res)
if (res.errMsg.indexOf("function not exist") > -1) {
alert("版本过低请升级");
}
}
});
},
}
}
这里有个坑:原本我是将mounted里面的内容放在created里面,但是切换客户会出现externalUserId还是上个客户的问题(偶发性)。后来调试发现企业微信侧边栏多个tab页面之间互相切换,pc端会将页面缓存(移动端目前没有发现这个问题),第一次访问A页面会走A页面的生命周期create方法,切换到B页面不会执行A页面的distory生命周期。从B页面切回A页面时,不会执行A页面的生命周期create方法,直接执行生命周期mounted方法,所以就把初始化相关操作放在了mounted里面。
页面中引入mixin,可以通过this.externalUserId调接口获取外部用户的信息。
// xxx.vue
<script>
import externalUserInfoMixin from "@/mixins/externalUserInfo.js";
export default {
mixins: [externalUserInfoMixin]
}
</script>
3.另:企微调试工具
参考:https://blog.csdn.net/Cris_are/article/details/111031601
4.添加外部联系人
按照如图如操作,添加的外部联系人会有@微信绿色标记。
end~ 刚开始做企微,有点懵,写的不好的地方,欢迎评论指出 ~