'use strict'; /** * * * @author Ellisran * @date 2020/7/2 * @version */ 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'); const { parseStringXml } = require('../lib/common'); module.exports = app => { class WechatController extends app.BaseController { /** * 接入微信 * * @param {Object} ctx - egg全局页面 * @return {void} */ async index(ctx) { try { const signature = ctx.query.signature; const timestamp = ctx.query.timestamp; const nonce = ctx.query.nonce; const echostr = ctx.query.echostr; const array = [ctx.app.config.wechatAll.token, timestamp, nonce]; array.sort(); const tempStr = array.join(''); const hashCode = crypto.createHash('sha1'); const resultCode = hashCode.update(tempStr, 'utf8').digest('hex'); if (resultCode === signature) { ctx.body = echostr; // res.send(echostr); } else { throw '验证失败'; } } catch (e) { console.log(e); } } /** * 微信自动回复 * * @param {Object} ctx - egg全局页面 * @return {void} */ async replyMessage(ctx) { const xml = ctx.request.body; try { const { createTime, msgType, toUserName, toFromName, event, msgContent, } = await parseStringXml(xml); let body = ''; if (msgType === 'text') { const reply_msg = '如有问题需要咨询,请电话联系0756-3850888;或添加企业QQ:800003850。'; body = ` ${createTime} `; } ctx.body = body; } catch (e) { console.log(e); } } /** * 微信登录验证 * * @param {Object} ctx - egg全局页面 * @return {void} */ async oauth(ctx) { const redirect_uri = ctx.query.redirect_uri; const url = await app.wechat.oauth.getAuthorizeURL(redirect_uri, '', 'snsapi_userinfo'); ctx.redirect(url); } /** * 绑定页面 * * @param {Object} ctx - egg全局页面 * @return {void} */ async bind(ctx) { try { const user = await app.wechat.oauth.getUser(ctx.session.wechatToken.openid); const errorMessage = ctx.session.loginError; // 显示完删除 ctx.session.loginError = null; // 获取系统维护信息 const maintainData = await ctx.service.maintain.getDataById(1); const renderData = { maintainData, maintainConst, errorMessage, user, }; await ctx.render('wechat/bind.ejs', renderData); } catch (e) { const renderData = { status: 1, msg: e, }; await ctx.render('wechat/tips.ejs', renderData); } } async bindwx(ctx) { try { const result = await ctx.service.projectAccount.accountCheck(ctx.request.body); if (!result) { throw '用户名或密码错误'; } if (result === 2) { // 查找项目数据 const projectData = await this.ctx.service.project.getProjectByCode(ctx.request.body.project.toString().trim()); // 判断是否有设置停用提示,有则展示 const msg = await ctx.service.projectStopmsg.getMsg(projectData.id); throw msg; } const accountData = result; if (accountData.wx_openid || ctx.session.wechatToken.openid === accountData.wx_openid) { throw '该账号已经绑定过微信'; } const wxAccountData = await ctx.service.projectAccount.getDataByCondition({ project_id: accountData.project_id, wx_openid: ctx.session.wechatToken.openid }); if (wxAccountData) { throw '该微信号已绑定过本项目账号'; } const user = await app.wechat.api.getUser(ctx.session.wechatToken.openid); if (user.subscribe === 0) { throw '先关注公众号才能绑定项目'; } const result2 = await ctx.service.projectAccount.bindWx(accountData.id, ctx.session.wechatToken.openid, user.nickname, user.unionid); if (!result2) { throw '绑定失败'; } const projectData = await ctx.service.project.getDataById(accountData.project_id); // 绑定成功通知 const templateId = 'JGJeWU2FT4syWKUE5haEf3iiqaRJ1XrsxY1PKixqLpw'; const url = ''; const msgData = { first: { value: '您好,纵横云计量与微信绑定成功。', }, keyword1: { value: projectData.code, }, keyword2: { value: accountData.account, }, keyword3: { value: moment(new Date()).format('YYYY-MM-DD'), }, remark: { value: '感谢您的使用。', }, }; await app.wechat.api.sendTemplate(ctx.session.wechatToken.openid, templateId, url, '', msgData); const renderData = { status: 0, msg: '绑定成功', }; await ctx.render('wechat/tips.ejs', renderData); } catch (error) { this.log(error); ctx.session.loginError = error; ctx.redirect('/wx/bind'); } } // 设置用户微信登录项目,跳转到对应wap页面 async url2wap(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 pa = await ctx.service.projectAccount.getDataByCondition({ project_id: projectData.id, wx_openid: ctx.session.wechatToken.openid }); if (!pa) { throw '该微信号未绑定此项目'; } if (pa.enable !== 1) { // 判断是否有设置停用提示,有则展示 const msg = await ctx.service.projectStopmsg.getMsg(projectData.id); throw msg; } // 设置项目和用户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 project(ctx) { try { // const user = await app.wechat.oauth.getUser(ctx.session.wechatToken.openid); const openid = ctx.session.wechatToken.openid; // const openid = 'fasdfklahsdklf'; const paList = await ctx.service.projectAccount.getAllDataByCondition({ where: { wx_openid: openid } }); const pidList = ctx.app._.uniq(ctx.app._.map(paList, 'project_id')); const pList = []; const redirect_url = ctx.protocol + '://' + ctx.host + '/wap/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, }; // ctx.body = renderData; await ctx.render('wechat/project.ejs', renderData); } catch (e) { const renderData = { status: 1, msg: e, }; await ctx.render('wechat/tips.ejs', renderData); } } async oauthTxt(ctx) { ctx.body = 't3MkWAMqplVxPjmr'; } async testwx(ctx) { try { const sck = 'https://scn.ink/'; // 微信模板通知 const tender = { data: { name: 'XXX标段', }, info: { deal_info: { buildName: 'XX项目', }, }, }; ctx.tender = tender; const stageInfo = await ctx.service.stage.getDataById(1704); const shenpiUrl = await ctx.helper.urlToShort(ctx.protocol + '://' + ctx.host + '/wap/tender/1998/stage/' + stageInfo.order); const wechatData = { wap_url: sck + shenpiUrl, qi: stageInfo.order, status: wxConst.status.success, tips: wxConst.tips.success, code: 'P1002', }; // ctx.body = { tender, wechatData }; await ctx.helper.sendWechat(133, smsTypeConst.const.JL, smsTypeConst.judge.result.toString(), wxConst.template.stage, wechatData); ctx.body = 'success'; } catch (error) { console.log(error); 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) { // 查找项目数据 const projectData = await this.ctx.service.project.getProjectByCode(ctx.request.body.project.toString().trim()); // 判断是否有设置停用提示,有则展示 const msg = await ctx.service.projectStopmsg.getMsg(projectData.id); throw msg; } 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) { // 判断是否有设置停用提示,有则展示 const msg = await ctx.service.projectStopmsg.getMsg(projectData.id); throw msg; } // 设置项目和用户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; };