UNPKG

wodax-login-qrcode.react

Version:

login component with qrcode for WodaX applications

721 lines (642 loc) 25.2 kB
'use strict'; function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } var _extends = _interopDefault(require('@babel/runtime/helpers/extends')); var _regeneratorRuntime = _interopDefault(require('@babel/runtime/regenerator')); var _asyncToGenerator = _interopDefault(require('@babel/runtime/helpers/asyncToGenerator')); var _assertThisInitialized = _interopDefault(require('@babel/runtime/helpers/assertThisInitialized')); var _inheritsLoose = _interopDefault(require('@babel/runtime/helpers/inheritsLoose')); var React = require('react'); var React__default = _interopDefault(React); var QRCode = _interopDefault(require('qrcode.react')); var PropTypes = _interopDefault(require('prop-types')); var StateQrCodeLogin = { ready: "ready", // 准备阶段,二维码未获取,界面准备阶段 loginFailed: "loginFailed", // 登录反馈阶段:二维码扫描登录失败 loginSuccess: "loginSuccess", // 登录反馈阶段:二维码扫描登录成功 scanComplete: "scanComplete", // 登录反馈阶段: 二维码已经扫描,等待用户授权 codeOutWork: "codeOutWork", // 登录反馈阶段: 二维码失效 networkLost: "networkLost", // 登录反馈阶段:长连接丢失 qrCodeGetting: "qrCodeGetting", // 信息获取:二维码获取... qrCodeGetSuccess: "qrCodeGetSuccess", // 信息获取:二维码获取成功 qrCodeGetFailed: "qrCodeGetFailed" // 信息获取:二维码获取失败 }; var ErrorType = { eventSourceError: 0 // eventSource error }; var noop = function noop() {}; var GlobalDebugEnable = false; var debugLog = function debugLog(type) { try { if (GlobalDebugEnable) { for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { args[_key - 1] = arguments[_key]; } console[type || "log"].apply(console, [' [WODAX_DEBUG]: '].concat(args)); } else { noop(); } } catch (e) { console.error(e); } }; var WodaXLoginWithQrCode = /*#__PURE__*/ function (_PureComponent) { _inheritsLoose(WodaXLoginWithQrCode, _PureComponent); function WodaXLoginWithQrCode() { var _this; for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { args[_key2] = arguments[_key2]; } _this = _PureComponent.call.apply(_PureComponent, [this].concat(args)) || this; _this.state = { // 默认状态 currentQrLoginState: StateQrCodeLogin.ready, // 初始二维码值,二维码值来源于内部封装服务或者外部服务 qrcode: "", // 接收到的事件存储起来 sseEvents: [] }; _this.updateQrCode = function () { var _this$props = _this.props, options = _this$props.options, fetchQrCodeHandler = _this$props.fetchQrCodeHandler; var oldQrCode = _this.state.qrcode; var useEventSourceForFetchQrCode = options.useEventSourceForFetchQrCode; _this.setState({ currentQrLoginState: StateQrCodeLogin.qrCodeGetting }, function () { if (!useEventSourceForFetchQrCode) { _asyncToGenerator( /*#__PURE__*/ _regeneratorRuntime.mark(function _callee() { var response, code, data; return _regeneratorRuntime.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: if (!fetchQrCodeHandler) { _context.next = 12; break; } _context.prev = 1; _context.next = 4; return fetchQrCodeHandler(_assertThisInitialized(_this)); case 4: response = _context.sent; code = response.code, data = response.data; if (code === 0) { if (oldQrCode === data) { _this.setState({ currentQrLoginState: StateQrCodeLogin.qrCodeGetSuccess }); } else { _this.uninstallEventSource(); _this.setState({ currentQrLoginState: StateQrCodeLogin.qrCodeGetSuccess, qrcode: data }, function () { _this.installEventSource({ qrcode: data }); }); } } else { _this.uninstallEventSource(); _this.setState({ currentQrLoginState: StateQrCodeLogin.qrCodeGetFailed }); } _context.next = 12; break; case 9: _context.prev = 9; _context.t0 = _context["catch"](1); console.error(_context.t0); case 12: case "end": return _context.stop(); } } }, _callee, null, [[1, 9]]); }))(); } else { _this.uninstallEventSource(); _this.installEventSource(); } }); }; _this.installEventSource = function (config) { if (config === void 0) { config = {}; } var defaultOptions = WodaXLoginWithQrCode.defaultProps.options; var _this$props2 = _this.props, options = _this$props2.options, onReceiveMessageHandler = _this$props2.onReceiveMessageHandler, debugEnable = _this$props2.debugEnable; // 设置全局DebugEnable GlobalDebugEnable = debugEnable; // 获取默认设置的EventSource可以处理的消息类型 var _defaultOptions$optio = _extends({}, defaultOptions, {}, options), clientEventSource = _defaultOptions$optio.clientEventSource; var url = clientEventSource.url, params = clientEventSource.params, messageTypes = clientEventSource.messageTypes, withCredentials = clientEventSource.withCredentials, saveAllEvents = clientEventSource.saveAllEvents; var paramsString = Object.entries(_extends({}, params, {}, config)).map(function (_ref2) { var key = _ref2[0], value = _ref2[1]; return key + "=" + value; }).join("&"); // 获取服务地址 var serviceUrl = encodeURI("" + url + (paramsString.length > 0 ? "?" : "") + paramsString); debugLog("log", "---> SSE url", serviceUrl); if (EventSource) { // 判断当前存在的sse的url是否已经创建过 if (_this.sse) { var _url = _this.sse.url; if (_url === serviceUrl) { return; } else { _this.uninstallEventSource(); } } // 创建 EventSource 实例 debugLog("log", "--> installEventSource"); _this.sse = new EventSource(serviceUrl, { withCredentials: !!withCredentials }); // 注册事件监听 var sseMsgTypes = messageTypes || []; sseMsgTypes = sseMsgTypes.includes("message") ? sseMsgTypes : sseMsgTypes.concat(["message"]); sseMsgTypes.forEach(function (type) { _this.sse.addEventListener(type, function (message) { _this.setState(function (prevState) { var events = (saveAllEvents ? prevState.sseEvents : []).concat(message); return { sseEvents: events }; }); onReceiveMessageHandler && onReceiveMessageHandler(message, _assertThisInitialized(_this)); }, false); }); _this.sse.onopen = function (e) { debugLog("log", "---> SSE Open"); onReceiveMessageHandler && onReceiveMessageHandler(e, _assertThisInitialized(_this)); }; // 连接异常时会触发 error 事件并自动重连 _this.sse.onerror = function (e) { var target = e.target; var readyState = target.readyState; if (EventSource.CLOSED === readyState) { debugLog("log", "---> SSE Disconnected"); } else if (EventSource.CONNECTING === readyState) { debugLog("log", "---> SSE Connecting..."); } onReceiveMessageHandler && onReceiveMessageHandler(e, _assertThisInitialized(_this)); _this.onErrorEventHandler({ type: ErrorType.eventSourceError, data: e }); }; } else { console.error("Your browser doesn't support SSE"); } }; _this.uninstallEventSource = function () { var debugEnable = _this.props.debugEnable; if (_this.sse) { try { debugLog("log", "--> uninstallEventSource"); _this.sse.close(); } catch (e) { debugLog("error", "--> uninstallEventSource [error]", e); } } }; _this.onErrorEventHandler = function (errorInfo) { try { var type = errorInfo.type, data = errorInfo.data; if (type === ErrorType.eventSourceError) {} else {} } catch (e) { console.error(e); } }; return _this; } var _proto = WodaXLoginWithQrCode.prototype; _proto.componentDidMount = function componentDidMount() { this.updateQrCode(); }; _proto.componentWillUnmount = function componentWillUnmount() { this.uninstallEventSource(); }; _proto.render = function render() { var _this$props3 = this.props, className = _this$props3.className, style = _this$props3.style, titleRender = _this$props3.titleRender, qrCodeRender = _this$props3.qrCodeRender, toolTipRender = _this$props3.toolTipRender, additionLayerRender = _this$props3.additionLayerRender, refreshQrCodeRender = _this$props3.refreshQrCodeRender, sseMessageRender = _this$props3.sseMessageRender; return React__default.createElement("div", { className: className, style: _extends({ display: 'flex', justifyContent: 'center', alignItems: 'center', flexDirection: 'column' }, style) }, titleRender(this), qrCodeRender(this), toolTipRender(this), additionLayerRender(this), refreshQrCodeRender(this), sseMessageRender(this)); } /** * 获取或更新二维码 */ ; return WodaXLoginWithQrCode; }(React.PureComponent); /** * 封装默认的渲染函数 * @private */ WodaXLoginWithQrCode.getEnumStateQrCodeLogin = function () { return StateQrCodeLogin; }; var _default = { /** * 最上部分标题渲染 * @param instance React Object * @returns {*} */ titleRender: function titleRender(instance) { var defaultOptions = WodaXLoginWithQrCode.defaultProps.options; var options = instance.props.options; var _defaultOptions$optio2 = _extends({}, defaultOptions, {}, options), title = _defaultOptions$optio2.title, titleStyle = _defaultOptions$optio2.titleStyle, titleClassName = _defaultOptions$optio2.titleClassName, appLogo = _defaultOptions$optio2.appLogo, appLogoClassName = _defaultOptions$optio2.appLogoClassName, appLogoStyle = _defaultOptions$optio2.appLogoStyle; return React__default.createElement("div", { className: titleClassName, style: _extends({ padding: '4px' }, titleStyle), wodaxuiname: "TitleContainer" }, React__default.createElement("span", null, title), appLogo !== "" ? React__default.createElement("div", { className: appLogoClassName, style: appLogoStyle, wodaxuiname: "appLogoContainer" }, React__default.createElement("img", { src: appLogo, alt: appLogo })) : null); }, /** * 二维码显示渲染 * @param instance React Object * @returns {*} */ qrCodeRender: function qrCodeRender(instance) { var defaultOptions = WodaXLoginWithQrCode.defaultProps.options; var options = instance.props.options; var _defaultOptions$optio3 = _extends({}, defaultOptions, {}, options), qrCodeContainerClassName = _defaultOptions$optio3.qrCodeContainerClassName, qrCodeContainerStyle = _defaultOptions$optio3.qrCodeContainerStyle, qrCodeContainerOpacity = _defaultOptions$optio3.qrCodeContainerOpacity, qrCodeConfig = _defaultOptions$optio3.qrCodeConfig; var _instance$state = instance.state, qrcode = _instance$state.qrcode, currentQrLoginState = _instance$state.currentQrLoginState; var opacity = [StateQrCodeLogin.loginFailed, StateQrCodeLogin.loginSuccess, StateQrCodeLogin.scanComplete, StateQrCodeLogin.codeOutWork, StateQrCodeLogin.networkLost, StateQrCodeLogin.qrCodeGetting, StateQrCodeLogin.qrCodeGetFailed].includes(currentQrLoginState) ? qrCodeContainerOpacity["min"] : qrCodeContainerOpacity["max"]; return React__default.createElement("div", { className: qrCodeContainerClassName, style: _extends({ padding: '4px' }, qrCodeContainerStyle, { opacity: opacity }), wodaxuiname: "qrCodeContainer" }, qrcode !== "" && React__default.createElement(QRCode, { value: qrcode, renderAs: qrCodeConfig.renderAs, size: qrCodeConfig.size, bgColor: qrCodeConfig.bgColor, fgColor: qrCodeConfig.fgColor, level: qrCodeConfig.level, includeMargin: qrCodeConfig.includeMargin })); }, /** * 提示信息显示渲染 * @param instance React Object * @returns {*} */ toolTipRender: function toolTipRender(instance) { var defaultOptions = WodaXLoginWithQrCode.defaultProps.options; var options = instance.props.options; var _defaultOptions$optio4 = _extends({}, defaultOptions, {}, options), toolTipContainerClassName = _defaultOptions$optio4.toolTipContainerClassName, toolTipContainerStyle = _defaultOptions$optio4.toolTipContainerStyle, toolTipContainerProps = _defaultOptions$optio4.toolTipContainerProps; var currentQrLoginState = instance.state.currentQrLoginState; var uiMapRender = function uiMapRender() { var uiMap = {}; // eslint-disable-next-line array-callback-return Object.entries(StateQrCodeLogin).map(function (_ref3) { var key = _ref3[0], value = _ref3[1]; ["Text", "ClassName", "Style"].forEach(function (attribute) { if (_extends({}, defaultOptions, {}, options).hasOwnProperty("" + key + attribute)) { var _extends2; uiMap[key] = uiMap[key] || {}; uiMap[key] = _extends((_extends2 = {}, _extends2["" + attribute] = _extends({}, defaultOptions, {}, options)["" + key + attribute], _extends2), uiMap[key]); } }); }); var eleProps = uiMap[currentQrLoginState]; return eleProps ? React.createElement('div', _extends({ className: toolTipContainerClassName, style: toolTipContainerStyle, wodaxuiname: "toolTipContainer" }, toolTipContainerProps), React__default.createElement("div", { className: eleProps["ClassName"], style: _extends({ padding: '4px' }, eleProps["Style"]) }, React__default.createElement("span", null, eleProps["Text"]))) : null; }; return uiMapRender(); }, /** * 附加层处理,完全由外部绘制 * @param instance * @returns {null} */ additionLayerRender: function additionLayerRender(instance) { return null; }, /** * 刷新操作显示渲染 * @param instance React Object * @returns {*} */ refreshQrCodeRender: function refreshQrCodeRender(instance) { var defaultOptions = WodaXLoginWithQrCode.defaultProps.options; var options = instance.props.options; var _defaultOptions$optio5 = _extends({}, defaultOptions, {}, options), refreshContainerShowEveryTime = _defaultOptions$optio5.refreshContainerShowEveryTime, refreshContainerProps = _defaultOptions$optio5.refreshContainerProps, refreshButtonCaption = _defaultOptions$optio5.refreshButtonCaption, refreshButtonElement = _defaultOptions$optio5.refreshButtonElement, refreshButtonProps = _defaultOptions$optio5.refreshButtonProps; var currentQrLoginState = instance.state.currentQrLoginState; var enableRenderElement = [// StateQrCodeLogin.ready, StateQrCodeLogin.loginFailed, StateQrCodeLogin.codeOutWork, // StateQrCodeLogin.qrCodeGetting, // StateQrCodeLogin.qrCodeGetSuccess, StateQrCodeLogin.qrCodeGetFailed].indexOf(currentQrLoginState) > 0 || refreshContainerShowEveryTime; return enableRenderElement && React.createElement("div", _extends({ wodaxuiname: "RefreshContainer" }, refreshContainerProps), React.createElement(refreshButtonElement, _extends({ wodaxuiname: "RefreshButton", onClick: function onClick() { instance.updateQrCode(); } }, refreshButtonProps), refreshButtonCaption)); }, /** * 实时信息接收处理 * @param instance React Object * @returns {null} */ sseMessageRender: function sseMessageRender(instance) { var sseEvents = instance.state.sseEvents; var defaultOptions = WodaXLoginWithQrCode.defaultProps.options; var options = instance.props.options; var _defaultOptions$optio6 = _extends({}, defaultOptions, {}, options), showSSEMessage = _defaultOptions$optio6.showSSEMessage; return instance.sse && sseEvents.length > 0 && showSSEMessage ? React__default.createElement("div", { wodaxuiname: "sseMessageRender", children: sseEvents.map(function (eventMsg) { // TODO: 根据事件的数据,来处理 return React__default.createElement("p", null, eventMsg.data); }) }) : null; }, /** * 获取二维码接口 * @param instance WodaXLoginWithQrCode 实例 * @returns {Promise<R>|Promise} */ fetchQrCodeHandler: function fetchQrCodeHandler(instance) { return new Promise(function (resolve, reject) { resolve({ code: 0, data: "http://ops.woda.ink/wodax/umi/" + Date.now() }); }); }, /** * 接收SSE发过来的数据 * @param data SSE发送的数据 * @param instance WodaXLoginWithQrCode 实例 */ onReceiveMessageHandler: function onReceiveMessageHandler(data, instance) {// debugLog(`log`, `onReceiveMessageHandler -->`, data); } }; WodaXLoginWithQrCode.propTypes = { className: PropTypes.string, Style: PropTypes.object, // 是否开启日志调试 debugEnable: PropTypes.bool, options: /*#__PURE__*/ PropTypes.shape({ // 基础参数: {eventSource使用} // 是否使用EventSource来重新获取最新QrCode useEventSourceForFetchQrCode: PropTypes.bool, // EventSource 的配置 clientEventSource: /*#__PURE__*/ PropTypes.shape({ // EventSource 主要服务url url: PropTypes.string, // EventSource 附带参数 params: PropTypes.object, // EventSource 可以处理的消息类型 messageTypes: PropTypes.array, // withCredentials withCredentials: PropTypes.bool, // EventSource 是否保存所有接收到的事件 saveAllEvents: PropTypes.bool }), // 基础参数: {Title使用} // 显示的Title内容 title: PropTypes.string, titleStyle: PropTypes.object, titleClassName: PropTypes.string, // 基础参数: {AppLogo使用} // 显示App的Logo appLogo: PropTypes.string, appLogoClassName: PropTypes.string, appLogoStyle: PropTypes.object, // 基础参数: {二维码配置} // QrCode 二维码配置 // see: https://github.com/zpao/qrcode.react qrCodeConfig: /*#__PURE__*/ PropTypes.shape({ renderAs: PropTypes.string, size: PropTypes.number, bgColor: PropTypes.string, fgColor: PropTypes.string, level: PropTypes.string, includeMargin: PropTypes.bool }), qrCodeContainerClassName: PropTypes.string, qrCodeContainerStyle: PropTypes.object, qrCodeContainerOpacity: /*#__PURE__*/ PropTypes.shape({ min: PropTypes.number, max: PropTypes.number }), // 基础参数: {提示信息} toolTipContainerClassName: PropTypes.string, toolTipContainerStyle: PropTypes.object, toolTipContainerProps: PropTypes.object, codeOutWorkText: PropTypes.string, codeOutWorkClassName: PropTypes.string, codeOutWorkStyle: PropTypes.object, loginFailedText: PropTypes.string, loginFailedClassName: PropTypes.string, loginFailedStyle: PropTypes.object, loginSuccessText: PropTypes.string, loginSuccessClassName: PropTypes.string, loginSuccessStyle: PropTypes.object, qrCodeGetFailedText: PropTypes.string, qrCodeGetFailedClassName: PropTypes.string, qrCodeGetFailedStyle: PropTypes.object, scanCompleteText: PropTypes.string, scanCompleteClassName: PropTypes.string, scanCompleteStyle: PropTypes.object, // 基础参数: {刷新,重新获取二维码} // 是否一直显示刷新区域 refreshContainerShowEveryTime: PropTypes.bool, // 刷新最外层的div的Props refreshContainerProps: PropTypes.object, // 指定按钮的标题 refreshButtonCaption: PropTypes.string, // 指定按钮的选择的元素 refreshButtonElement: PropTypes.string | PropTypes.element | PropTypes.elementType | PropTypes.func, // 指定按钮的Props refreshButtonProps: PropTypes.object, // 基础参数: {实时信息接收处理} // 是否默认显示sse回显信息 showSSEMessage: PropTypes.bool }), // 数据请求接口,可以覆盖 fetchQrCodeHandler: PropTypes.func.isRequired, // 数据反馈接口。外接应用,可以自己处理所有来自服务器的消息 onReceiveMessageHandler: PropTypes.func, // 渲染接口, 可以覆盖 titleRender: PropTypes.func.isRequired, qrCodeRender: PropTypes.func.isRequired, toolTipRender: PropTypes.func.isRequired, additionLayerRender: PropTypes.func, refreshQrCodeRender: PropTypes.func.isRequired, sseMessageRender: PropTypes.func.isRequired }; WodaXLoginWithQrCode.defaultProps = { className: "wodax-login-with-qrcode", Style: {}, // 是否开启日志调试 debugEnable: false, // 可选项 options: { // 基础参数: {eventSource使用} // 是否使用EventSource来重新获取最新QrCode useEventSourceForFetchQrCode: false, clientEventSource: { // EventSource 主要服务url url: "https://stream.wikimedia.org/v2/stream/recentchange", // EventSource 附带参数 params: {}, // EventSource 可以处理的消息类型 messageTypes: ["message"], // withCredentials withCredentials: false, // EventSource 是否保存所有 saveAllEvents: false }, // 基础参数: {Title使用} title: "\u6253\u5F00App\uFF0C\u626B\u7801\u767B\u5F55", titleClassName: "qr-login-title", appLogo: "", // QrCode 二维码配置 qrCodeConfig: { renderAs: "canvas", size: 128, bgColor: "#FFFFFF", fgColor: "#000000", level: "L", includeMargin: false }, qrCodeContainerOpacity: { min: 0.01, max: 1 }, // 提示信息 toolTipContainerClassName: "qr-login-tooltip", toolTipContainerStyle: { padding: '4px', position: 'absolute' }, codeOutWorkText: "\u4E8C\u7EF4\u7801\u5DF2\u5931\u6548", loginFailedText: "\u767B\u5F55\u5931\u8D25", loginSuccessText: "\u767B\u5F55\u6210\u529F", qrCodeGetFailedText: "\u83B7\u53D6\u4E8C\u7EF4\u7801\u5931\u8D25", scanCompleteText: "\u626B\u63CF\u6210\u529F! \u8BF7\u5728\u624B\u673A\u4E0A\u786E\u8BA4\u767B\u5F55", // 基础参数: {刷新区域,重新获取二维码} // 是否一直显示刷新区域 refreshContainerShowEveryTime: false, refreshContainerProps: { style: { padding: '4px', position: 'absolute', marginTop: '40px' } }, // 点击刷新 refreshButtonCaption: "\u8BF7\u70B9\u51FB\u5237\u65B0", refreshButtonElement: "button", refreshButtonProps: { style: { padding: '4px' } }, // 基础参数: {实时信息接收处理} // 是否默认显示sse回显信息 showSSEMessage: false }, // 数据请求接口,可以覆盖 fetchQrCodeHandler: _default.fetchQrCodeHandler, // 数据反馈接口。外接应用,可以自己处理所有来自服务器的消息 onReceiveMessageHandler: _default.onReceiveMessageHandler, // 渲染接口, 可以覆盖,重新写 titleRender: _default.titleRender, qrCodeRender: _default.qrCodeRender, toolTipRender: _default.toolTipRender, additionLayerRender: _default.additionLayerRender, refreshQrCodeRender: _default.refreshQrCodeRender, sseMessageRender: _default.sseMessageRender }; module.exports = WodaXLoginWithQrCode; //# sourceMappingURL=index.cjs.js.map