react-app-shell
Version:
react打包脚本和example, 这里的版本请忽略
393 lines (359 loc) • 12 kB
JavaScript
import queryString from 'query-string';
import wx from 'weixin-js-sdk';
import { wechatService } from '../service';
// import message from './message';
import { appConfig, shareConfig } from '../config';
const noop = () => {};
// let debugStatus = process.env.NODE_ENV === "production" ? false : true;
const debugStatus = false;
/**
* 微信验证状态
* @type {{ready: boolean, error: string}}
*/
export const wechatStatus = {
/**
* config信息验证是否完成
*/
ready: false,
/**
* config信息验证错误信息
*/
error: ''
};
/**
* 根据微信签名, 通过config接口注入权限验证配置
* 所有需要使用JS-SDK的页面必须先注入配置信息,否则将无法调用
*
* staging环境对应的微信公众号: 魔力好家长: appid=wxd7ec12bd329457fb
* mobile 生产环境对应的微信公众号: 魔力耳朵: appid=wxa86689ab270599d4
* @param wechatSign 签名数据
* @param showShare 显示微信分享, 默认为真
* @param shareOptions 分享选项
*/
export const wechatConfig = (wechatSign = {}, showShare = true, shareOptions = {}) => {
const config = {
debug: debugStatus, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: wechatSign.appId, // 必填,公众号的唯一标识
timestamp: wechatSign.timestamp, // 必填,生成签名的时间戳
nonceStr: wechatSign.nonceStr, // 必填,生成签名的随机串
signature: wechatSign.signature, // 必填,签名
jsApiList: [
'chooseWXPay',
'chooseImage',
'onMenuShareTimeline',
'onMenuShareAppMessage',
'onMenuShareQQ',
'onMenuShareWeibo',
'onMenuShareQZone',
'hideMenuItems',
'showMenuItems',
'hideOptionMenu'
] // 必填,需要使用的JS接口列表
};
wx.config(config);
wechatReady(showShare, shareOptions);
wechatError();
};
/**
* 微信, 通过ready接口处理成功验证
* @param showShare 是否显示微信分享
* @param options
*/
const wechatReady = (showShare, shareOptions = {}) => {
wx.ready(function() {
console.log('微信 js-sdk wx.ready');
// config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,
// config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。
// 对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
wechatStatus.ready = true;
wechatStatus.error = '';
// 配置
configShare(showShare, shareOptions);
});
};
/**
* 配置分享
* @param showShare
* @param shareOptions
*/
export const configShare = (showShare, shareOptions = {}) => {
console.log('configShare >>> ', shareOptions);
const parser = queryString.parse(window.location.search) || {};
const { from, isappinstalled, ...rest } = parser;
const location = window.location;
const defaultLink = `${location.protocol}//${location.host}${
location.pathname
}?${queryString.stringify(rest)}`;
const options = {
title: shareConfig.default.title, // 分享标题
desc: shareConfig.default.desc, // 分享描述
link: defaultLink, // 默认分享链接
imgUrl: shareConfig.default.imgUrl, // 分享图标
type: shareConfig.default.type, // 分享类型,music、video或link,不填默认为link
dataUrl: shareConfig.default.dataUrl, // 如果type是music或video,则要提供数据链接,默认为空
...shareOptions
};
console.log('微信分享设置', '是否允许分享功能: ' + showShare, options);
onMenuShareTimeline(options);
onMenuShareAppMessage(options);
onMenuShareQQ(options);
onMenuShareWeibo(options);
onMenuShareQZone(options);
// 展示分享 或 隐藏分享
showOrHideMenuShare(showShare);
};
/**
* 微信, 通过error接口处理失败验证
*/
const wechatError = () => {
wx.error(function(res) {
// config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
wechatStatus.ready = false;
wechatStatus.error = JSON.stringify(res);
// console.error('wechatError >> 微信签名失败!', res);
});
};
/**
* 选择微信支付
*/
export const chooseWXPay = (option) => {
if (!wechatStatus.ready) {
console.error('微信>>>签名失败');
return;
}
wx.chooseWXPay({
timestamp: option.timestamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
nonceStr: option.nonceStr, // 支付签名随机串,不长于 32 位
package: option.package, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=\*\*\*)
signType: option.signType, // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
paySign: option.paySign, // 支付签名
success: function(res) {
if (res.errMsg === 'chooseWXPay:ok') {
option.success && option.success();
} else {
option.fail && option.fail({ msg: res.errMsg });
}
},
cancel: function() {
option.cancel && option.cancel();
},
fail: function(res) {
option.fail && option.fail({ msg: (res && res.errMsg) || '支付失败' });
}
});
};
/**
* 微信选择图片
* @param count
* @param callback 回调
*/
export const chooseImage = ({ count = 1, callback }) => {
if (!wechatStatus.ready) {
// console.error('微信>>>签名失败');
return;
}
wx.chooseImage({
count: count, // 默认9
sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
success: function(res) {
callback && callback(res.localIds);
}
});
};
/**
* 展示分享 或 屏蔽分享
*/
export const showOrHideMenuShare = (showShare) => {
if (showShare) {
wx.showMenuItems({
menuList: [
'menuItem:share:appMessage',
'menuItem:share:timeline',
'menuItem:share:qq',
'menuItem:share:weiboApp',
'menuItem:share:facebook',
'menuItem:share:QZone',
'menuItem:favorite',
'menuItem:openWithQQBrowser',
'menuItem:openWithSafari'
]
});
} else {
wx.hideMenuItems({
menuList: [
'menuItem:share:appMessage',
'menuItem:share:timeline',
'menuItem:share:qq',
'menuItem:share:weiboApp',
'menuItem:share:facebook',
'menuItem:share:QZone',
'menuItem:favorite',
'menuItem:openWithQQBrowser',
'menuItem:openWithSafari'
] // 要隐藏的菜单项,只能隐藏“传播类”和“保护类”按钮,所有menu项见附录3
});
}
};
/**
* 获取“分享到朋友圈”按钮点击状态及自定义分享内容接口
*/
const onMenuShareTimeline = ({ title, link, imgUrl, success = noop, cancel = noop }) => {
wx.onMenuShareTimeline({
title, // 分享标题
link, // 分享链接
imgUrl, // 分享图标
success,
cancel
});
};
/**
* 获取“分享给朋友”按钮点击状态及自定义分享内容接口
*/
const onMenuShareAppMessage = (options) => {
const { title, desc, link, imgUrl, type, dataUrl, success = noop, cancel = noop } = options;
wx.onMenuShareAppMessage({
title, // 分享标题
desc, // 分享描述
link,
imgUrl, // 分享图标
type, // 分享类型,music、video或link,不填默认为link
dataUrl, // 如果type是music或video,则要提供数据链接,默认为空
success,
cancel // 用户取消分享后执行的回调函数
});
};
/**
* 获取“分享到QQ”按钮点击状态及自定义分享内容接口
*/
const onMenuShareQQ = ({ title, desc, link, imgUrl }) => {
wx.onMenuShareQQ({
title,
desc,
link,
imgUrl,
success: function() {
// 用户确认分享后执行的回调函数
},
cancel: function() {
// 用户取消分享后执行的回调函数
}
});
};
/**
* 获取“分享到腾讯微博”按钮点击状态及自定义分享内容接口
*/
const onMenuShareWeibo = ({ title, desc, link, imgUrl }) => {
wx.onMenuShareWeibo({
title,
desc,
link,
imgUrl,
success: function() {
// 用户确认分享后执行的回调函数
},
cancel: function() {
// 用户取消分享后执行的回调函数
}
});
};
/**
* 分享到QQ空间
*/
const onMenuShareQZone = ({ title, desc, link, imgUrl }) => {
wx.onMenuShareQZone({
title,
desc,
link,
imgUrl,
success: function() {
// 用户确认分享后执行的回调函数
},
cancel: function() {
// 用户取消分享后执行的回调函数
}
});
};
/**
* 延迟, 单位毫秒
* @param delay
* @returns {Promise<any>}
*/
export const getDelay = (delay) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, delay);
});
};
/**
* 用户授权code已经被使用
* @type {number}
*/
const CODE_ALREADY_USED = 40163;
/**
* 用户授权code无效
* @type {number}
*/
const CODE_INVALID = 40029;
/**
* 根据用户主动授权的code, 获取openId和微信token, 接口的响应 会给浏览器添加一个cookie, "wxToken"
* @param code 用户主动授权的code
* @param redirectUrl 当code值已被使用或者无效时的重定向地址
* @returns {Promise<T>}
*/
export const getOpenIdByCode = (code, redirectUrl) => {
return wechatService
.getOpenIdByCode(code)
.then((wechatUserInfo) => {
return new Promise((resolve, reject) => {
if (!wechatUserInfo) {
return reject(new Error({ msg: '获取授权的用户信息失败' }));
}
if (typeof wechatUserInfo === 'string') {
/* eslint no-param-reassign: "off" */
wechatUserInfo = JSON.parse(wechatUserInfo);
}
// 用户授权code已经被使用 或 用户授权code无效, 则需要重定向到 redirectUrl, 然后重新获取用户授权码
if (wechatUserInfo.code === CODE_ALREADY_USED || wechatUserInfo.code === CODE_INVALID) {
resolve();
redirectUrl && redirectUrl.startsWith('http') && window.location.replace(redirectUrl);
return;
}
resolve(wechatUserInfo.openId);
});
})
.catch((error) => {
// console.error(error);
return Promise.reject(new Error({ msg: '获取授权的用户信息失败' }));
});
};
/**
* 环境
* @type {string}
*/
const NODE_ENV = process.env.NODE_ENV || 'development';
/**
* 同步检查用户授权, 如果未授权, 则让用户选择同意授权
*/
export const checkUserAuth = () => {
// 本地开发环境没有微信环境, 所以不做主动授权
if (NODE_ENV === 'development') {
return;
}
console.log('同步检查用户授权, 当前Url参数:', window.location.search);
// 获取微信code
const { code, state } = queryString.parse(window.location.search);
if (code || state) {
return;
}
console.log('同步检查微信授权, 需要用户主动授权', window.location.search);
// 用户主动授权的链接地址
const mainUserAuthUrl = appConfig.resources.mainUserAuthUrl;
// 需要用户主动授权, 获取用户的头像信息
const commonAuthUrl = `${mainUserAuthUrl}&redirect_uri=${encodeURIComponent(
window.location.href
)}&response_type=code&scope=snsapi_userinfo&state=1#wechat_redirect`;
window.location.replace(commonAuthUrl);
return;
};