123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297 |
- 'use strict';
- const Service = require('egg').Service;
- const querystring = require('querystring');
- // 微信接口操作类
- class WechatService extends Service {
- /**
- * [cacheAccessTokenKey 微信公众号access_token key]
- * @return {[type]} [description]
- */
- get cacheAccessTokenKey() {
- return `${process.env.APP_CUSTOME || 'universal'}_wechat_account_access_token`;
- }
- /**
- * [cacheJsapiTicketKey 缓存jsapi ticket key]
- * @return {[type]} [description]
- */
- get cacheJsapiTicketKey() {
- return `${process.env.APP_CUSTOME || 'universal'}_jsapi_ticket`;
- }
- /**
- * [msgText 响应文本消息]
- * @param {String} text [回复内容]
- * @param {Object} data [原消息结构]
- * @return {[type]} [string]
- */
- async msgText(text = '', data = {}) {
- const that = this;
- const result = {
- FromUserName: data.ToUserName,
- ToUserName: data.FromUserName,
- CreateTime: that.app.szjcomo.time(),
- MsgType: 'text',
- Content: text,
- };
- return await that.app.szjcomo.createXml(result);
- }
- /**
- * [msgNews 回复图文消息]
- * @param {Array} list [description]
- * @param {Object} data [description]
- * @return {[type]} [description]
- */
- async msgNews(list = [], data = {}, fields = {}) {
- const that = this;
- const fieldsMap = Object.assign({
- title: 'title',
- description: 'description',
- image_path: 'image_path',
- link_url: 'link_url',
- }, fields);
- const Articles = [];
- list.forEach(item => {
- Articles.push({
- Title: item[fieldsMap.title],
- Description: item[fieldsMap.description] || item[fieldsMap.title],
- PicUrl: item[fieldsMap.image_path] || '',
- Url: item[fieldsMap.link_url] || '',
- });
- });
- const result = {
- FromUserName: data.ToUserName,
- ToUserName: data.FromUserName,
- CreateTime: that.app.szjcomo.time(),
- MsgType: 'news',
- ArticleCount: list.length,
- Articles: { item: Articles },
- };
- return await that.app.szjcomo.createXml(result);
- }
- /**
- * [publicAccessToken 获取众号的access_token]
- * @param {[type]} appid [description]
- * @param {[type]} secret [description]
- * @return {[type]} [description]
- */
- async publicAccessToken(appid, secret) {
- const that = this;
- appid = appid || await that.service.configs.getConfigValue('wechat_account_appid');
- secret = secret || await that.service.configs.getConfigValue('wechat_account_secret');
- let result = await that.service.redis.get(that.cacheAccessTokenKey);
- if (!result) {
- const uri = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${appid}&secret=${secret}`;
- const respone = await that.app.curl(uri, { dataType: 'json' });
- if (respone.data && respone.data.access_token) {
- result = respone.data.access_token;
- await that.service.redis.set(that.cacheAccessTokenKey, result, 1.5 * 60 * 60);
- } else {
- throw new Error(that.app.szjcomo.json_encode(respone.data));
- }
- }
- return result;
- }
- /**
- * [authLogin 网页用户授权登录]
- * @param {[type]} appid [description]
- * @param {[type]} secret [description]
- * @param {String} code [description]
- * @return {[type]} [description]
- */
- async authLogin(appid, secret, code = '') {
- const that = this;
- const uri = `https://api.weixin.qq.com/sns/oauth2/access_token?appid=${appid}&secret=${secret}&code=${code}&grant_type=authorization_code`;
- const respone = await that.app.curl(uri, { dataType: 'json' });
- return respone.data;
- }
- /**
- * [authUserInfo 获取用户信息]
- * @param {[type]} access_token [description]
- * @param {[type]} openid [description]
- * @return {[type]} [description]
- */
- async authUserInfo(data = {}) {
- const that = this;
- const uri = `https://api.weixin.qq.com/sns/userinfo?access_token=${data.access_token}&openid=${data.openid}&lang=zh_CN`;
- const respone = await that.app.curl(uri, { dataType: 'json' });
- return respone.data;
- }
- /**
- * [jsapiTicket 获取微信公众号jsapi_ticket]
- * @author szjcomo
- * @date 2021-05-16
- * @return {[type]} [description]
- */
- async jsapiTicket() {
- const that = this;
- const access_token = await that.publicAccessToken();
- let result = await that.service.redis.get(that.cacheJsapiTicketKey);
- if (!result) {
- const uri = `https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=${access_token}&type=jsapi`;
- const res = await that.app.curl(uri, { method: 'GET', dataType: 'json' });
- if (res.data && res.data.ticket) {
- result = res.data.ticket;
- await that.service.redis.set(that.cacheJsapiTicketKey, result, 1.5 * 60 * 60);
- } else {
- throw new Error(that.app.szjcomo.json_encode(res.data));
- }
- }
- return result;
- }
- /**
- * [jsapiConfig 获取微信公众号jsapi_config]
- * @author szjcomo
- * @date 2021-05-16
- * @return {[type]} [description]
- */
- async jsapiConfig(urlData = {}) {
- const that = this;
- const configs = await that.service.configs.getConfigMoreValue([ 'wechat_account_appid', 'wechat_account_jsapi_uri', 'wechat_account_jsapi_list', 'wechat_account_jsapi_debug' ]);
- const jsApiList = configs.wechat_account_jsapi_list.split(',');
- const data = {
- nonceStr: that.app.szjcomo.str_rand(16),
- timestamp: that.app.szjcomo.time(),
- url: urlData.url || configs.wechat_account_jsapi_uri,
- debug: !!Number(configs.wechat_account_jsapi_debug),
- jsApiList,
- };
- const jsapi_ticket = await that.jsapiTicket();
- const configSign = `jsapi_ticket=${jsapi_ticket}&noncestr=${data.nonceStr}×tamp=${data.timestamp}&url=${data.url}`;
- data.signature = that.app.szjcomo.sha1(configSign);
- data.appId = configs.wechat_account_appid;
- return data;
- }
- /**
- * [orderPay 订单下单支付]
- * @param {Object} data [description]
- * @return {[type]} [description]
- */
- async orderPay(data = {}) {
- const that = this;
- const config = await that.service.configs.getConfigMoreValue([ 'wechat_pay_token', 'wechat_pay_domain', 'wechat_pay_callback' ]);
- const defaults = {
- identity: config.wechat_pay_token, total_fee: 1, notify_url: config.wechat_pay_callback,
- detail: '', trade_type: 'NATIVE',
- };
- const bodyData = Object.assign(defaults, data);
- // 2022/12/09 微信最终下单价格向上取整
- bodyData.total_fee = Math.ceil(bodyData.total_fee);
- const respone = await that.app.curl(`${config.wechat_pay_domain}/pays/v1/order`, {
- method: 'POST', data: bodyData, dataType: 'json', contentType: 'json',
- });
- return respone.data;
- }
- /**
- * [wechatAccountJsApiPay 微信公众号发起js微信支付功能]
- * @param {Object} data [description]
- * @return {[type]} [description]
- */
- async wechatAccountJsApiPay(data = {}) {
- const that = this;
- const respone = await that.orderPay(data);
- if (respone.error !== false) throw new Error(respone.message);
- if (respone.result.result_code != 'SUCCESS') throw new Error(respone.result.err_code_des);
- const options = {
- timeStamp: `${that.app.szjcomo.time()}`,
- nonceStr: respone.result.nonce_str,
- package: `prepay_id=${respone.result.prepay_id}`,
- signType: 'MD5',
- appId: respone.result.appid || respone.result.sub_appid,
- };
- const tmpOptions = {
- timestamp: options.timeStamp,
- nonceStr: respone.result.nonce_str,
- package: `prepay_id=${respone.result.prepay_id}`,
- signType: 'MD5',
- appId: respone.result.appid || respone.result.sub_appid,
- };
- const wxpay_key = await that.service.configs.getConfigValue('wechat_pay_key');
- const paySign = await that.jsPaySign(options, wxpay_key);
- tmpOptions.paySign = paySign;
- return tmpOptions;
- }
- /**
- * [jsSign js对象签名算法]
- * @author szjcomo
- * @date 2021-05-16
- * @param {Object} data [description]
- * @return {[type]} [description]
- */
- async jsPaySign(data = {}, key = '') {
- const that = this;
- const keysArr = Object.keys(data)
- .sort();
- const sortObj = {};
- for (const i in keysArr) {
- sortObj[keysArr[i]] = data[keysArr[i]];
- }
- const str = querystring.unescape(querystring.stringify(sortObj));
- return that.app.szjcomo.MD5(`${str}&key=${key}`)
- .toUpperCase();
- }
- /**
- * openid转换接口
- */
- // async changeOpenid(openidList, token) {
- // const that = this;
- // let access_token = '';
- // if (token) {
- // access_token = token;
- // } else {
- // const appid = 'wx34b388c12eb961c7';
- // const secret = '0b325cbee8ca9a660aa66b554768c18d';
- // const uri = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${appid}&secret=${secret}`;
- // const respone = await that.app.curl(uri, { dataType: 'json' });
- // if (respone.data && respone.data.access_token) {
- // access_token = respone.data.access_token;
- // } else {
- // throw new Error(that.app.szjcomo.json_encode(respone.data));
- // }
- // }
- // console.log('==new token ==:' + access_token);
- // if (access_token) {
- // const uri = `https://api.weixin.qq.com/cgi-bin/changeopenid?access_token=${access_token}`;
- // // 需要转换的openid,即第1步中拉取的原帐号用户列表,这些必须是旧账号目前关注的才行,否则会出错;一次最多100个,不能多。
- // const res = await that.app.curl(uri, {
- // method: 'POST', dataType: 'json', contentType: 'json',
- // data: {
- // from_appid: 'wxc3b3607411a67f7b',
- // openid_list: openidList,
- // },
- // });
- // if (res.data.result_list) {
- // for (const re of res.data.result_list) {
- // const updateBean = await that.app.comoBean.instance({
- // new_openid: re.new_openid,
- // ori_openid: re.ori_openid,
- // update_time: that.app.szjcomo.date('Y-m-d H:i:s'),
- // }, { where: { openid: re.ori_openid } });
- // // 2022/9/27 用户新openid更新
- // await that.app.comoBean.update(updateBean, that.app.model.Users, '用户新openid更新失败,请稍候重试');
- // continue;
- // }
- // } else {
- // console.log('res.data.errmsg === :');
- // console.log(res.data.errmsg);
- // // throw new Error(that.app.szjcomo.json_encode(res.data));
- // }
- // return res.data.result_list;
- // }
- // return 'access_token null';
- // }
- }
- module.exports = WechatService;
|