message-verify 1.0.1-beta.48 → 1.0.1-beta.5
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.
- package/dist/index.d.ts +2 -3
- package/dist/index.js +30 -59
- package/dist/locales/en.d.ts +0 -4
- package/dist/locales/en.js +1 -5
- package/dist/locales/id.d.ts +0 -4
- package/dist/locales/id.js +1 -5
- package/dist/locales/zh.d.ts +0 -4
- package/dist/locales/zh.js +1 -5
- package/dist/main.js +21 -14
- package/dist/relogin-modal.d.ts +2 -2
- package/dist/relogin-modal.js +7 -8
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utils/type.d.ts +4 -14
- package/dist/verify-modal.d.ts +2 -2
- package/dist/verify-modal.js +19 -40
- package/package.json +2 -3
- package/src/index.tsx +44 -74
- package/src/locales/en.ts +1 -5
- package/src/locales/id.ts +1 -5
- package/src/locales/zh.ts +1 -5
- package/src/main.tsx +19 -16
- package/src/{modal/relogin-modal.tsx → relogin-modal.tsx} +11 -13
- package/src/utils/type.ts +4 -13
- package/src/verify-modal.tsx +129 -0
- package/dist/modal/relogin-modal.d.ts +0 -5
- package/dist/modal/relogin-modal.js +0 -24
- package/dist/modal/verify-modal.d.ts +0 -5
- package/dist/modal/verify-modal.js +0 -143
- package/dist/utils/resource.d.ts +0 -2
- package/dist/utils/resource.js +0 -7
- package/src/modal/verify-modal.tsx +0 -179
- /package/src/{utils/resource.ts → resource.ts} +0 -0
package/src/main.tsx
CHANGED
@@ -1,12 +1,11 @@
|
|
1
1
|
import { createRoot } from 'react-dom/client';
|
2
|
-
import {
|
2
|
+
import { createMessageVerifyModal, initFingerprint } from './index.js'; // 或 './index'
|
3
3
|
import { axios } from '@yqg/resource';
|
4
4
|
|
5
5
|
const data = "{\"mobile\":\"188****4035\",\"verifyCodeKey\":\"3f025b33-988e-47c0-950d-6beb776d043f\",\"needValid\":true,\"step\":2,\"message\":\"需要填写验证码\"}";
|
6
6
|
|
7
7
|
const fp = await initFingerprint();
|
8
|
-
|
9
|
-
console.log(fp, fp2);
|
8
|
+
console.log(fp);
|
10
9
|
|
11
10
|
const config = {
|
12
11
|
"transitional": {
|
@@ -14,6 +13,12 @@ const config = {
|
|
14
13
|
"forcedJSONParsing": true,
|
15
14
|
"clarifyTimeoutError": false
|
16
15
|
},
|
16
|
+
"transformRequest": [
|
17
|
+
null
|
18
|
+
],
|
19
|
+
"transformResponse": [
|
20
|
+
null
|
21
|
+
],
|
17
22
|
"timeout": 0,
|
18
23
|
"xsrfCookieName": "XSRF-TOKEN",
|
19
24
|
"xsrfHeaderName": "X-XSRF-TOKEN",
|
@@ -22,7 +27,9 @@ const config = {
|
|
22
27
|
"headers": {
|
23
28
|
"Accept": "application/json, text/plain, */*",
|
24
29
|
"X-Device-Fingerprint": "185fcce88c629725321adf29daa5e444",
|
25
|
-
"Content-Type": "application/json"
|
30
|
+
"Content-Type": "application/json",
|
31
|
+
"sms-code": "121212",
|
32
|
+
"sms-code-key": "212190c7-2f5e-4cc1-82ec-a242c2ab5425"
|
26
33
|
},
|
27
34
|
"url": "/classification/admin/level/edit",
|
28
35
|
"method": "post",
|
@@ -38,21 +45,17 @@ const config = {
|
|
38
45
|
"data": "{\"id\":1,\"classificationName\":\"个人基本概况信息\",\"classificationLevel\":2}",
|
39
46
|
"baseURL": "http://localhost:62888"
|
40
47
|
};
|
41
|
-
|
42
|
-
const promise = {current: null};
|
43
48
|
createRoot(document.getElementById('root')!).render(
|
44
49
|
<>
|
45
|
-
<button onClick={() => {
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
<button onClick={() => createReLoginModal({
|
51
|
-
goLogin: () => {
|
52
|
-
console.log('goLogin');
|
50
|
+
<button onClick={() => createMessageVerifyModal({
|
51
|
+
data,
|
52
|
+
config,
|
53
|
+
response: {
|
54
|
+
config
|
53
55
|
},
|
54
|
-
lang: '
|
56
|
+
lang: 'en',
|
57
|
+
http: axios,
|
55
58
|
})}>
|
56
|
-
Show
|
59
|
+
Show verify Modal
|
57
60
|
</button>
|
58
61
|
</>);
|
@@ -1,23 +1,20 @@
|
|
1
1
|
import { useState } from 'react'
|
2
|
-
import { Modal, Button } from '
|
3
|
-
import {
|
4
|
-
import t from '../utils/i18n.js'
|
2
|
+
import { Modal, Button } from './compoments/index.js'
|
3
|
+
import { ModalConfig } from './utils/type.js';
|
5
4
|
|
6
|
-
const ReLoginModal = ({ props }: { props:
|
7
|
-
|
5
|
+
const ReLoginModal = ({ props }: { props: ModalConfig }) => {
|
6
|
+
console.log('props', props);
|
8
7
|
const [visible, setVisible] = useState(true);
|
9
8
|
const onClose = () => {
|
10
9
|
setVisible(false);
|
11
|
-
goLogin();
|
12
|
-
destroyModal?.();
|
13
10
|
};
|
14
11
|
return (
|
15
12
|
<Modal visible={visible} onClose={onClose} width={420}>
|
16
13
|
<div style={{ fontWeight: 500, fontSize: 20, marginBottom: 24 }}>
|
17
|
-
|
14
|
+
账号安全提醒
|
18
15
|
</div>
|
19
16
|
<div style={{ color: '#222', fontSize: 16, marginBottom: 40, lineHeight: '24px' }}>
|
20
|
-
|
17
|
+
检测到您的登录环境或网络信息有变动,为保障账户安全,请重新登录验证身份
|
21
18
|
</div>
|
22
19
|
<div style={{ display: 'flex', justifyContent: 'center' }}>
|
23
20
|
<Button
|
@@ -25,15 +22,16 @@ const ReLoginModal = ({ props }: { props: LoginModalConfig }) => {
|
|
25
22
|
background: '#1677ff',
|
26
23
|
color: '#fff',
|
27
24
|
border: 'none',
|
28
|
-
width:
|
29
|
-
height:
|
30
|
-
fontSize:
|
25
|
+
width: 160,
|
26
|
+
height: 44,
|
27
|
+
fontSize: 18,
|
28
|
+
fontWeight: 500,
|
31
29
|
borderRadius: 8,
|
32
30
|
boxShadow: '0 2px 8px rgba(22,119,255,0.08)',
|
33
31
|
}}
|
34
32
|
onClick={onClose}
|
35
33
|
>
|
36
|
-
|
34
|
+
好的
|
37
35
|
</Button>
|
38
36
|
</div>
|
39
37
|
</Modal>
|
package/src/utils/type.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
|
2
|
-
export type
|
2
|
+
export type ModalConfig = {
|
3
3
|
data: string;
|
4
4
|
onClose?: () => void
|
5
5
|
config: {
|
@@ -8,7 +8,7 @@ export type VerifyModalConfig = {
|
|
8
8
|
};
|
9
9
|
[key: string]: unknown;
|
10
10
|
};
|
11
|
-
lang
|
11
|
+
lang: 'zh' | 'en' | 'id';
|
12
12
|
http: {
|
13
13
|
(params: object): Promise<unknown>;
|
14
14
|
defaults: {
|
@@ -19,15 +19,6 @@ export type VerifyModalConfig = {
|
|
19
19
|
}
|
20
20
|
}
|
21
21
|
};
|
22
|
-
|
23
|
-
|
24
|
-
apiResolve?: any;
|
25
|
-
apiPromiseToEmpty?: () => void;
|
26
|
-
verifyPromise: {current: Promise<any> | null}
|
27
|
-
}
|
28
|
-
|
29
|
-
export type LoginModalConfig = {
|
30
|
-
goLogin: () => void;
|
31
|
-
onClose?: () => void
|
32
|
-
lang?: 'zh' | 'en' | 'id';
|
22
|
+
api?: string;
|
23
|
+
response: any;
|
33
24
|
}
|
@@ -0,0 +1,129 @@
|
|
1
|
+
import { useEffect, useState } from 'react'
|
2
|
+
import { Modal, Input, Button, message } from './compoments/index.js'
|
3
|
+
import Api from './resource.js'
|
4
|
+
import t from './utils/i18n.js'
|
5
|
+
import { ModalConfig } from './utils/type.js';
|
6
|
+
import { axios } from '@yqg/resource';
|
7
|
+
|
8
|
+
const CreateMessageVerifyModal = ({ props }: { props: ModalConfig }) => {
|
9
|
+
const [visible, setVisible] = useState(true);
|
10
|
+
const [countdown, setCountdown] = useState(60);
|
11
|
+
const [otp, setOtp] = useState('');
|
12
|
+
const [captchaImage, setCaptchaImage] = useState<string>('');
|
13
|
+
const [captchCode, setCaptchCode] = useState<string>('');
|
14
|
+
const [captchaKey, setCaptchaKey] = useState<string>('');
|
15
|
+
const { data, config, http, lang, api='/admin/sms/send', response } = props || {};
|
16
|
+
const dataObj = JSON.parse(data || '{}');
|
17
|
+
const { mobile, verifyCodeKey } = dataObj || {};
|
18
|
+
|
19
|
+
const getKey = async () => {
|
20
|
+
try {
|
21
|
+
const res = await Api.getCaptchaKey();
|
22
|
+
const { body: key } = res.data || {};
|
23
|
+
setCaptchaKey(key);
|
24
|
+
if (key) {
|
25
|
+
const image = Api.getCaptchaImgUrl(key) as unknown;
|
26
|
+
setCaptchaImage(image as string);
|
27
|
+
}
|
28
|
+
} catch (err) {const msg =
|
29
|
+
typeof err === 'object' && err !== null && 'message' in err
|
30
|
+
? (err as {message: string}).message
|
31
|
+
: String(err);
|
32
|
+
message.error(msg as React.ReactNode);
|
33
|
+
}
|
34
|
+
}
|
35
|
+
|
36
|
+
useEffect(() => {
|
37
|
+
let timer: number | null = null;
|
38
|
+
if (visible && countdown > 0) {
|
39
|
+
timer = setInterval(() => {
|
40
|
+
setCountdown((prev) => prev - 1);
|
41
|
+
}, 1000);
|
42
|
+
}
|
43
|
+
if (countdown === 0) {
|
44
|
+
getKey();
|
45
|
+
}
|
46
|
+
return () => {
|
47
|
+
if (timer) clearInterval(timer);
|
48
|
+
};
|
49
|
+
}, [visible, countdown]);
|
50
|
+
|
51
|
+
const handleResend = async () => {
|
52
|
+
const formData = new FormData();
|
53
|
+
formData.append('captchaKey', captchaKey);
|
54
|
+
formData.append('captcha', captchCode);
|
55
|
+
// 重新发送验证码
|
56
|
+
const res = await axios.post(api, formData);
|
57
|
+
const { code, detail } = res.data?.status || {};
|
58
|
+
if (code !== 0) {
|
59
|
+
message.error(detail || t('sendFailed', lang));
|
60
|
+
return;
|
61
|
+
}
|
62
|
+
message.success(t('sendSuccess', lang));
|
63
|
+
setCountdown(60);
|
64
|
+
}
|
65
|
+
|
66
|
+
return (
|
67
|
+
<Modal
|
68
|
+
width={420}
|
69
|
+
visible={visible}
|
70
|
+
onClose={() => {
|
71
|
+
setVisible(false);
|
72
|
+
props.onClose?.();
|
73
|
+
}}
|
74
|
+
>
|
75
|
+
<div style={{ fontSize: 14, color: '#666' }}>{t('alreadySend', lang, { phone: mobile })}</div>
|
76
|
+
|
77
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 12 }}>
|
78
|
+
<Input.OTP
|
79
|
+
length={6}
|
80
|
+
value={otp}
|
81
|
+
onChange={async (val) => {
|
82
|
+
setOtp(val);
|
83
|
+
if (val.length === 6) {
|
84
|
+
const {data: {status: {code, detail} = {}}} = response || {};
|
85
|
+
http({
|
86
|
+
...config,
|
87
|
+
headers: {
|
88
|
+
...http.defaults.headers.common,
|
89
|
+
'sms-code': val,
|
90
|
+
'sms-code-key': verifyCodeKey,
|
91
|
+
'Content-Type': config.headers['Content-Type'],
|
92
|
+
}
|
93
|
+
}) as any;
|
94
|
+
console.log(response, code, 'config');
|
95
|
+
if(code !== 0) {
|
96
|
+
message.error(detail || t('verifyFailed', lang));
|
97
|
+
return;
|
98
|
+
} else {
|
99
|
+
message.success(t('verifySuccess', lang));
|
100
|
+
setVisible(false);
|
101
|
+
}
|
102
|
+
}
|
103
|
+
}} />
|
104
|
+
<Button
|
105
|
+
disabled={countdown > 0 || !captchCode}
|
106
|
+
onClick={handleResend}
|
107
|
+
style={{ padding: '8px' }}
|
108
|
+
>
|
109
|
+
{countdown > 0 ? t('countDownSecound', lang, { countdown }) : t('reSend', lang)}
|
110
|
+
</Button>
|
111
|
+
</div>
|
112
|
+
{countdown > 0 ? null :
|
113
|
+
<div style={{ marginTop: 12, display: 'flex', alignItems: 'center' }}>
|
114
|
+
<Input
|
115
|
+
placeholder={t('pleaseEnterPicVerifyCode', lang)}
|
116
|
+
onChange={(e) => {
|
117
|
+
setCaptchCode(e as string)
|
118
|
+
}}
|
119
|
+
style={{ width: 300 }}
|
120
|
+
/>
|
121
|
+
|
122
|
+
{captchaImage && <img src={captchaImage} alt={t('verifyCode', lang)} style={{ width: 100, height: 30, marginLeft: 8 }} onClick={getKey} />}
|
123
|
+
</div>}
|
124
|
+
{(countdown > 0 || captchCode) ? null : <div style={{ fontSize: 14, color: 'red' }}>{t('pleaseEnterAndSend', lang)}</div>}
|
125
|
+
</Modal>
|
126
|
+
);
|
127
|
+
};
|
128
|
+
|
129
|
+
export default CreateMessageVerifyModal;
|
@@ -1,24 +0,0 @@
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
2
|
-
import { useState } from 'react';
|
3
|
-
import { Modal, Button } from '../compoments/index.js';
|
4
|
-
import t from '../utils/i18n.js';
|
5
|
-
const ReLoginModal = ({ props }) => {
|
6
|
-
const { goLogin, lang, onClose: destroyModal } = props || {};
|
7
|
-
const [visible, setVisible] = useState(true);
|
8
|
-
const onClose = () => {
|
9
|
-
setVisible(false);
|
10
|
-
goLogin();
|
11
|
-
destroyModal?.();
|
12
|
-
};
|
13
|
-
return (_jsxs(Modal, { visible: visible, onClose: onClose, width: 420, children: [_jsx("div", { style: { fontWeight: 500, fontSize: 20, marginBottom: 24 }, children: t('accountAlert', lang) }), _jsx("div", { style: { color: '#222', fontSize: 16, marginBottom: 40, lineHeight: '24px' }, children: t('alertContent', lang) }), _jsx("div", { style: { display: 'flex', justifyContent: 'center' }, children: _jsx(Button, { style: {
|
14
|
-
background: '#1677ff',
|
15
|
-
color: '#fff',
|
16
|
-
border: 'none',
|
17
|
-
width: 80,
|
18
|
-
height: 36,
|
19
|
-
fontSize: 14,
|
20
|
-
borderRadius: 8,
|
21
|
-
boxShadow: '0 2px 8px rgba(22,119,255,0.08)',
|
22
|
-
}, onClick: onClose, children: t('ok', lang) }) })] }));
|
23
|
-
};
|
24
|
-
export default ReLoginModal;
|
@@ -1,143 +0,0 @@
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
2
|
-
import { useEffect, useState } from 'react';
|
3
|
-
import { Modal, Input, Button, message } from '../compoments/index.js';
|
4
|
-
import Api from '../utils/resource.js';
|
5
|
-
import t from '../utils/i18n.js';
|
6
|
-
import { axios } from '@yqg/resource';
|
7
|
-
const CreateMessageVerifyModal = ({ props }) => {
|
8
|
-
const [visible, setVisible] = useState(true);
|
9
|
-
const [countdown, setCountdown] = useState(60);
|
10
|
-
const [otp, setOtp] = useState('');
|
11
|
-
const [captchaImage, setCaptchaImage] = useState('');
|
12
|
-
const [captchCode, setCaptchCode] = useState('');
|
13
|
-
const [captchaKey, setCaptchaKey] = useState('');
|
14
|
-
const { data, http, lang, sendApi = '/admin/sms/send', config, apiResolve, apiPromiseToEmpty, onClose } = props || {};
|
15
|
-
const dataObj = JSON.parse(data || '{}');
|
16
|
-
const { mobile, verifyCodeKey } = dataObj || {};
|
17
|
-
const getKey = async () => {
|
18
|
-
try {
|
19
|
-
const res = await Api.getCaptchaKey();
|
20
|
-
const { body: key } = res.data || {};
|
21
|
-
setCaptchaKey(key);
|
22
|
-
if (key) {
|
23
|
-
const image = Api.getCaptchaImgUrl(key);
|
24
|
-
setCaptchaImage(image);
|
25
|
-
}
|
26
|
-
}
|
27
|
-
catch (err) {
|
28
|
-
const msg = typeof err === 'object' && err !== null && 'message' in err
|
29
|
-
? err.message
|
30
|
-
: String(err);
|
31
|
-
message.error(msg);
|
32
|
-
}
|
33
|
-
};
|
34
|
-
useEffect(() => {
|
35
|
-
let timer = null;
|
36
|
-
if (visible && countdown > 0) {
|
37
|
-
timer = setInterval(() => {
|
38
|
-
setCountdown((prev) => prev - 1);
|
39
|
-
}, 1000);
|
40
|
-
}
|
41
|
-
if (countdown === 0) {
|
42
|
-
getKey();
|
43
|
-
}
|
44
|
-
return () => {
|
45
|
-
if (timer)
|
46
|
-
clearInterval(timer);
|
47
|
-
};
|
48
|
-
}, [visible, countdown]);
|
49
|
-
const handleResend = async () => {
|
50
|
-
const formData = new FormData();
|
51
|
-
formData.append('captchaKey', captchaKey);
|
52
|
-
formData.append('captcha', captchCode);
|
53
|
-
// 重新发送验证码
|
54
|
-
const res = await axios.post(sendApi, formData);
|
55
|
-
const { code, detail } = res.data?.status || {};
|
56
|
-
if (code !== 0) {
|
57
|
-
message.error(detail || t('sendFailed', lang));
|
58
|
-
return;
|
59
|
-
}
|
60
|
-
message.success(t('sendSuccess', lang));
|
61
|
-
// 重置倒计时、验证码
|
62
|
-
setCountdown(60);
|
63
|
-
setOtp('');
|
64
|
-
};
|
65
|
-
return (_jsxs(Modal, { width: 420, visible: visible, onClose: () => {
|
66
|
-
setVisible(false);
|
67
|
-
apiPromiseToEmpty?.();
|
68
|
-
onClose?.();
|
69
|
-
}, children: [_jsx("div", { style: { fontSize: 14, color: '#666' }, children: t('alreadySend', lang, { phone: mobile }) }), _jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 8, marginTop: 12 }, children: [_jsx(Input.OTP, { length: 6, value: otp, onChange: async (val) => {
|
70
|
-
setOtp(val);
|
71
|
-
if (val.length === 6) {
|
72
|
-
// try {
|
73
|
-
// const res = await Promise.race([
|
74
|
-
// new Promise((resolve, reject) => {
|
75
|
-
// setTimeout(() => {
|
76
|
-
// reject(new Error('Timeout'));
|
77
|
-
// }, 1000);
|
78
|
-
// }),
|
79
|
-
// new Promise((resolve, reject) => {
|
80
|
-
// http({
|
81
|
-
// ...config,
|
82
|
-
// headers: {
|
83
|
-
// ...http.defaults.headers.common,
|
84
|
-
// 'sms-code': val,
|
85
|
-
// 'sms-code-key': verifyCodeKey,
|
86
|
-
// 'Content-Type': config.headers['Content-Type'],
|
87
|
-
// }
|
88
|
-
// }).then(res => {
|
89
|
-
// resolve(res);
|
90
|
-
// }).catch(err => {
|
91
|
-
// reject(err);
|
92
|
-
// })
|
93
|
-
// ]) as any;
|
94
|
-
// if (res?.data?.status?.code === 0) {
|
95
|
-
// apiResolve(res);
|
96
|
-
// setVisible(false);
|
97
|
-
// } else {
|
98
|
-
// message.error('验证失败');
|
99
|
-
// setOtp('');
|
100
|
-
// }
|
101
|
-
// } catch (error) {
|
102
|
-
// console.warn('catch', error);
|
103
|
-
// message.error('验证失败');
|
104
|
-
// setOtp('');
|
105
|
-
// }
|
106
|
-
try {
|
107
|
-
const res = new Promise((resolve, reject) => {
|
108
|
-
http({
|
109
|
-
...config,
|
110
|
-
headers: {
|
111
|
-
...http.defaults.headers.common,
|
112
|
-
'sms-code': val,
|
113
|
-
'sms-code-key': verifyCodeKey,
|
114
|
-
'Content-Type': config.headers['Content-Type'],
|
115
|
-
}
|
116
|
-
}).then(res => {
|
117
|
-
resolve(res);
|
118
|
-
}).catch(err => {
|
119
|
-
reject(err);
|
120
|
-
});
|
121
|
-
});
|
122
|
-
console.log('res', res);
|
123
|
-
if (res?.data?.status?.code === 0) {
|
124
|
-
apiResolve(res);
|
125
|
-
setVisible(false);
|
126
|
-
}
|
127
|
-
else {
|
128
|
-
message.error('验证失败');
|
129
|
-
setOtp('');
|
130
|
-
}
|
131
|
-
}
|
132
|
-
catch (error) {
|
133
|
-
console.warn('catch', error);
|
134
|
-
message.error('验证失败');
|
135
|
-
setOtp('');
|
136
|
-
}
|
137
|
-
}
|
138
|
-
} }), _jsx(Button, { disabled: countdown > 0 || !captchCode, onClick: handleResend, style: { padding: '8px' }, children: countdown > 0 ? t('countDownSecound', lang, { countdown }) : t('reSend', lang) })] }), countdown > 0 ? null :
|
139
|
-
_jsxs("div", { style: { marginTop: 12, display: 'flex', alignItems: 'center' }, children: [_jsx(Input, { placeholder: t('pleaseEnterPicVerifyCode', lang), onChange: (e) => {
|
140
|
-
setCaptchCode(e);
|
141
|
-
}, style: { width: 300 } }), captchaImage && _jsx("img", { src: captchaImage, alt: t('verifyCode', lang), style: { width: 100, height: 30, marginLeft: 8 }, onClick: getKey })] }), (countdown > 0 || captchCode) ? null : _jsx("div", { style: { fontSize: 14, color: 'red' }, children: t('pleaseEnterAndSend', lang) }), _jsx("div", { style: { fontSize: 14, color: '#666', marginTop: 12 }, children: t('chidoriOpenPro', lang) })] }));
|
142
|
-
};
|
143
|
-
export default CreateMessageVerifyModal;
|
package/dist/utils/resource.d.ts
DELETED
package/dist/utils/resource.js
DELETED
@@ -1,7 +0,0 @@
|
|
1
|
-
import { assign, customPost } from '@yqg/resource';
|
2
|
-
const api = {
|
3
|
-
getCaptchaKey: customPost('/messageVerify/admin/captcha/key'),
|
4
|
-
reSendCode: customPost('/admin/sms/send'),
|
5
|
-
getCaptchaImgUrl: (captchaKey) => { return `/messageVerify/admin/captcha/image/${captchaKey}`; },
|
6
|
-
};
|
7
|
-
export default assign(api);
|
@@ -1,179 +0,0 @@
|
|
1
|
-
import { useEffect, useState } from 'react'
|
2
|
-
import { Modal, Input, Button, message } from '../compoments/index.js'
|
3
|
-
import Api from '../utils/resource.js'
|
4
|
-
import t from '../utils/i18n.js'
|
5
|
-
import { VerifyModalConfig } from '../utils/type.js';
|
6
|
-
import { axios } from '@yqg/resource';
|
7
|
-
|
8
|
-
const CreateMessageVerifyModal = ({ props }: { props: VerifyModalConfig }) => {
|
9
|
-
const [visible, setVisible] = useState(true);
|
10
|
-
const [countdown, setCountdown] = useState(60);
|
11
|
-
const [otp, setOtp] = useState('');
|
12
|
-
const [captchaImage, setCaptchaImage] = useState<string>('');
|
13
|
-
const [captchCode, setCaptchCode] = useState<string>('');
|
14
|
-
const [captchaKey, setCaptchaKey] = useState<string>('');
|
15
|
-
const { data, http, lang, sendApi = '/admin/sms/send', config, apiResolve, apiPromiseToEmpty, onClose } = props || {};
|
16
|
-
const dataObj = JSON.parse(data || '{}');
|
17
|
-
const { mobile, verifyCodeKey } = dataObj || {};
|
18
|
-
|
19
|
-
const getKey = async () => {
|
20
|
-
try {
|
21
|
-
const res = await Api.getCaptchaKey();
|
22
|
-
const { body: key } = res.data || {};
|
23
|
-
setCaptchaKey(key);
|
24
|
-
if (key) {
|
25
|
-
const image = Api.getCaptchaImgUrl(key) as unknown;
|
26
|
-
setCaptchaImage(image as string);
|
27
|
-
}
|
28
|
-
} catch (err) {
|
29
|
-
const msg =
|
30
|
-
typeof err === 'object' && err !== null && 'message' in err
|
31
|
-
? (err as { message: string }).message
|
32
|
-
: String(err);
|
33
|
-
message.error(msg as React.ReactNode);
|
34
|
-
}
|
35
|
-
}
|
36
|
-
|
37
|
-
useEffect(() => {
|
38
|
-
let timer: number | null = null;
|
39
|
-
if (visible && countdown > 0) {
|
40
|
-
timer = setInterval(() => {
|
41
|
-
setCountdown((prev) => prev - 1);
|
42
|
-
}, 1000);
|
43
|
-
}
|
44
|
-
if (countdown === 0) {
|
45
|
-
getKey();
|
46
|
-
}
|
47
|
-
return () => {
|
48
|
-
if (timer) clearInterval(timer);
|
49
|
-
};
|
50
|
-
}, [visible, countdown]);
|
51
|
-
|
52
|
-
const handleResend = async () => {
|
53
|
-
const formData = new FormData();
|
54
|
-
formData.append('captchaKey', captchaKey);
|
55
|
-
formData.append('captcha', captchCode);
|
56
|
-
// 重新发送验证码
|
57
|
-
const res = await axios.post(sendApi, formData);
|
58
|
-
const { code, detail } = res.data?.status || {};
|
59
|
-
if (code !== 0) {
|
60
|
-
message.error(detail || t('sendFailed', lang));
|
61
|
-
return;
|
62
|
-
}
|
63
|
-
message.success(t('sendSuccess', lang));
|
64
|
-
// 重置倒计时、验证码
|
65
|
-
setCountdown(60);
|
66
|
-
setOtp('');
|
67
|
-
}
|
68
|
-
|
69
|
-
return (
|
70
|
-
<Modal
|
71
|
-
width={420}
|
72
|
-
visible={visible}
|
73
|
-
onClose={() => {
|
74
|
-
setVisible(false);
|
75
|
-
apiPromiseToEmpty?.();
|
76
|
-
onClose?.();
|
77
|
-
}}
|
78
|
-
>
|
79
|
-
<div style={{ fontSize: 14, color: '#666' }}>{t('alreadySend', lang, { phone: mobile })}</div>
|
80
|
-
|
81
|
-
<div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 12 }}>
|
82
|
-
<Input.OTP
|
83
|
-
length={6}
|
84
|
-
value={otp}
|
85
|
-
onChange={async (val) => {
|
86
|
-
setOtp(val);
|
87
|
-
if (val.length === 6) {
|
88
|
-
// try {
|
89
|
-
// const res = await Promise.race([
|
90
|
-
// new Promise((resolve, reject) => {
|
91
|
-
// setTimeout(() => {
|
92
|
-
// reject(new Error('Timeout'));
|
93
|
-
// }, 1000);
|
94
|
-
// }),
|
95
|
-
// new Promise((resolve, reject) => {
|
96
|
-
// http({
|
97
|
-
// ...config,
|
98
|
-
// headers: {
|
99
|
-
// ...http.defaults.headers.common,
|
100
|
-
// 'sms-code': val,
|
101
|
-
// 'sms-code-key': verifyCodeKey,
|
102
|
-
// 'Content-Type': config.headers['Content-Type'],
|
103
|
-
// }
|
104
|
-
// }).then(res => {
|
105
|
-
// resolve(res);
|
106
|
-
// }).catch(err => {
|
107
|
-
// reject(err);
|
108
|
-
// })
|
109
|
-
// ]) as any;
|
110
|
-
// if (res?.data?.status?.code === 0) {
|
111
|
-
// apiResolve(res);
|
112
|
-
// setVisible(false);
|
113
|
-
// } else {
|
114
|
-
// message.error('验证失败');
|
115
|
-
// setOtp('');
|
116
|
-
// }
|
117
|
-
// } catch (error) {
|
118
|
-
// console.warn('catch', error);
|
119
|
-
// message.error('验证失败');
|
120
|
-
// setOtp('');
|
121
|
-
// }
|
122
|
-
try {
|
123
|
-
const res = new Promise((resolve, reject) => {
|
124
|
-
http({
|
125
|
-
...config,
|
126
|
-
headers: {
|
127
|
-
...http.defaults.headers.common,
|
128
|
-
'sms-code': val,
|
129
|
-
'sms-code-key': verifyCodeKey,
|
130
|
-
'Content-Type': config.headers['Content-Type'],
|
131
|
-
}
|
132
|
-
}).then(res => {
|
133
|
-
resolve(res);
|
134
|
-
}).catch(err => {
|
135
|
-
reject(err);
|
136
|
-
})
|
137
|
-
}) as any;
|
138
|
-
console.log('res', res);
|
139
|
-
if (res?.data?.status?.code === 0) {
|
140
|
-
apiResolve(res);
|
141
|
-
setVisible(false);
|
142
|
-
} else {
|
143
|
-
message.error('验证失败');
|
144
|
-
setOtp('');
|
145
|
-
}
|
146
|
-
} catch (error) {
|
147
|
-
console.warn('catch', error);
|
148
|
-
message.error('验证失败');
|
149
|
-
setOtp('');
|
150
|
-
}
|
151
|
-
}
|
152
|
-
}} />
|
153
|
-
<Button
|
154
|
-
disabled={countdown > 0 || !captchCode}
|
155
|
-
onClick={handleResend}
|
156
|
-
style={{ padding: '8px' }}
|
157
|
-
>
|
158
|
-
{countdown > 0 ? t('countDownSecound', lang, { countdown }) : t('reSend', lang)}
|
159
|
-
</Button>
|
160
|
-
</div>
|
161
|
-
{countdown > 0 ? null :
|
162
|
-
<div style={{ marginTop: 12, display: 'flex', alignItems: 'center' }}>
|
163
|
-
<Input
|
164
|
-
placeholder={t('pleaseEnterPicVerifyCode', lang)}
|
165
|
-
onChange={(e) => {
|
166
|
-
setCaptchCode(e as string)
|
167
|
-
}}
|
168
|
-
style={{ width: 300 }}
|
169
|
-
/>
|
170
|
-
|
171
|
-
{captchaImage && <img src={captchaImage} alt={t('verifyCode', lang)} style={{ width: 100, height: 30, marginLeft: 8 }} onClick={getKey} />}
|
172
|
-
</div>}
|
173
|
-
{(countdown > 0 || captchCode) ? null : <div style={{ fontSize: 14, color: 'red' }}>{t('pleaseEnterAndSend', lang)}</div>}
|
174
|
-
<div style={{ fontSize: 14, color: '#666', marginTop: 12 }}>{t('chidoriOpenPro', lang)}</div>
|
175
|
-
</Modal>
|
176
|
-
);
|
177
|
-
};
|
178
|
-
|
179
|
-
export default CreateMessageVerifyModal;
|
File without changes
|