wx_work.js 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. 'use strict';
  2. // 企业微信一些方法
  3. const axios = require('axios');
  4. class wxWork {
  5. constructor(ctx) {
  6. this.ctx = ctx;
  7. }
  8. async setSuiteTicket(suite_ticket) {
  9. return await this.ctx.app.redis.set('suite_ticket', suite_ticket, 'EX', 1800);// 最多半小时有效期,企业微信会自动请求刷新获取
  10. }
  11. async getSuiteTicket() {
  12. try {
  13. const suite_ticket = this.ctx.app.redis.get('suite_ticket');
  14. if (!suite_ticket) {
  15. throw '还没有设置过';
  16. }
  17. return suite_ticket;
  18. } catch (error) {
  19. console.log(error);
  20. return false;
  21. }
  22. }
  23. async getSuiteAccessToken() {
  24. const suite_access_token = await this.ctx.app.redis.get('suite_access_token');
  25. if (!suite_access_token) {
  26. const suite_ticket = await this.getSuiteTicket();
  27. const post_data = {
  28. suite_id: this.ctx.app.config.qywx.suiteID,
  29. suite_secret: this.ctx.app.config.qywx.suiteSecret,
  30. suite_ticket,
  31. };
  32. // const response = await this.ctx.helper.sendRequest('https://qyapi.work.weixin.qq.com/cgi-bin/service/get_suite_token', post_data, 'POST');
  33. // console.log(response);
  34. const { data } = await axios.post('https://qyapi.weixin.qq.com/cgi-bin/service/get_suite_token', post_data);
  35. const { suite_access_token, expires_in } = data;
  36. if (suite_access_token) {
  37. await this.ctx.app.redis.set('suite_access_token', suite_access_token, 'EX', expires_in);// 最多两个小时有效期
  38. return suite_access_token;
  39. }
  40. }
  41. return suite_access_token;
  42. }
  43. async savePermanentCode(temporary_code) {
  44. return await this.ctx.app.redis.set('temporary_code', temporary_code, 'EX', 600);// 最多10分钟有效期,企业信息要入库
  45. }
  46. // 设置永久授权码(代开发授权凭证)
  47. async setPermanentCode() {
  48. const temporary_code = await this.ctx.app.redis.get('temporary_code');
  49. if (!temporary_code) {
  50. console.log('不存在授权码');
  51. return false;
  52. }
  53. const suite_access_token = await this.getSuiteAccessToken();
  54. const { data } = await axios.post(`https://qyapi.weixin.qq.com/cgi-bin/service/get_permanent_code?suite_access_token=${suite_access_token}`, {
  55. auth_code: temporary_code,
  56. });
  57. const {
  58. permanent_code,
  59. auth_corp_info,
  60. auth_user_info,
  61. auth_info,
  62. } = data;
  63. if (permanent_code) {
  64. const agentid = auth_info.agent[0].agentid;
  65. const result = await this.ctx.service.wxWork.insertCorp(permanent_code, agentid, auth_corp_info, auth_user_info);
  66. console.log(result, permanent_code, agentid, auth_corp_info, auth_user_info);
  67. console.log(auth_corp_info.corp_name + ' 授权企业成功');
  68. await this.ctx.app.redis.del('temporary_code');
  69. return result;
  70. }
  71. console.error('获取永久授权码失败', data);
  72. return false;
  73. }
  74. // 读取企业的通讯录 access_token
  75. async getCorpTxlAccessToken(corpID) {
  76. try {
  77. let token = await this.ctx.app.redis.get(`${corpID}_txl_access_token`);
  78. if (!token) {
  79. const corpInfo = await this.ctx.service.wxWork.getDataByCondition({ corpid: corpID });
  80. if (!corpInfo) {
  81. throw '未绑定该企业';
  82. }
  83. const { data } = await axios.get(`https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=${corpID}&corpsecret=8SZKdgpUICzj9ImEjrqHHVCD6NxEpgWqkoEb0KzzG40`);
  84. const { access_token, expires_in } = data;
  85. if (!access_token) {
  86. throw '获取 corp_access_token 失败';
  87. }
  88. await this.ctx.app.redis.set(`${corpID}_txl_access_token`, access_token, 'EX', expires_in);
  89. token = access_token;
  90. }
  91. return token;
  92. } catch (e) {
  93. console.log(e);
  94. return null;
  95. }
  96. }
  97. // 读取企业的 access_token
  98. async getCorpAccessToken(corpID) {
  99. try {
  100. let token = await this.ctx.app.redis.get(`${corpID}_access_token`);
  101. if (!token) {
  102. const corpInfo = await this.ctx.service.wxWork.getDataByCondition({ corpid: corpID });
  103. if (!corpInfo) {
  104. throw '未绑定该企业';
  105. }
  106. const { data } = await axios.get(`https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=${corpID}&corpsecret=${corpInfo.permanent_code}`);
  107. const { access_token, expires_in } = data;
  108. if (!access_token) {
  109. throw '获取 corp_access_token 失败';
  110. }
  111. await this.ctx.app.redis.set(`${corpID}_access_token`, access_token, 'EX', expires_in);
  112. token = access_token;
  113. }
  114. return token;
  115. } catch (e) {
  116. console.log(e);
  117. return null;
  118. }
  119. }
  120. // 读取企业用户信息, 只获取一次
  121. async getCorpUser(token, code) {
  122. try {
  123. const { data: user_data } = await axios.get(`https://qyapi.weixin.qq.com/cgi-bin/auth/getuserinfo?access_token=${token}&code=${code}`);
  124. if (user_data.errcode !== 0) {
  125. throw '获取企业微信用户信息失败';
  126. }
  127. const user_ticket = user_data.user_ticket;
  128. const { data: user_detail_data } = await axios.post(`https://qyapi.weixin.qq.com/cgi-bin/auth/getuserdetail?access_token=${token}`, {
  129. user_ticket,
  130. });
  131. if (user_detail_data.errcode !== 0) {
  132. throw '获取企业微信用户详细信息失败';
  133. }
  134. const user_info = {
  135. userid: user_data.userid,
  136. avatar: user_detail_data.avatar !== undefined ? user_detail_data.avatar : null,
  137. gender: user_detail_data.gender !== undefined ? user_detail_data.gender : null,
  138. };
  139. return user_info;
  140. } catch (e) {
  141. console.log(e);
  142. return null;
  143. }
  144. }
  145. // 读取企业用户信息
  146. async getCorpUserCommonData(token, userid, corpID) {
  147. try {
  148. const { data: user_common_data } = await axios.get(`https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token=${token}&userid=${userid}`);
  149. if (user_common_data.errcode !== 0) {
  150. throw '获取企业微信用户详细信息失败';
  151. }
  152. const corpInfo = await this.ctx.service.wxWork.getDataByCondition({ corpid: corpID });
  153. const user_info = {
  154. userid: user_common_data.userid,
  155. name: user_common_data.name,
  156. department: user_common_data.department,
  157. position: user_common_data.position,
  158. company: corpInfo.corp_name,
  159. };
  160. return user_info;
  161. } catch (e) {
  162. console.log(e);
  163. return null;
  164. }
  165. }
  166. // 获取通讯录
  167. async getUserList(corpid) {
  168. const token = await this.getCorpTxlAccessToken(corpid);
  169. const { data: user_data } = await axios.post(`https://qyapi.weixin.qq.com/cgi-bin/user/list_id?access_token=${token}`);
  170. console.log(user_data, user_data.dept_user);
  171. return user_data.dept_user;
  172. }
  173. // 发送模板卡片信息
  174. async sendTemplateCard(userids, corpid, title, desc, content, url = '', btntxt = null) {
  175. try {
  176. const corpInfo = await this.ctx.service.wxWork.getDataByCondition({ corpid });
  177. if (!corpInfo) {
  178. throw '该企业不存在';
  179. }
  180. const token = await this.getCorpAccessToken(corpid);
  181. const templateCard = {
  182. card_type: 'text_notice',
  183. main_title: {
  184. title,
  185. desc,
  186. },
  187. horizontal_content_list: content,
  188. };
  189. if (btntxt) {
  190. templateCard.jump_list = {
  191. type: 1,
  192. title: btntxt,
  193. url,
  194. };
  195. }
  196. templateCard.card_action = {
  197. type: 1,
  198. url,
  199. };
  200. const data = await axios.post(`https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=${token}`, {
  201. touser: userids.join('|'),
  202. msgtype: 'template_card',
  203. agentid: corpInfo.agentid,
  204. template_card: templateCard,
  205. });
  206. console.log(data);
  207. return data;
  208. } catch (e) {
  209. console.log(e);
  210. return null;
  211. }
  212. }
  213. // 发送文本卡片信息
  214. async sendTextCard(userids, corpid, title, content, url = '', btntxt = null) {
  215. try {
  216. const corpInfo = await this.ctx.service.wxWork.getDataByCondition({ corpid });
  217. if (!corpInfo) {
  218. throw '该企业不存在';
  219. }
  220. const token = await this.getCorpAccessToken(corpid);
  221. const textCard = {
  222. title,
  223. description: content,
  224. };
  225. if (url) textCard.url = url ? url : '';
  226. if (btntxt) textCard.btntxt = btntxt;
  227. const data = await axios.post(`https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=${token}`, {
  228. touser: userids.join('|'),
  229. msgtype: 'textcard',
  230. agentid: corpInfo.agentid,
  231. textcard: textCard,
  232. });
  233. console.log(data);
  234. return data;
  235. } catch (e) {
  236. console.log(e);
  237. return null;
  238. }
  239. }
  240. }
  241. module.exports = wxWork;