component-sanzhizhou 1.1.7 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ interface Props {
3
+ env?: Global.Env;
4
+ apiUrl?: string;
5
+ roleType?: UserAuth.RoleType;
6
+ disabledFormItemLabel?: boolean;
7
+ accountRegDisabled?: boolean;
8
+ onSuccess: () => void;
9
+ }
10
+ /** 账户登录 / 注册 / 找回密码 切换。 */
11
+ declare const Account: React.FC<Props>;
12
+ export default Account;
@@ -0,0 +1,57 @@
1
+ import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
2
+ import React, { useState } from 'react';
3
+ import { Radio } from 'antd';
4
+ import { UserOutlined, UserAddOutlined, UnlockOutlined } from '@ant-design/icons';
5
+ import formatMessage from "../lib/formatMessage";
6
+ import Login from "./login";
7
+ import Register from "./register";
8
+ import ForgotPassword from "./forgot-password";
9
+ import styles from "./index.css";
10
+ /** 账户登录 / 注册 / 找回密码 切换。 */
11
+ var Account = function Account(_ref) {
12
+ var env = _ref.env,
13
+ apiUrl = _ref.apiUrl,
14
+ roleType = _ref.roleType,
15
+ disabledFormItemLabel = _ref.disabledFormItemLabel,
16
+ accountRegDisabled = _ref.accountRegDisabled,
17
+ onSuccess = _ref.onSuccess;
18
+ var _useState = useState(accountRegDisabled ? 'login' : 'login'),
19
+ _useState2 = _slicedToArray(_useState, 2),
20
+ activeKey = _useState2[0],
21
+ setActiveKey = _useState2[1];
22
+ return /*#__PURE__*/React.createElement(styles.Account, null, /*#__PURE__*/React.createElement("div", {
23
+ className: "radioSelectBox"
24
+ }, /*#__PURE__*/React.createElement(Radio.Group, {
25
+ value: activeKey,
26
+ onChange: function onChange(e) {
27
+ return setActiveKey(e.target.value);
28
+ }
29
+ }, /*#__PURE__*/React.createElement(Radio.Button, {
30
+ value: "login"
31
+ }, /*#__PURE__*/React.createElement(UserOutlined, null), " ", formatMessage('登录')), /*#__PURE__*/React.createElement(Radio.Button, {
32
+ value: "reg",
33
+ disabled: accountRegDisabled
34
+ }, /*#__PURE__*/React.createElement(UserAddOutlined, null), " ", formatMessage('注册')), /*#__PURE__*/React.createElement(Radio.Button, {
35
+ value: "forgot"
36
+ }, /*#__PURE__*/React.createElement(UnlockOutlined, null), " ", formatMessage('忘记密码')))), activeKey === 'login' && /*#__PURE__*/React.createElement(Login, {
37
+ env: env,
38
+ apiUrl: apiUrl,
39
+ roleType: roleType,
40
+ disabledFormItemLabel: disabledFormItemLabel,
41
+ onSuccess: onSuccess
42
+ }), activeKey === 'reg' && /*#__PURE__*/React.createElement(Register, {
43
+ env: env,
44
+ apiUrl: apiUrl,
45
+ roleType: roleType,
46
+ disabledFormItemLabel: disabledFormItemLabel,
47
+ onSuccess: onSuccess
48
+ }), activeKey === 'forgot' && /*#__PURE__*/React.createElement(ForgotPassword, {
49
+ env: env,
50
+ apiUrl: apiUrl,
51
+ disabledFormItemLabel: disabledFormItemLabel,
52
+ onDone: function onDone() {
53
+ return setActiveKey('login');
54
+ }
55
+ }));
56
+ };
57
+ export default Account;
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ interface Props {
3
+ env?: Global.Env;
4
+ apiUrl?: string;
5
+ disabledFormItemLabel?: boolean;
6
+ /** 重置成功后回调(切回登录)。 */
7
+ onDone: () => void;
8
+ }
9
+ /** 找回密码:短信验证码 + 新密码。 */
10
+ declare const ForgotPassword: React.FC<Props>;
11
+ export default ForgotPassword;
@@ -0,0 +1,109 @@
1
+ import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
2
+ import React from 'react';
3
+ import { LockOutlined, UserOutlined, EyeTwoTone, EyeInvisibleOutlined } from '@ant-design/icons';
4
+ import { Input, Button, Form } from 'antd';
5
+ import { useRequest } from '@umijs/hooks';
6
+ import Tool from "../lib/Tool";
7
+ import * as AuthController from "../service/api/AuthController";
8
+ import formatMessage from "../lib/formatMessage";
9
+ import PhoneCode from "./phone-code";
10
+ /** 找回密码:短信验证码 + 新密码。 */
11
+ var ForgotPassword = function ForgotPassword(_ref) {
12
+ var env = _ref.env,
13
+ apiUrl = _ref.apiUrl,
14
+ disabledFormItemLabel = _ref.disabledFormItemLabel,
15
+ onDone = _ref.onDone;
16
+ var _Form$useForm = Form.useForm(),
17
+ _Form$useForm2 = _slicedToArray(_Form$useForm, 1),
18
+ form = _Form$useForm2[0];
19
+ var _useRequest = useRequest(function (data) {
20
+ return AuthController.forgotPassword({
21
+ accountName: data.accountName,
22
+ smsCode: data.smsCode,
23
+ password: data.password
24
+ }, {
25
+ env: env,
26
+ apiUrl: apiUrl
27
+ });
28
+ }, {
29
+ manual: true,
30
+ onSuccess: function onSuccess() {
31
+ Tool.toast(formatMessage('密码已重置,请登录'));
32
+ onDone();
33
+ }
34
+ }),
35
+ loading = _useRequest.loading,
36
+ run = _useRequest.run;
37
+ var onFinish = function onFinish(values) {
38
+ values.accountName = (values.accountName || '').replace(/\s+/g, '');
39
+ run(values);
40
+ };
41
+ return /*#__PURE__*/React.createElement("section", {
42
+ className: "authMainForgot"
43
+ }, /*#__PURE__*/React.createElement(Form, {
44
+ form: form,
45
+ onFinish: onFinish,
46
+ disabled: loading,
47
+ autoComplete: "off"
48
+ }, /*#__PURE__*/React.createElement(Form.Item, {
49
+ label: disabledFormItemLabel ? undefined : formatMessage('手机号码'),
50
+ labelCol: {
51
+ span: 8
52
+ },
53
+ name: "accountName",
54
+ rules: [{
55
+ required: true,
56
+ message: formatMessage('请输入')
57
+ }, {
58
+ pattern: /^\s*1\d{2}\s*\d{4}\s*\d{4}\s*$/,
59
+ message: "".concat(formatMessage('这似乎不是中国大陆手机号码'), "\uFF1F")
60
+ }]
61
+ }, /*#__PURE__*/React.createElement(Input, {
62
+ placeholder: formatMessage('手机号码'),
63
+ prefix: /*#__PURE__*/React.createElement(UserOutlined, {
64
+ className: "input-prefix-icon"
65
+ })
66
+ })), /*#__PURE__*/React.createElement(PhoneCode, {
67
+ form: form,
68
+ scene: "forgot",
69
+ env: env,
70
+ apiUrl: apiUrl,
71
+ disabledFormItemLabel: disabledFormItemLabel
72
+ }), /*#__PURE__*/React.createElement(Form.Item, {
73
+ label: disabledFormItemLabel ? undefined : formatMessage('新密码'),
74
+ labelCol: {
75
+ span: 8
76
+ },
77
+ name: "password",
78
+ rules: [{
79
+ required: true,
80
+ message: formatMessage('请输入')
81
+ }, {
82
+ min: 6,
83
+ message: formatMessage('最少{maxCount}个字符', {
84
+ maxCount: 6
85
+ })
86
+ }, {
87
+ max: 60,
88
+ message: formatMessage('最多{maxCount}个字符', {
89
+ maxCount: 60
90
+ })
91
+ }]
92
+ }, /*#__PURE__*/React.createElement(Input.Password, {
93
+ prefix: /*#__PURE__*/React.createElement(LockOutlined, {
94
+ className: "input-prefix-icon"
95
+ }),
96
+ placeholder: formatMessage('请输入'),
97
+ iconRender: function iconRender(visible) {
98
+ return visible ? /*#__PURE__*/React.createElement(EyeTwoTone, null) : /*#__PURE__*/React.createElement(EyeInvisibleOutlined, null);
99
+ }
100
+ })), /*#__PURE__*/React.createElement("div", {
101
+ className: "auth-submits"
102
+ }, /*#__PURE__*/React.createElement(Button, {
103
+ type: "primary",
104
+ loading: loading,
105
+ htmlType: "submit",
106
+ icon: /*#__PURE__*/React.createElement(UserOutlined, null)
107
+ }, formatMessage('重置密码')))));
108
+ };
109
+ export default ForgotPassword;
@@ -0,0 +1,8 @@
1
+ /// <reference types="react" />
2
+ declare const _default: {
3
+ AuthQrLogin: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
4
+ LoginForm: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
5
+ WeQrUrlBox: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
6
+ Account: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
7
+ };
8
+ export default _default;
@@ -0,0 +1,19 @@
1
+ import styled from 'styled-components';
2
+ export default {
3
+ AuthQrLogin: styled.div.withConfig({
4
+ displayName: "AuthQrLogin",
5
+ componentId: "component-sanzhizhou__sc-17uutxn-0"
6
+ })(["position:relative;.ant-tabs-tab-btn{.anticon{margin-right:6px;}}.weQrUrl{position:absolute;left:50%;transform:translateX(-50%);}.qr{position:relative;display:block;margin:12px auto 0;width:230px;height:230px;background-repeat:no-repeat;background-size:cover;background-position:center;.reTry{position:absolute;z-index:100;left:0;top:0;width:100%;font-size:80px;background-color:rgba(255,255,255,0.95);text-align:center;line-height:210px;height:100%;a{display:block;}}}.alt{padding:10px 0 0;color:#999;text-align:center;}.altWeb{padding:16px 0 0;max-width:300px;margin:0 auto;.titles{text-align:center;font-weight:bold;}ul{margin:0 10px;}}.percent{width:100%;position:absolute;overflow:hidden;left:0;bottom:0;.warp{height:4px;background-color:#1677ff;transition:all 1.6s ease-in-out;-webkit-transition:all 1.6s ease-in-out;}}.callWechat{position:absolute;left:6px;bottom:6px;background:#f6f6f6;width:4px;height:4px;}.callAccount{position:absolute;right:6px;bottom:6px;background:#f6f6f6;width:4px;height:4px;}.ssz-webTitle{font-weight:normal;font-size:26px;text-align:center;padding:6px 0 0 0;line-height:1em;span{display:inline-block;padding-left:5px;font-weight:lighter;font-size:16px;}}"]),
7
+ LoginForm: styled.div.withConfig({
8
+ displayName: "LoginForm",
9
+ componentId: "component-sanzhizhou__sc-17uutxn-1"
10
+ })(["margin:0 auto;padding:12px 16px 6px 16px;background-color:rgba(255,255,255,0.9);border-radius:6px;"]),
11
+ WeQrUrlBox: styled.div.withConfig({
12
+ displayName: "WeQrUrlBox",
13
+ componentId: "component-sanzhizhou__sc-17uutxn-2"
14
+ })(["min-height:240px !important;"]),
15
+ Account: styled.div.withConfig({
16
+ displayName: "Account",
17
+ componentId: "component-sanzhizhou__sc-17uutxn-3"
18
+ })([".radioSelectBox{text-align:right;margin-bottom:8px;}.auth-submits{margin-top:8px;text-align:right;.ant-btn{width:100%;}}"])
19
+ };
@@ -0,0 +1,22 @@
1
+ import React from 'react';
2
+ interface Props {
3
+ productType: string;
4
+ apiUrl?: string;
5
+ clientUniqueKeyList: string[];
6
+ loginTypeList: Global.AuthClientLoginType[];
7
+ domain?: string;
8
+ env?: Global.Env;
9
+ roleType?: UserAuth.RoleType;
10
+ disabledFormItemLabel?: boolean;
11
+ postData: {
12
+ [name: string]: any;
13
+ };
14
+ onLoginSuccess: () => void;
15
+ }
16
+ /**
17
+ * 登录 / 注册(重构版)。
18
+ * - 微信扫码:逻辑与旧 Auth 保持一致(WechatQr)。
19
+ * - 账户:登录 / 短信注册 / 找回密码(Account)。
20
+ */
21
+ declare const Auth: React.FC<Props>;
22
+ export default Auth;
@@ -0,0 +1,92 @@
1
+ import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
2
+ import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
3
+ import React, { useState, useEffect } from 'react';
4
+ import { WechatOutlined, UserOutlined } from '@ant-design/icons';
5
+ import { Tabs } from 'antd';
6
+ import Platform from "../lib/platform";
7
+ import formatMessage from "../lib/formatMessage";
8
+ import h5WePublicLogin from "../AuthClient/qr/h5-we-public-login";
9
+ import WechatQr from "./wechat-qr";
10
+ import Account from "./account";
11
+ import styles from "./index.css";
12
+ /**
13
+ * 登录 / 注册(重构版)。
14
+ * - 微信扫码:逻辑与旧 Auth 保持一致(WechatQr)。
15
+ * - 账户:登录 / 短信注册 / 找回密码(Account)。
16
+ */
17
+ var Auth = function Auth(_ref) {
18
+ var productType = _ref.productType,
19
+ apiUrl = _ref.apiUrl,
20
+ clientUniqueKeyList = _ref.clientUniqueKeyList,
21
+ loginTypeList = _ref.loginTypeList,
22
+ env = _ref.env,
23
+ postData = _ref.postData,
24
+ roleType = _ref.roleType,
25
+ disabledFormItemLabel = _ref.disabledFormItemLabel,
26
+ _ref$domain = _ref.domain,
27
+ domain = _ref$domain === void 0 ? document.location.hostname : _ref$domain,
28
+ _ref$onLoginSuccess = _ref.onLoginSuccess,
29
+ onLoginSuccess = _ref$onLoginSuccess === void 0 ? function () {} : _ref$onLoginSuccess;
30
+ var _useState = useState(_toConsumableArray(loginTypeList)),
31
+ _useState2 = _slicedToArray(_useState, 2),
32
+ currentLoginTypeList = _useState2[0],
33
+ setCurrentLoginTypeList = _useState2[1];
34
+ var _useState3 = useState((currentLoginTypeList === null || currentLoginTypeList === void 0 ? void 0 : currentLoginTypeList[0]) || 'account'),
35
+ _useState4 = _slicedToArray(_useState3, 2),
36
+ activeKey = _useState4[0],
37
+ setActiveKey = _useState4[1];
38
+ var hasWechat = currentLoginTypeList.includes('wechat');
39
+ var hasAccount = currentLoginTypeList.includes('account-login') || currentLoginTypeList.includes('account');
40
+ var accountRegDisabled = !currentLoginTypeList.includes('account-reg');
41
+ var onTabChange = function onTabChange(keyName) {
42
+ setActiveKey(keyName);
43
+ };
44
+ var onCallWechat = function onCallWechat() {
45
+ currentLoginTypeList.push('wechat');
46
+ setCurrentLoginTypeList(_toConsumableArray(currentLoginTypeList));
47
+ };
48
+ var onCallAccount = function onCallAccount() {
49
+ currentLoginTypeList.push('account', 'account-reg', 'account-login');
50
+ setCurrentLoginTypeList(_toConsumableArray(currentLoginTypeList));
51
+ };
52
+ useEffect(function () {
53
+ if (Platform.isWechat) {
54
+ h5WePublicLogin();
55
+ }
56
+ // eslint-disable-next-line react-hooks/exhaustive-deps
57
+ }, []);
58
+ return /*#__PURE__*/React.createElement(styles.AuthQrLogin, null, /*#__PURE__*/React.createElement(styles.LoginForm, null, /*#__PURE__*/React.createElement("div", {
59
+ className: "ssz-webTitle"
60
+ }, formatMessage('登录/注册')), /*#__PURE__*/React.createElement(Tabs, {
61
+ activeKey: activeKey,
62
+ onChange: onTabChange
63
+ }, hasWechat && /*#__PURE__*/React.createElement(Tabs.TabPane, {
64
+ tab: /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(WechatOutlined, null), " ", formatMessage('微信')),
65
+ key: "wechat"
66
+ }, /*#__PURE__*/React.createElement(WechatQr, {
67
+ domain: domain,
68
+ onLoginSuccess: onLoginSuccess
69
+ })), /*#__PURE__*/React.createElement(Tabs.TabPane, {
70
+ tab: /*#__PURE__*/React.createElement("span", {
71
+ className: "tab-icon"
72
+ }, /*#__PURE__*/React.createElement(UserOutlined, null), " ", formatMessage('账户')),
73
+ disabled: !hasAccount,
74
+ key: "account"
75
+ }, /*#__PURE__*/React.createElement(Account, {
76
+ env: env,
77
+ apiUrl: apiUrl,
78
+ roleType: roleType,
79
+ disabledFormItemLabel: disabledFormItemLabel,
80
+ accountRegDisabled: accountRegDisabled,
81
+ onSuccess: function onSuccess() {
82
+ return onLoginSuccess();
83
+ }
84
+ })))), /*#__PURE__*/React.createElement("div", {
85
+ className: "callWechat",
86
+ onClick: onCallWechat
87
+ }), /*#__PURE__*/React.createElement("div", {
88
+ className: "callAccount",
89
+ onClick: onCallAccount
90
+ }));
91
+ };
92
+ export default Auth;
@@ -0,0 +1,3 @@
1
+ import type { AccountAuthData } from './types';
2
+ /** 登录 / 注册成功后的统一处理:写本地用户信息 + 触发事件。 */
3
+ export declare function applyLoginSuccess(data: AccountAuthData, roleType?: UserAuth.RoleType): void;
@@ -0,0 +1,14 @@
1
+ import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
2
+ import Tool from "../lib/Tool";
3
+ import formatMessage from "../lib/formatMessage";
4
+ /** 登录 / 注册成功后的统一处理:写本地用户信息 + 触发事件。 */
5
+ export function applyLoginSuccess(data, roleType) {
6
+ Tool.setLocalUserInfo(_objectSpread(_objectSpread({}, data), {}, {
7
+ isLogin: true
8
+ }));
9
+ Tool.toast(formatMessage('成功'));
10
+ Tool.event.run('user-info');
11
+ Tool.event.run("".concat(roleType || 'user', "-login-success"), _objectSpread(_objectSpread({}, data), {}, {
12
+ isLogin: true
13
+ }));
14
+ }
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ import type { AccountFormProps } from './types';
3
+ interface Props extends AccountFormProps {
4
+ roleType?: UserAuth.RoleType;
5
+ disabledFormItemLabel?: boolean;
6
+ }
7
+ /** 账户密码登录。 */
8
+ declare const Login: React.FC<Props>;
9
+ export default Login;
@@ -0,0 +1,99 @@
1
+ import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
2
+ import React from 'react';
3
+ import { LockOutlined, UserOutlined, EyeTwoTone, EyeInvisibleOutlined } from '@ant-design/icons';
4
+ import { Input, Button, Form } from 'antd';
5
+ import { useRequest } from '@umijs/hooks';
6
+ import * as AuthController from "../service/api/AuthController";
7
+ import formatMessage from "../lib/formatMessage";
8
+ import { applyLoginSuccess } from "./login-success";
9
+ /** 账户密码登录。 */
10
+ var Login = function Login(_ref) {
11
+ var env = _ref.env,
12
+ apiUrl = _ref.apiUrl,
13
+ roleType = _ref.roleType,
14
+ disabledFormItemLabel = _ref.disabledFormItemLabel,
15
+ _onSuccess = _ref.onSuccess;
16
+ var _Form$useForm = Form.useForm(),
17
+ _Form$useForm2 = _slicedToArray(_Form$useForm, 1),
18
+ form = _Form$useForm2[0];
19
+ var _useRequest = useRequest(function (data) {
20
+ return AuthController.accountLogin(data, {
21
+ env: env,
22
+ apiUrl: apiUrl
23
+ });
24
+ }, {
25
+ manual: true,
26
+ onSuccess: function onSuccess(result) {
27
+ applyLoginSuccess(result, roleType);
28
+ _onSuccess();
29
+ }
30
+ }),
31
+ loading = _useRequest.loading,
32
+ run = _useRequest.run;
33
+ var onFinish = function onFinish(values) {
34
+ values.accountName = (values.accountName || '').replace(/\s+/g, '');
35
+ run(values);
36
+ };
37
+ return /*#__PURE__*/React.createElement("section", {
38
+ className: "authMainLogin"
39
+ }, /*#__PURE__*/React.createElement(Form, {
40
+ form: form,
41
+ onFinish: onFinish,
42
+ disabled: loading,
43
+ autoComplete: "off"
44
+ }, /*#__PURE__*/React.createElement(Form.Item, {
45
+ label: disabledFormItemLabel ? undefined : formatMessage('手机号码'),
46
+ labelCol: {
47
+ span: 8
48
+ },
49
+ name: "accountName",
50
+ rules: [{
51
+ required: true,
52
+ message: formatMessage('请输入')
53
+ }, {
54
+ pattern: /^\s*1\d{2}\s*\d{4}\s*\d{4}\s*$/,
55
+ message: "".concat(formatMessage('这似乎不是中国大陆手机号码'), "\uFF1F")
56
+ }]
57
+ }, /*#__PURE__*/React.createElement(Input, {
58
+ placeholder: formatMessage('手机号码'),
59
+ prefix: /*#__PURE__*/React.createElement(UserOutlined, {
60
+ className: "input-prefix-icon"
61
+ })
62
+ })), /*#__PURE__*/React.createElement(Form.Item, {
63
+ label: disabledFormItemLabel ? undefined : formatMessage('密码'),
64
+ labelCol: {
65
+ span: 8
66
+ },
67
+ name: "password",
68
+ rules: [{
69
+ required: true,
70
+ message: formatMessage('请输入')
71
+ }, {
72
+ min: 6,
73
+ message: formatMessage('最少{maxCount}个字符', {
74
+ maxCount: 6
75
+ })
76
+ }, {
77
+ max: 60,
78
+ message: formatMessage('最多{maxCount}个字符', {
79
+ maxCount: 60
80
+ })
81
+ }]
82
+ }, /*#__PURE__*/React.createElement(Input.Password, {
83
+ prefix: /*#__PURE__*/React.createElement(LockOutlined, {
84
+ className: "input-prefix-icon"
85
+ }),
86
+ placeholder: formatMessage('请输入'),
87
+ iconRender: function iconRender(visible) {
88
+ return visible ? /*#__PURE__*/React.createElement(EyeTwoTone, null) : /*#__PURE__*/React.createElement(EyeInvisibleOutlined, null);
89
+ }
90
+ })), /*#__PURE__*/React.createElement("div", {
91
+ className: "auth-submits"
92
+ }, /*#__PURE__*/React.createElement(Button, {
93
+ type: "primary",
94
+ loading: loading,
95
+ htmlType: "submit",
96
+ icon: /*#__PURE__*/React.createElement(UserOutlined, null)
97
+ }, formatMessage('登录')))));
98
+ };
99
+ export default Login;
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import type { SmsScene } from './types';
3
+ interface Props {
4
+ form: any;
5
+ scene: SmsScene;
6
+ env?: Global.Env;
7
+ apiUrl?: string;
8
+ disabledFormItemLabel?: boolean;
9
+ }
10
+ /** 手机号 + 验证码 + 发送按钮(含倒计时与工作量证明)。 */
11
+ declare const PhoneCode: React.FC<Props>;
12
+ export default PhoneCode;
@@ -0,0 +1,134 @@
1
+ import _regeneratorRuntime from "@babel/runtime/helpers/esm/regeneratorRuntime";
2
+ import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
3
+ import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
4
+ import React, { useEffect, useState } from 'react';
5
+ import { Button, Form, Input, Space } from 'antd';
6
+ import { SafetyOutlined } from '@ant-design/icons';
7
+ import Tool from "../lib/Tool";
8
+ import formatMessage from "../lib/formatMessage";
9
+ import * as AuthController from "../service/api/AuthController";
10
+ import { solvePow } from "./pow";
11
+ var phoneReg = /^1\d{10}$/;
12
+ /** 手机号 + 验证码 + 发送按钮(含倒计时与工作量证明)。 */
13
+ var PhoneCode = function PhoneCode(_ref) {
14
+ var form = _ref.form,
15
+ scene = _ref.scene,
16
+ env = _ref.env,
17
+ apiUrl = _ref.apiUrl,
18
+ disabledFormItemLabel = _ref.disabledFormItemLabel;
19
+ var accountName = Form.useWatch('accountName', form);
20
+ var _useState = useState(0),
21
+ _useState2 = _slicedToArray(_useState, 2),
22
+ countdown = _useState2[0],
23
+ setCountdown = _useState2[1];
24
+ var _useState3 = useState(false),
25
+ _useState4 = _slicedToArray(_useState3, 2),
26
+ sending = _useState4[0],
27
+ setSending = _useState4[1];
28
+ useEffect(function () {
29
+ if (countdown <= 0) {
30
+ return;
31
+ }
32
+ var timer = setTimeout(function () {
33
+ return setCountdown(function (c) {
34
+ return c - 1;
35
+ });
36
+ }, 1000);
37
+ return function () {
38
+ return clearTimeout(timer);
39
+ };
40
+ }, [countdown]);
41
+ var onSendCode = /*#__PURE__*/function () {
42
+ var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee() {
43
+ var phone, challengeData, nonce;
44
+ return _regeneratorRuntime().wrap(function _callee$(_context) {
45
+ while (1) switch (_context.prev = _context.next) {
46
+ case 0:
47
+ phone = (accountName || '').replace(/\s+/g, '');
48
+ if (phoneReg.test(phone)) {
49
+ _context.next = 4;
50
+ break;
51
+ }
52
+ Tool.toastError(formatMessage('请输入正确的手机号码'));
53
+ return _context.abrupt("return");
54
+ case 4:
55
+ setSending(true);
56
+ _context.prev = 5;
57
+ _context.next = 8;
58
+ return AuthController.powChallenge({
59
+ accountName: phone,
60
+ scene: scene
61
+ }, {
62
+ env: env,
63
+ apiUrl: apiUrl
64
+ });
65
+ case 8:
66
+ challengeData = _context.sent;
67
+ _context.next = 11;
68
+ return solvePow(challengeData.challenge, challengeData.difficulty);
69
+ case 11:
70
+ nonce = _context.sent;
71
+ _context.next = 14;
72
+ return AuthController.sendSmsCode({
73
+ accountName: phone,
74
+ scene: scene,
75
+ challenge: challengeData.challenge,
76
+ nonce: nonce
77
+ }, {
78
+ env: env,
79
+ apiUrl: apiUrl
80
+ });
81
+ case 14:
82
+ setCountdown(60);
83
+ Tool.toast(formatMessage('验证码已发送'));
84
+ _context.next = 20;
85
+ break;
86
+ case 18:
87
+ _context.prev = 18;
88
+ _context.t0 = _context["catch"](5);
89
+ case 20:
90
+ _context.prev = 20;
91
+ setSending(false);
92
+ return _context.finish(20);
93
+ case 23:
94
+ case "end":
95
+ return _context.stop();
96
+ }
97
+ }, _callee, null, [[5, 18, 20, 23]]);
98
+ }));
99
+ return function onSendCode() {
100
+ return _ref2.apply(this, arguments);
101
+ };
102
+ }();
103
+ return /*#__PURE__*/React.createElement(Form.Item, {
104
+ label: disabledFormItemLabel ? undefined : formatMessage('验证码'),
105
+ labelCol: {
106
+ span: 8
107
+ }
108
+ }, /*#__PURE__*/React.createElement(Space.Compact, {
109
+ style: {
110
+ width: '100%'
111
+ }
112
+ }, /*#__PURE__*/React.createElement(Form.Item, {
113
+ name: "smsCode",
114
+ noStyle: true,
115
+ rules: [{
116
+ required: true,
117
+ message: formatMessage('请输入验证码')
118
+ }, {
119
+ len: 6,
120
+ message: formatMessage('验证码为6位数字')
121
+ }]
122
+ }, /*#__PURE__*/React.createElement(Input, {
123
+ placeholder: formatMessage('验证码'),
124
+ maxLength: 6,
125
+ prefix: /*#__PURE__*/React.createElement(SafetyOutlined, {
126
+ className: "input-prefix-icon"
127
+ })
128
+ })), /*#__PURE__*/React.createElement(Button, {
129
+ onClick: onSendCode,
130
+ loading: sending,
131
+ disabled: countdown > 0
132
+ }, countdown > 0 ? "".concat(countdown, "s") : formatMessage('获取验证码'))));
133
+ };
134
+ export default PhoneCode;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * hashcash 式工作量证明(客户端)。
3
+ * 与 api-order-printer 的 models/pow.go 保持一致:
4
+ * 输入为 `${challenge}.${nonce}`,求 SHA-256 前导零比特数 >= difficulty。
5
+ */
6
+ /** 计算 ASCII 字符串的 SHA-256 十六进制(输入为纯 ASCII,含数字/字母/点/下划线)。 */
7
+ export declare function sha256Hex(ascii: string): string;
8
+ /** 计算十六进制哈希的前导零比特数。 */
9
+ export declare function leadingZeroBits(hex: string): number;
10
+ /** 求解 nonce,使 SHA256(`${challenge}.${nonce}`) 前导零比特数 >= difficulty。 */
11
+ export declare function solvePow(challenge: string, difficulty: number): Promise<string>;