|
@@ -11,9 +11,12 @@
|
|
|
const moment = require('moment');
|
|
|
// const Controller = require('egg').Controller;
|
|
|
const crypto = require('crypto');
|
|
|
+const qywxCrypto = require('@wecom/crypto');
|
|
|
+const getRawBody = require('raw-body');
|
|
|
const maintainConst = require('../const/maintain');
|
|
|
const wxConst = require('../const/wechat_template.js');
|
|
|
const smsTypeConst = require('../const/sms_type');
|
|
|
+const wxWork = require('../lib/wx_work');
|
|
|
|
|
|
module.exports = app => {
|
|
|
class WechatController extends app.BaseController {
|
|
@@ -254,6 +257,294 @@ module.exports = app => {
|
|
|
ctx.body = error;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ // 企业微信功能
|
|
|
+ // 回调方法
|
|
|
+ async command(ctx) {
|
|
|
+ try {
|
|
|
+ const msg_signature = ctx.query.msg_signature;
|
|
|
+ const timestamp = ctx.query.timestamp;
|
|
|
+ const nonce = ctx.query.nonce;
|
|
|
+ const echostr = ctx.query.echostr;
|
|
|
+ const signature = qywxCrypto.getSignature(ctx.app.config.qywx.token, timestamp, nonce, echostr);
|
|
|
+ if (signature === msg_signature) {
|
|
|
+ const aeskey = ctx.app.config.qywx.encodingAESKey;
|
|
|
+ const { message } = qywxCrypto.decrypt(aeskey, echostr);
|
|
|
+ ctx.body = message;
|
|
|
+ // res.send(message);
|
|
|
+ } else {
|
|
|
+ throw '验证失败';
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ console.log(e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 获取suite_ticket方法
|
|
|
+ async postCommand(ctx) {
|
|
|
+ try {
|
|
|
+ // ctx.req才能获取到rawbody
|
|
|
+ const wholeXML = await getRawBody(ctx.req, {
|
|
|
+ length: ctx.headers['content-length'],
|
|
|
+ limit: '1mb',
|
|
|
+ encoding: 'utf-8',
|
|
|
+ });
|
|
|
+ const formatJson = await ctx.helper.parseXML(wholeXML);
|
|
|
+ const messageXML = qywxCrypto.decrypt(ctx.app.config.qywx.encodingAESKey, formatJson.Encrypt);
|
|
|
+ const callbackDataBody = await ctx.helper.parseXML(messageXML.message);
|
|
|
+ console.log('CallbackData', callbackDataBody);
|
|
|
+ const qywx = new wxWork(ctx);
|
|
|
+ switch (callbackDataBody.InfoType) {
|
|
|
+ case 'suite_ticket':
|
|
|
+ // 刷新
|
|
|
+ console.log('SuiteTicket', callbackDataBody.SuiteTicket);
|
|
|
+ await qywx.setSuiteTicket(callbackDataBody.SuiteTicket);
|
|
|
+ // await app.redis.set('suite_ticket', callbackDataBody.SuiteTicket, 'EX', 1500);
|
|
|
+ break;
|
|
|
+ case 'reset_permanent_code':
|
|
|
+ case 'create_auth':
|
|
|
+ console.log('AuthCode', callbackDataBody.AuthCode);
|
|
|
+ await qywx.savePermanentCode(callbackDataBody.AuthCode);
|
|
|
+ qywx.setPermanentCode();// 不用马上执行,有执行就行
|
|
|
+ break;
|
|
|
+ case 'cancel_auth':
|
|
|
+ // 企业管理员删除应用
|
|
|
+ await ctx.service.wxWork.delCorp(callbackDataBody.AuthCorpId);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ // 很重要,一定要返回 success 字符串
|
|
|
+ ctx.body = 'success';
|
|
|
+ } catch (e) {
|
|
|
+ console.log(e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ async oauthWxWorkTxt(ctx) {
|
|
|
+ ctx.body = 'CZwGPbI7BRGOBUX1';
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 企业微信登录验证
|
|
|
+ *
|
|
|
+ * @param {Object} ctx - egg全局页面
|
|
|
+ * @return {void}
|
|
|
+ */
|
|
|
+ async workOauth(ctx) {
|
|
|
+ const corpid = ctx.params.corpid;
|
|
|
+ const redirect_uri = encodeURIComponent(ctx.query.redirect_uri);
|
|
|
+ const corpInfo = await ctx.service.wxWork.getDataByCondition({ corpid });
|
|
|
+ const url = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${corpid}&redirect_uri=${redirect_uri}&response_type=code&scope=snsapi_privateinfo&state=STATE&agentid=${corpInfo.agentid}#wechat_redirect`;
|
|
|
+ ctx.redirect(url);
|
|
|
+ }
|
|
|
+
|
|
|
+ async workBind(ctx) {
|
|
|
+ try {
|
|
|
+ const qywx = new wxWork(ctx);
|
|
|
+ const token = await qywx.getCorpAccessToken(ctx.params.corpid);
|
|
|
+ const user = await qywx.getCorpUser(token, ctx.query.code);
|
|
|
+ if (!user) {
|
|
|
+ throw '获取企业用户信息失败';
|
|
|
+ }
|
|
|
+ const errorMessage = ctx.session.loginError;
|
|
|
+ // 显示完删除
|
|
|
+ ctx.session.loginError = null;
|
|
|
+ // 获取系统维护信息
|
|
|
+ const maintainData = await ctx.service.maintain.getDataById(1);
|
|
|
+ const renderData = {
|
|
|
+ maintainData,
|
|
|
+ maintainConst,
|
|
|
+ errorMessage,
|
|
|
+ user,
|
|
|
+ corpid: ctx.params.corpid,
|
|
|
+ };
|
|
|
+ await ctx.render('wechat/work_bind.ejs', renderData);
|
|
|
+ } catch (error) {
|
|
|
+ console.log(error);
|
|
|
+ const renderData = {
|
|
|
+ status: 1,
|
|
|
+ msg: error,
|
|
|
+ };
|
|
|
+ await ctx.render('wechat/tips.ejs', renderData);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ async workBindwx(ctx) {
|
|
|
+ const corpid = ctx.request.body.corpid ? ctx.request.body.corpid : null;
|
|
|
+ try {
|
|
|
+ const result = await ctx.service.projectAccount.accountCheck(ctx.request.body);
|
|
|
+
|
|
|
+ if (!result) {
|
|
|
+ throw '用户名或密码错误';
|
|
|
+ }
|
|
|
+
|
|
|
+ if (result === 2) {
|
|
|
+ throw '该账号已被停用,请联系销售人员';
|
|
|
+ }
|
|
|
+ const accountData = result;
|
|
|
+ const qywx_userid = ctx.request.body.userid;
|
|
|
+ if (!qywx_userid || !corpid) {
|
|
|
+ throw '参数有误';
|
|
|
+ }
|
|
|
+ if (accountData.qywx_userid || qywx_userid === accountData.qywx_userid) {
|
|
|
+ throw '该账号已经绑定过企业微信';
|
|
|
+ }
|
|
|
+ const wxAccountData = await ctx.service.projectAccount.getDataByCondition({ project_id: accountData.project_id, qywx_userid });
|
|
|
+ if (wxAccountData) {
|
|
|
+ throw '该企业微信号已绑定过本项目其它账号';
|
|
|
+ }
|
|
|
+ const qywx = new wxWork(ctx);
|
|
|
+ const token = await qywx.getCorpAccessToken(corpid);
|
|
|
+ const user = await qywx.getCorpUserCommonData(token, qywx_userid, corpid);
|
|
|
+ if (!user) {
|
|
|
+ throw '获取企业用户信息失败';
|
|
|
+ }
|
|
|
+ user.avatar = ctx.request.body.avatar !== undefined ? ctx.request.body.avatar : null;
|
|
|
+ user.gender = ctx.request.body.gender !== undefined ? ctx.request.body.gender : null;
|
|
|
+
|
|
|
+ const result2 = await ctx.service.projectAccount.bindWx4Work(accountData.id, corpid, qywx_userid, user);
|
|
|
+ if (!result2) {
|
|
|
+ throw '绑定失败';
|
|
|
+ }
|
|
|
+ const projectData = await ctx.service.project.getDataById(accountData.project_id);
|
|
|
+ const desc = '您好,纵横云计量与企业微信绑定成功。';
|
|
|
+ const content = [
|
|
|
+ {
|
|
|
+ keyname: '项目编号',
|
|
|
+ value: projectData.code,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ keyname: '账号',
|
|
|
+ value: accountData.account,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ keyname: '绑定时间',
|
|
|
+ value: moment(new Date()).format('YYYY-MM-DD'),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ keyname: '备注',
|
|
|
+ value: '感谢您的使用。',
|
|
|
+ },
|
|
|
+ ];
|
|
|
+ const url = ctx.protocol + '://' + ctx.host + `/wx/work/${corpid}/project`;
|
|
|
+ await qywx.sendTemplateCard([qywx_userid], corpid, '账号绑定成功通知', desc, content, url, '登录项目');
|
|
|
+ const renderData = {
|
|
|
+ status: 0,
|
|
|
+ msg: '绑定成功',
|
|
|
+ };
|
|
|
+ await ctx.render('wechat/tips.ejs', renderData);
|
|
|
+ } catch (error) {
|
|
|
+ this.log(error);
|
|
|
+ ctx.session.loginError = error;
|
|
|
+ const returnUrl = corpid ? `/wx/work/${corpid}/bind` : '/';
|
|
|
+ ctx.redirect(returnUrl);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置用户企业微信登录项目,跳转到对应wap页面
|
|
|
+ async url2wap4work(ctx) {
|
|
|
+ try {
|
|
|
+ if (!ctx.query.project || !ctx.query.url) {
|
|
|
+ throw '参数有误';
|
|
|
+ }
|
|
|
+ const code = ctx.query.project;
|
|
|
+ // 查找项目数据
|
|
|
+ const projectData = await ctx.service.project.getProjectByCode(code.toString().trim());
|
|
|
+ if (projectData === null) {
|
|
|
+ throw '不存在项目数据';
|
|
|
+ }
|
|
|
+ const qywx = new wxWork(ctx);
|
|
|
+ const token = await qywx.getCorpAccessToken(ctx.params.corpid);
|
|
|
+ const user = await qywx.getCorpUser(token, ctx.query.code);
|
|
|
+ if (!user) {
|
|
|
+ throw '获取企业用户信息失败';
|
|
|
+ }
|
|
|
+ const pa = await ctx.service.projectAccount.getDataByCondition({ project_id: projectData.id, qywx_userid: user.userid });
|
|
|
+ if (!pa) {
|
|
|
+ throw '该企业微信号未绑定此项目';
|
|
|
+ }
|
|
|
+ if (pa.enable !== 1) {
|
|
|
+ throw '该账号已被停用,请联系销售人员';
|
|
|
+ }
|
|
|
+ // 设置项目和用户session记录
|
|
|
+ const result = await ctx.service.projectAccount.accountLogin({ project: projectData, accountData: pa }, 3);
|
|
|
+ if (!result) {
|
|
|
+ throw '登录出错';
|
|
|
+ }
|
|
|
+ ctx.redirect(ctx.query.url);
|
|
|
+ } catch (error) {
|
|
|
+ const renderData = {
|
|
|
+ status: 1,
|
|
|
+ msg: error,
|
|
|
+ };
|
|
|
+ await ctx.render('wechat/tips.ejs', renderData);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ async workProject(ctx) {
|
|
|
+ try {
|
|
|
+ // const user = await app.wechat.oauth.getUser(ctx.session.wechatToken.openid);
|
|
|
+ const qywx = new wxWork(ctx);
|
|
|
+ const token = await qywx.getCorpAccessToken(ctx.params.corpid);
|
|
|
+ const user = await qywx.getCorpUser(token, ctx.query.code);
|
|
|
+ if (!user) {
|
|
|
+ throw '获取企业用户信息失败';
|
|
|
+ }
|
|
|
+ const paList = await ctx.service.projectAccount.getAllDataByCondition({ where: { qywx_userid: user.userid } });
|
|
|
+ const pidList = ctx.app._.uniq(ctx.app._.map(paList, 'project_id'));
|
|
|
+ const pList = [];
|
|
|
+ const isWap = ctx.helper.isMobile(ctx.request.header['user-agent']) ? '/wap' : '';
|
|
|
+ const redirect_url = ctx.protocol + '://' + ctx.host + isWap + '/dashboard';
|
|
|
+ for (const p of pidList) {
|
|
|
+ const pro = await ctx.service.project.getDataById(p);
|
|
|
+ pList.push(pro);
|
|
|
+ }
|
|
|
+ if (pList.length === 0) {
|
|
|
+ throw '该企业微信号未绑定任何项目';
|
|
|
+ }
|
|
|
+ // 获取系统维护信息
|
|
|
+ const maintainData = await ctx.service.maintain.getDataById(1);
|
|
|
+ const renderData = {
|
|
|
+ maintainData,
|
|
|
+ maintainConst,
|
|
|
+ // user,
|
|
|
+ pList,
|
|
|
+ redirect_url,
|
|
|
+ corpid: ctx.params.corpid,
|
|
|
+ };
|
|
|
+ // ctx.body = renderData;
|
|
|
+ await ctx.render('wechat/work_project.ejs', renderData);
|
|
|
+ } catch (e) {
|
|
|
+ const renderData = {
|
|
|
+ status: 1,
|
|
|
+ msg: e,
|
|
|
+ };
|
|
|
+ await ctx.render('wechat/tips.ejs', renderData);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ async workTest(ctx) {
|
|
|
+ try {
|
|
|
+ // const user = await app.wechat.oauth.getUser(ctx.session.wechatToken.openid);
|
|
|
+ const qywx = new wxWork(ctx);
|
|
|
+ const result = await qywx.getUserList(ctx.params.corpid);
|
|
|
+ ctx.body = result;
|
|
|
+ } catch (e) {
|
|
|
+ const renderData = {
|
|
|
+ status: 1,
|
|
|
+ msg: e,
|
|
|
+ };
|
|
|
+ await ctx.render('wechat/tips.ejs', renderData);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ async tips(ctx) {
|
|
|
+ const renderData = {
|
|
|
+ status: 0,
|
|
|
+ msg: ctx.query.msg,
|
|
|
+ };
|
|
|
+ await ctx.render('wechat/tips.ejs', renderData);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
return WechatController;
|