message-verify 0.0.51-beta.0 → 0.1.1-beta.1
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/README.md +26 -1
- package/dist/compoments/input.js +14 -10
- package/dist/index.d.ts +1 -17
- package/dist/index.js +1 -6
- package/dist/main.js +6 -9
- package/dist/resource.d.ts +1 -1
- package/dist/resource.js +2 -45
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utils/type.d.ts +22 -0
- package/dist/utils/type.js +1 -0
- package/dist/verify-modal.d.ts +1 -16
- package/dist/verify-modal.js +32 -13
- package/package.json +1 -1
- package/src/compoments/input.tsx +16 -8
- package/src/index.tsx +2 -25
- package/src/main.tsx +7 -12
- package/src/resource.ts +2 -50
- package/src/utils/type.ts +23 -0
- package/src/verify-modal.tsx +32 -30
- package/vite.config.ts +8 -1
package/README.md
CHANGED
@@ -9,4 +9,29 @@
|
|
9
9
|
### 1. 引入组件
|
10
10
|
|
11
11
|
```typescript
|
12
|
-
import {createMessageVerifyModal} from 'message-verify';
|
12
|
+
import {createMessageVerifyModal} from 'message-verify';
|
13
|
+
```
|
14
|
+
|
15
|
+
### 2. 参数说明
|
16
|
+
|
17
|
+
```typescript
|
18
|
+
- data :字符串,包含手机号、验证码 key 等信息(JSON 字符串)。
|
19
|
+
- config :对象,必须包含 headers 字段(可为空对象),用于 http 请求配置。
|
20
|
+
- lang :组件使用语言,支持 'zh' (中文)、 'en' (英文)、 'id' (印尼语)。
|
21
|
+
- http :http 客户端实例(如 axios)。
|
22
|
+
- onClose :弹窗关闭回调(可选)。
|
23
|
+
```
|
24
|
+
|
25
|
+
### 3. 示例
|
26
|
+
|
27
|
+
```typescript
|
28
|
+
createMessageVerifyModal({
|
29
|
+
data,
|
30
|
+
config: { headers: {} }, // 必须包含 headers 字段
|
31
|
+
lang: 'zh', // 支持 'zh' | 'en' | 'id'
|
32
|
+
http: axios,
|
33
|
+
onClose: () => {
|
34
|
+
// 可选,弹窗关闭回调
|
35
|
+
}
|
36
|
+
});
|
37
|
+
```
|
package/dist/compoments/input.js
CHANGED
@@ -25,28 +25,32 @@ const OTPInput = ({ length, value = '', onChange, style }) => {
|
|
25
25
|
inputsRef.current[idx - 1]?.focus();
|
26
26
|
}
|
27
27
|
};
|
28
|
-
return (_jsx("div", { style: { display: 'flex', gap:
|
29
|
-
width:
|
30
|
-
height:
|
28
|
+
return (_jsx("div", { style: { display: 'flex', gap: 4, ...style }, children: Array.from({ length }).map((_, idx) => (_jsx("input", { ref: el => { inputsRef.current[idx] = el; }, type: "text", maxLength: 1, value: chars[idx], onChange: e => handleChange(idx, e.target.value), onKeyDown: e => handleKeyDown(idx, e), style: {
|
29
|
+
width: 36,
|
30
|
+
height: 32,
|
31
31
|
textAlign: 'center',
|
32
|
-
fontSize:
|
32
|
+
fontSize: 16,
|
33
33
|
border: '1px solid #d9d9d9',
|
34
|
-
borderRadius:
|
34
|
+
borderRadius: 6,
|
35
35
|
outline: 'none',
|
36
|
-
|
36
|
+
background: '#fff',
|
37
|
+
transition: 'border-color 0.2s',
|
38
|
+
}, onFocus: e => (e.currentTarget.style.borderColor = '#4096ff'), onBlur: e => (e.currentTarget.style.borderColor = '#d9d9d9') }, idx))) }));
|
37
39
|
};
|
38
40
|
const Input = (props) => {
|
39
41
|
return (_jsx("input", { type: props.type || 'text', value: props.value, placeholder: props.placeholder, onChange: e => props.onChange?.(e.target.value), style: {
|
40
|
-
padding: '
|
42
|
+
padding: '4px 11px',
|
41
43
|
border: '1px solid #d9d9d9',
|
42
|
-
borderRadius:
|
44
|
+
borderRadius: 6,
|
43
45
|
outline: 'none',
|
44
46
|
fontSize: 14,
|
45
47
|
width: '100%',
|
46
48
|
boxSizing: 'border-box',
|
47
|
-
height:
|
49
|
+
height: 32,
|
50
|
+
background: '#fff',
|
51
|
+
transition: 'border-color 0.2s',
|
48
52
|
...props.style,
|
49
|
-
} }));
|
53
|
+
}, onFocus: e => (e.currentTarget.style.borderColor = '#4096ff'), onBlur: e => (e.currentTarget.style.borderColor = '#d9d9d9') }));
|
50
54
|
};
|
51
55
|
Input.OTP = OTPInput;
|
52
56
|
export default Input;
|
package/dist/index.d.ts
CHANGED
@@ -1,19 +1,3 @@
|
|
1
|
-
|
1
|
+
import { ModalConfig } from './utils/type.js';
|
2
2
|
export declare const initFingerprint: () => Promise<string>;
|
3
|
-
export type ModalConfig = {
|
4
|
-
data: string;
|
5
|
-
onClose?: () => void;
|
6
|
-
config: object;
|
7
|
-
lang: 'zh' | 'en' | 'id';
|
8
|
-
http: {
|
9
|
-
(params: object): Promise<unknown>;
|
10
|
-
defaults: {
|
11
|
-
headers: {
|
12
|
-
common: {
|
13
|
-
[key: string]: unknown;
|
14
|
-
};
|
15
|
-
};
|
16
|
-
};
|
17
|
-
};
|
18
|
-
};
|
19
3
|
export declare const createMessageVerifyModal: (modalProps: ModalConfig) => void;
|
package/dist/index.js
CHANGED
@@ -2,11 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import ReactDOM from 'react-dom/client';
|
3
3
|
import VerifyModal from './verify-modal.js';
|
4
4
|
import Fingerprint2 from 'fingerprintjs2';
|
5
|
-
|
6
|
-
export const getFingerprint = () => {
|
7
|
-
return cachedFingerprint;
|
8
|
-
};
|
9
|
-
export const initFingerprint = () => {
|
5
|
+
export const initFingerprint = async () => {
|
10
6
|
return new Promise((resolve) => {
|
11
7
|
Fingerprint2.get(function (components) {
|
12
8
|
const includeKeys = ['userAgent', 'deviceMemory', 'cpuClass', 'hardwareConcurrency', 'platform'];
|
@@ -15,7 +11,6 @@ export const initFingerprint = () => {
|
|
15
11
|
.map(component => component.value)
|
16
12
|
.join('###');
|
17
13
|
const fingerprint = Fingerprint2.x64hash128(values, 31);
|
18
|
-
cachedFingerprint = fingerprint;
|
19
14
|
resolve(fingerprint);
|
20
15
|
});
|
21
16
|
});
|
package/dist/main.js
CHANGED
@@ -1,16 +1,13 @@
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
2
2
|
import { createRoot } from 'react-dom/client';
|
3
|
-
import { createMessageVerifyModal } from './index.js'; // 或 './index'
|
3
|
+
import { createMessageVerifyModal, initFingerprint } from './index.js'; // 或 './index'
|
4
|
+
import { axios } from '@yqg/resource';
|
4
5
|
const data = "{\"mobile\":\"188****4035\",\"verifyCodeKey\":\"3f025b33-988e-47c0-950d-6beb776d043f\",\"needValid\":true,\"step\":2,\"message\":\"需要填写验证码\"}";
|
6
|
+
const fp = await initFingerprint();
|
7
|
+
console.log(fp);
|
5
8
|
createRoot(document.getElementById('root')).render(_jsx("button", { onClick: () => createMessageVerifyModal({
|
6
9
|
data,
|
7
|
-
config: {},
|
10
|
+
config: { headers: {} },
|
8
11
|
lang: 'en',
|
9
|
-
http:
|
10
|
-
defaults: {
|
11
|
-
headers: {
|
12
|
-
common: {}
|
13
|
-
}
|
14
|
-
}
|
15
|
-
}),
|
12
|
+
http: axios,
|
16
13
|
}), children: "Show Modal" }));
|
package/dist/resource.d.ts
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
declare const _default: import("@yqg/resource").default & Record<"
|
1
|
+
declare const _default: import("@yqg/resource").default & Record<"getCaptchaKey" | "reSendCode" | "getCaptchaImgUrl", import("@yqg/resource").CustomMethod>;
|
2
2
|
export default _default;
|
package/dist/resource.js
CHANGED
@@ -1,50 +1,7 @@
|
|
1
1
|
import { assign, customPost } from '@yqg/resource';
|
2
|
-
// import { assign, axios as instance, customPost } from '@yqg/resource';
|
3
|
-
// import { message } from './compoments/index.js';
|
4
|
-
// import { YQG_SUCCESS } from './utils/status.js';
|
5
|
-
const urlPrefix = '/messageVerify/admin/';
|
6
|
-
// axios.defaults.headers.common['Access-Control-Allow-Origin'] = '*';
|
7
|
-
// instance.interceptors.response.use(
|
8
|
-
// (res) => {
|
9
|
-
// const { status } = res?.data || {};
|
10
|
-
// const { code, detail } = status || {};
|
11
|
-
// if (res?.config?.responseType === 'blob') {
|
12
|
-
// if (res?.data?.type === 'application/json') {
|
13
|
-
// // 没有拿到文件时,将拿到的 blob 流转为 js 对象,进而拿到错误信息(detail)并返回 reject 状态
|
14
|
-
// // 不处理将默认下载一个 json 文件
|
15
|
-
// const reader = new FileReader();
|
16
|
-
// reader.readAsText(res.data, 'utf-8');
|
17
|
-
// reader.onload = () => {
|
18
|
-
// const parsedObj = JSON.parse(reader.result as string);
|
19
|
-
// message.info(parsedObj?.status?.detail);
|
20
|
-
// };
|
21
|
-
// return Promise.reject();
|
22
|
-
// } else {
|
23
|
-
// return res;
|
24
|
-
// }
|
25
|
-
// }
|
26
|
-
// if (res.headers && res.headers['content-type'] === 'image/jpeg') {
|
27
|
-
// return res;
|
28
|
-
// }
|
29
|
-
// switch (code) {
|
30
|
-
// case YQG_SUCCESS:
|
31
|
-
// return Promise.resolve(res);
|
32
|
-
// default: {
|
33
|
-
// message.error(detail);
|
34
|
-
// return Promise.reject(res);
|
35
|
-
// }
|
36
|
-
// }
|
37
|
-
// },
|
38
|
-
// (err: {data: {status: {detail: string}}}) => {
|
39
|
-
// const detail = err?.data?.status?.detail || 'Unknown error';
|
40
|
-
// message.error(detail);
|
41
|
-
// return Promise.reject(err);
|
42
|
-
// },
|
43
|
-
// );
|
44
2
|
const api = {
|
45
|
-
|
46
|
-
|
47
|
-
reSendCode: customPost('sms/send'),
|
3
|
+
getCaptchaKey: customPost('/messageVerify/admin/captcha/key'),
|
4
|
+
reSendCode: customPost('/admin/sms/send'),
|
48
5
|
getCaptchaImgUrl: (captchaKey) => { return `/messageVerify/admin/captcha/image/${captchaKey}`; },
|
49
6
|
};
|
50
7
|
export default assign(api);
|
@@ -1 +1 @@
|
|
1
|
-
{"root":["../src/index.tsx","../src/main.tsx","../src/resource.ts","../src/verify-modal.tsx","../src/vite-env.d.ts","../src/compoments/button.tsx","../src/compoments/index.ts","../src/compoments/input.tsx","../src/compoments/message.tsx","../src/compoments/modal.tsx","../src/locales/en.ts","../src/locales/id.ts","../src/locales/zh.ts","../src/utils/i18n.ts","../src/utils/status.ts"],"version":"5.7.3"}
|
1
|
+
{"root":["../src/index.tsx","../src/main.tsx","../src/resource.ts","../src/verify-modal.tsx","../src/vite-env.d.ts","../src/compoments/button.tsx","../src/compoments/index.ts","../src/compoments/input.tsx","../src/compoments/message.tsx","../src/compoments/modal.tsx","../src/locales/en.ts","../src/locales/id.ts","../src/locales/zh.ts","../src/utils/i18n.ts","../src/utils/status.ts","../src/utils/type.ts"],"version":"5.7.3"}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
export type ModalConfig = {
|
2
|
+
data: string;
|
3
|
+
onClose?: () => void;
|
4
|
+
config: {
|
5
|
+
headers: {
|
6
|
+
[key: string]: string | undefined;
|
7
|
+
};
|
8
|
+
[key: string]: unknown;
|
9
|
+
};
|
10
|
+
lang: 'zh' | 'en' | 'id';
|
11
|
+
http: {
|
12
|
+
(params: object): Promise<unknown>;
|
13
|
+
defaults: {
|
14
|
+
headers: {
|
15
|
+
common: {
|
16
|
+
[key: string]: unknown;
|
17
|
+
};
|
18
|
+
};
|
19
|
+
};
|
20
|
+
};
|
21
|
+
api?: string;
|
22
|
+
};
|
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|
package/dist/verify-modal.d.ts
CHANGED
@@ -1,19 +1,4 @@
|
|
1
|
-
|
2
|
-
data: string;
|
3
|
-
onClose?: () => void;
|
4
|
-
config: object;
|
5
|
-
lang: 'zh' | 'en' | 'id';
|
6
|
-
http: {
|
7
|
-
(params: object): Promise<unknown>;
|
8
|
-
defaults: {
|
9
|
-
headers: {
|
10
|
-
common: {
|
11
|
-
[key: string]: unknown;
|
12
|
-
};
|
13
|
-
};
|
14
|
-
};
|
15
|
-
};
|
16
|
-
};
|
1
|
+
import { ModalConfig } from './utils/type.js';
|
17
2
|
declare const CreateMessageVerifyModal: ({ props }: {
|
18
3
|
props: ModalConfig;
|
19
4
|
}) => import("react/jsx-runtime.js").JSX.Element;
|
package/dist/verify-modal.js
CHANGED
@@ -3,23 +3,32 @@ import { useEffect, useState } from 'react';
|
|
3
3
|
import { Modal, Input, Button, message } from './compoments/index.js';
|
4
4
|
import Api from './resource.js';
|
5
5
|
import t from './utils/i18n.js';
|
6
|
+
import { axios } from '@yqg/resource';
|
6
7
|
const CreateMessageVerifyModal = ({ props }) => {
|
7
8
|
const [visible, setVisible] = useState(true);
|
8
|
-
const [countdown, setCountdown] = useState(
|
9
|
+
const [countdown, setCountdown] = useState(60);
|
9
10
|
const [otp, setOtp] = useState('');
|
10
11
|
const [captchaImage, setCaptchaImage] = useState('');
|
11
12
|
const [captchCode, setCaptchCode] = useState('');
|
12
13
|
const [captchaKey, setCaptchaKey] = useState('');
|
13
|
-
const { data, config, http, lang } = props || {};
|
14
|
+
const { data, config, http, lang, api = '/admin/sms/send' } = props || {};
|
14
15
|
const dataObj = JSON.parse(data || '{}');
|
15
16
|
const { mobile, verifyCodeKey } = dataObj || {};
|
16
17
|
const getKey = async () => {
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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);
|
23
32
|
}
|
24
33
|
};
|
25
34
|
useEffect(() => {
|
@@ -39,8 +48,11 @@ const CreateMessageVerifyModal = ({ props }) => {
|
|
39
48
|
}, [visible, countdown]);
|
40
49
|
const handleResend = async () => {
|
41
50
|
setCountdown(60);
|
42
|
-
const
|
43
|
-
|
51
|
+
const formData = new FormData();
|
52
|
+
formData.append('captchaKey', captchaKey);
|
53
|
+
formData.append('captcha', captchCode);
|
54
|
+
// 重新发送验证码
|
55
|
+
await axios.post(api, formData);
|
44
56
|
message.success(t('sendSuccess', lang));
|
45
57
|
};
|
46
58
|
return (_jsxs(Modal, { width: 420, visible: visible, onClose: () => {
|
@@ -48,10 +60,17 @@ const CreateMessageVerifyModal = ({ props }) => {
|
|
48
60
|
props.onClose?.();
|
49
61
|
}, 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: (val) => {
|
50
62
|
setOtp(val);
|
63
|
+
console.log('打印Content-Type', config.headers['Content-Type']);
|
51
64
|
if (val.length === 6) {
|
52
|
-
http
|
53
|
-
|
54
|
-
|
65
|
+
http({
|
66
|
+
...config,
|
67
|
+
headers: {
|
68
|
+
...http.defaults.headers.common,
|
69
|
+
'sms-code': val,
|
70
|
+
'sms-code-key': verifyCodeKey,
|
71
|
+
'Content-Type': config.headers['Content-Type'],
|
72
|
+
}
|
73
|
+
});
|
55
74
|
setVisible(false);
|
56
75
|
}
|
57
76
|
} }), _jsx(Button, { disabled: countdown > 0 || !captchCode, onClick: handleResend, style: { padding: '8px' }, children: countdown > 0 ? t('countDownSecound', lang, { countdown }) : t('reSend', lang) })] }), countdown > 0 ? null :
|
package/package.json
CHANGED
package/src/compoments/input.tsx
CHANGED
@@ -44,7 +44,7 @@ const OTPInput: React.FC<OTPInputProps> = ({ length, value = '', onChange, style
|
|
44
44
|
};
|
45
45
|
|
46
46
|
return (
|
47
|
-
<div style={{ display: 'flex', gap:
|
47
|
+
<div style={{ display: 'flex', gap: 4, ...style }}>
|
48
48
|
{Array.from({ length }).map((_, idx) => (
|
49
49
|
<input
|
50
50
|
key={idx}
|
@@ -55,14 +55,18 @@ const OTPInput: React.FC<OTPInputProps> = ({ length, value = '', onChange, style
|
|
55
55
|
onChange={e => handleChange(idx, e.target.value)}
|
56
56
|
onKeyDown={e => handleKeyDown(idx, e)}
|
57
57
|
style={{
|
58
|
-
width:
|
59
|
-
height:
|
58
|
+
width: 36,
|
59
|
+
height: 32,
|
60
60
|
textAlign: 'center',
|
61
|
-
fontSize:
|
61
|
+
fontSize: 16,
|
62
62
|
border: '1px solid #d9d9d9',
|
63
|
-
borderRadius:
|
63
|
+
borderRadius: 6,
|
64
64
|
outline: 'none',
|
65
|
+
background: '#fff',
|
66
|
+
transition: 'border-color 0.2s',
|
65
67
|
}}
|
68
|
+
onFocus={e => (e.currentTarget.style.borderColor = '#4096ff')}
|
69
|
+
onBlur={e => (e.currentTarget.style.borderColor = '#d9d9d9')}
|
66
70
|
/>
|
67
71
|
))}
|
68
72
|
</div>
|
@@ -77,16 +81,20 @@ const Input: React.FC<CustomInputProps> & { OTP: typeof OTPInput } = (props) =>
|
|
77
81
|
placeholder={props.placeholder}
|
78
82
|
onChange={e => props.onChange?.(e.target.value)}
|
79
83
|
style={{
|
80
|
-
padding: '
|
84
|
+
padding: '4px 11px',
|
81
85
|
border: '1px solid #d9d9d9',
|
82
|
-
borderRadius:
|
86
|
+
borderRadius: 6,
|
83
87
|
outline: 'none',
|
84
88
|
fontSize: 14,
|
85
89
|
width: '100%',
|
86
90
|
boxSizing: 'border-box',
|
87
|
-
height:
|
91
|
+
height: 32,
|
92
|
+
background: '#fff',
|
93
|
+
transition: 'border-color 0.2s',
|
88
94
|
...props.style,
|
89
95
|
}}
|
96
|
+
onFocus={e => (e.currentTarget.style.borderColor = '#4096ff')}
|
97
|
+
onBlur={e => (e.currentTarget.style.borderColor = '#d9d9d9')}
|
90
98
|
/>
|
91
99
|
);
|
92
100
|
};
|
package/src/index.tsx
CHANGED
@@ -1,14 +1,9 @@
|
|
1
1
|
import ReactDOM from 'react-dom/client'
|
2
2
|
import VerifyModal from './verify-modal.js'
|
3
3
|
import Fingerprint2 from 'fingerprintjs2';
|
4
|
+
import { ModalConfig } from './utils/type.js';
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
export const getFingerprint = (): string | null => {
|
8
|
-
return cachedFingerprint;
|
9
|
-
};
|
10
|
-
|
11
|
-
export const initFingerprint = (): Promise<string> => {
|
6
|
+
export const initFingerprint = async (): Promise<string> => {
|
12
7
|
return new Promise((resolve) => {
|
13
8
|
Fingerprint2.get(function (components) {
|
14
9
|
const includeKeys = ['userAgent', 'deviceMemory', 'cpuClass', 'hardwareConcurrency', 'platform'];
|
@@ -17,29 +12,11 @@ export const initFingerprint = (): Promise<string> => {
|
|
17
12
|
.map(component => component.value)
|
18
13
|
.join('###');
|
19
14
|
const fingerprint = Fingerprint2.x64hash128(values, 31);
|
20
|
-
cachedFingerprint = fingerprint;
|
21
15
|
resolve(fingerprint);
|
22
16
|
});
|
23
17
|
});
|
24
18
|
};
|
25
19
|
|
26
|
-
export type ModalConfig = {
|
27
|
-
data: string;
|
28
|
-
onClose?: () => void
|
29
|
-
config: object;
|
30
|
-
lang: 'zh' | 'en' | 'id';
|
31
|
-
http: {
|
32
|
-
(params: object): Promise<unknown>;
|
33
|
-
defaults: {
|
34
|
-
headers: {
|
35
|
-
common: {
|
36
|
-
[key: string]: unknown;
|
37
|
-
}
|
38
|
-
}
|
39
|
-
}
|
40
|
-
};
|
41
|
-
}
|
42
|
-
|
43
20
|
let modalRoot: ReactDOM.Root | null = null
|
44
21
|
|
45
22
|
export const createMessageVerifyModal = (modalProps: ModalConfig) => {
|
package/src/main.tsx
CHANGED
@@ -1,23 +1,18 @@
|
|
1
1
|
import { createRoot } from 'react-dom/client';
|
2
|
-
import { createMessageVerifyModal } from './index.js'; // 或 './index'
|
2
|
+
import { createMessageVerifyModal, initFingerprint } from './index.js'; // 或 './index'
|
3
|
+
import { axios } from '@yqg/resource';
|
3
4
|
|
4
5
|
const data = "{\"mobile\":\"188****4035\",\"verifyCodeKey\":\"3f025b33-988e-47c0-950d-6beb776d043f\",\"needValid\":true,\"step\":2,\"message\":\"需要填写验证码\"}";
|
5
6
|
|
7
|
+
const fp = await initFingerprint();
|
8
|
+
console.log(fp);
|
9
|
+
|
6
10
|
createRoot(document.getElementById('root')!).render(
|
7
11
|
<button onClick={() => createMessageVerifyModal({
|
8
12
|
data,
|
9
|
-
config: {},
|
13
|
+
config: {headers: {}},
|
10
14
|
lang: 'en',
|
11
|
-
http:
|
12
|
-
() => Promise.resolve({}),
|
13
|
-
{
|
14
|
-
defaults: {
|
15
|
-
headers: {
|
16
|
-
common: {}
|
17
|
-
}
|
18
|
-
}
|
19
|
-
}
|
20
|
-
),
|
15
|
+
http: axios,
|
21
16
|
})}>
|
22
17
|
Show Modal
|
23
18
|
</button>);
|
package/src/resource.ts
CHANGED
@@ -1,56 +1,8 @@
|
|
1
1
|
import { assign, customPost } from '@yqg/resource';
|
2
|
-
// import { assign, axios as instance, customPost } from '@yqg/resource';
|
3
|
-
// import { message } from './compoments/index.js';
|
4
|
-
// import { YQG_SUCCESS } from './utils/status.js';
|
5
2
|
|
6
|
-
const urlPrefix = '/messageVerify/admin/';
|
7
|
-
// axios.defaults.headers.common['Access-Control-Allow-Origin'] = '*';
|
8
|
-
// instance.interceptors.response.use(
|
9
|
-
// (res) => {
|
10
|
-
// const { status } = res?.data || {};
|
11
|
-
// const { code, detail } = status || {};
|
12
|
-
// if (res?.config?.responseType === 'blob') {
|
13
|
-
// if (res?.data?.type === 'application/json') {
|
14
|
-
// // 没有拿到文件时,将拿到的 blob 流转为 js 对象,进而拿到错误信息(detail)并返回 reject 状态
|
15
|
-
// // 不处理将默认下载一个 json 文件
|
16
|
-
// const reader = new FileReader();
|
17
|
-
// reader.readAsText(res.data, 'utf-8');
|
18
|
-
// reader.onload = () => {
|
19
|
-
// const parsedObj = JSON.parse(reader.result as string);
|
20
|
-
// message.info(parsedObj?.status?.detail);
|
21
|
-
// };
|
22
|
-
|
23
|
-
// return Promise.reject();
|
24
|
-
// } else {
|
25
|
-
// return res;
|
26
|
-
// }
|
27
|
-
// }
|
28
|
-
|
29
|
-
// if (res.headers && res.headers['content-type'] === 'image/jpeg') {
|
30
|
-
// return res;
|
31
|
-
// }
|
32
|
-
|
33
|
-
// switch (code) {
|
34
|
-
// case YQG_SUCCESS:
|
35
|
-
// return Promise.resolve(res);
|
36
|
-
// default: {
|
37
|
-
// message.error(detail);
|
38
|
-
// return Promise.reject(res);
|
39
|
-
// }
|
40
|
-
// }
|
41
|
-
// },
|
42
|
-
// (err: {data: {status: {detail: string}}}) => {
|
43
|
-
// const detail = err?.data?.status?.detail || 'Unknown error';
|
44
|
-
// message.error(detail);
|
45
|
-
|
46
|
-
// return Promise.reject(err);
|
47
|
-
// },
|
48
|
-
// );
|
49
3
|
const api = {
|
50
|
-
|
51
|
-
|
52
|
-
getCaptchaKey: customPost('captcha/key'),
|
53
|
-
reSendCode: customPost('sms/send'),
|
4
|
+
getCaptchaKey: customPost('/messageVerify/admin/captcha/key'),
|
5
|
+
reSendCode: customPost('/admin/sms/send'),
|
54
6
|
getCaptchaImgUrl: (captchaKey: string) => {return `/messageVerify/admin/captcha/image/${captchaKey}`},
|
55
7
|
};
|
56
8
|
|
@@ -0,0 +1,23 @@
|
|
1
|
+
|
2
|
+
export type ModalConfig = {
|
3
|
+
data: string;
|
4
|
+
onClose?: () => void
|
5
|
+
config: {
|
6
|
+
headers: {
|
7
|
+
[key: string]: string | undefined;
|
8
|
+
};
|
9
|
+
[key: string]: unknown;
|
10
|
+
};
|
11
|
+
lang: 'zh' | 'en' | 'id';
|
12
|
+
http: {
|
13
|
+
(params: object): Promise<unknown>;
|
14
|
+
defaults: {
|
15
|
+
headers: {
|
16
|
+
common: {
|
17
|
+
[key: string]: unknown;
|
18
|
+
}
|
19
|
+
}
|
20
|
+
}
|
21
|
+
};
|
22
|
+
api?: string;
|
23
|
+
}
|
package/src/verify-modal.tsx
CHANGED
@@ -2,42 +2,34 @@ import { useEffect, useState } from 'react'
|
|
2
2
|
import { Modal, Input, Button, message } from './compoments/index.js'
|
3
3
|
import Api from './resource.js'
|
4
4
|
import t from './utils/i18n.js'
|
5
|
+
import { ModalConfig } from './utils/type.js';
|
6
|
+
import { axios } from '@yqg/resource';
|
5
7
|
|
6
|
-
type ModalConfig = {
|
7
|
-
data: string;
|
8
|
-
onClose?: () => void;
|
9
|
-
config: object;
|
10
|
-
lang: 'zh' | 'en' | 'id';
|
11
|
-
http: {
|
12
|
-
(params: object): Promise<unknown>;
|
13
|
-
defaults: {
|
14
|
-
headers: {
|
15
|
-
common: {
|
16
|
-
[key: string]: unknown;
|
17
|
-
}
|
18
|
-
}
|
19
|
-
}
|
20
|
-
};
|
21
|
-
}
|
22
8
|
const CreateMessageVerifyModal = ({ props }: { props: ModalConfig }) => {
|
23
|
-
|
24
9
|
const [visible, setVisible] = useState(true);
|
25
|
-
const [countdown, setCountdown] = useState(
|
10
|
+
const [countdown, setCountdown] = useState(60);
|
26
11
|
const [otp, setOtp] = useState('');
|
27
12
|
const [captchaImage, setCaptchaImage] = useState<string>('');
|
28
13
|
const [captchCode, setCaptchCode] = useState<string>('');
|
29
14
|
const [captchaKey, setCaptchaKey] = useState<string>('');
|
30
|
-
const { data, config, http, lang } = props || {};
|
15
|
+
const { data, config, http, lang, api='/admin/sms/send' } = props || {};
|
31
16
|
const dataObj = JSON.parse(data || '{}');
|
32
17
|
const { mobile, verifyCodeKey } = dataObj || {};
|
33
18
|
|
34
19
|
const getKey = async () => {
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
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);
|
41
33
|
}
|
42
34
|
}
|
43
35
|
|
@@ -58,8 +50,11 @@ const CreateMessageVerifyModal = ({ props }: { props: ModalConfig }) => {
|
|
58
50
|
|
59
51
|
const handleResend = async () => {
|
60
52
|
setCountdown(60);
|
61
|
-
const
|
62
|
-
|
53
|
+
const formData = new FormData();
|
54
|
+
formData.append('captchaKey', captchaKey);
|
55
|
+
formData.append('captcha', captchCode);
|
56
|
+
// 重新发送验证码
|
57
|
+
await axios.post(api, formData);
|
63
58
|
message.success(t('sendSuccess', lang));
|
64
59
|
}
|
65
60
|
|
@@ -80,10 +75,17 @@ const CreateMessageVerifyModal = ({ props }: { props: ModalConfig }) => {
|
|
80
75
|
value={otp}
|
81
76
|
onChange={(val) => {
|
82
77
|
setOtp(val);
|
78
|
+
console.log('打印Content-Type', config.headers['Content-Type'])
|
83
79
|
if (val.length === 6) {
|
84
|
-
http
|
85
|
-
|
86
|
-
|
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
|
+
});
|
87
89
|
setVisible(false);
|
88
90
|
}
|
89
91
|
}} />
|
package/vite.config.ts
CHANGED
@@ -15,8 +15,15 @@ export default defineConfig({
|
|
15
15
|
host: 'reconcile-test.yangqianguan.com', // 和转发url一样 host不带协议头 origin带上
|
16
16
|
origin: 'https://reconcile-test.yangqianguan.com'
|
17
17
|
},
|
18
|
-
|
19
18
|
},
|
19
|
+
'/admin': {
|
20
|
+
target: 'https://chidori-admin-test.yangqianguan.com',
|
21
|
+
changeOrigin: true,
|
22
|
+
headers: {
|
23
|
+
host: 'chidori-admin-test.yangqianguan.com', // 和转发url一样 host不带协议头 origin带上
|
24
|
+
origin: 'https://chidori-admin-test.yangqianguan.com'
|
25
|
+
},
|
26
|
+
}
|
20
27
|
},
|
21
28
|
},
|
22
29
|
build: {
|