message-verify 0.0.24-beta.0 → 0.0.25-beta.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.
- package/dist/app.d.ts +11 -0
- package/dist/app.js +53 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +5 -48
- package/dist/main.js +1 -1
- package/dist/resource.js +40 -2
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utils/status.d.ts +2 -0
- package/dist/utils/status.js +2 -0
- package/package.json +2 -1
- package/src/app.tsx +98 -0
- package/src/index.tsx +5 -78
- package/src/main.tsx +1 -1
- package/src/resource.ts +46 -2
- package/src/utils/status.ts +2 -0
- package/vite.config.ts +5 -1
- package/src/components/input.tsx +0 -35
- package/src/components/modal.tsx +0 -60
package/dist/app.d.ts
ADDED
package/dist/app.js
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
2
|
+
import { useEffect, useState } from 'react';
|
3
|
+
import { Input, Button, Modal, message } from 'antd';
|
4
|
+
import Api from './resource.js';
|
5
|
+
import '@ant-design/v5-patch-for-react-19';
|
6
|
+
const App = ({ data }) => {
|
7
|
+
const { mobile } = data || {};
|
8
|
+
const [countdown, setCountdown] = useState(3);
|
9
|
+
const [visible, setVisible] = useState(false);
|
10
|
+
const [captchaImage, setCaptchaImage] = useState('');
|
11
|
+
const [captchCode, setCaptchCode] = useState('');
|
12
|
+
const [captchaKey, setCaptchaKey] = useState('');
|
13
|
+
const getKey = async () => {
|
14
|
+
const res = await Api.getCaptchaKey();
|
15
|
+
const { body: key } = res.data || {};
|
16
|
+
setCaptchaKey(key);
|
17
|
+
if (key) {
|
18
|
+
console.log('res=>key', key);
|
19
|
+
const image = Api.getCaptchaImgUrl(key);
|
20
|
+
console.log('image', image);
|
21
|
+
setCaptchaImage(image);
|
22
|
+
}
|
23
|
+
};
|
24
|
+
useEffect(() => {
|
25
|
+
setVisible(true);
|
26
|
+
}, []);
|
27
|
+
useEffect(() => {
|
28
|
+
let timer = null;
|
29
|
+
if (visible && countdown > 0) {
|
30
|
+
timer = setInterval(() => {
|
31
|
+
setCountdown((prev) => prev - 1);
|
32
|
+
}, 1000);
|
33
|
+
}
|
34
|
+
if (countdown === 0) {
|
35
|
+
getKey();
|
36
|
+
}
|
37
|
+
return () => {
|
38
|
+
if (timer)
|
39
|
+
clearInterval(timer);
|
40
|
+
};
|
41
|
+
}, [visible, countdown]);
|
42
|
+
const handleResend = async () => {
|
43
|
+
setCountdown(60);
|
44
|
+
const res = await Api.reSendCode({ captchaKey, captcha: captchCode });
|
45
|
+
console.log('handleResend=>res', res);
|
46
|
+
message.success('发送成功');
|
47
|
+
};
|
48
|
+
console.log('captchCode', captchCode);
|
49
|
+
return (_jsxs(Modal, { open: visible, onClose: () => setVisible(false), width: 400, footer: _jsx(Button, { onClick: () => { }, children: "\u63D0\u4EA4" }), children: [_jsxs("div", { children: ["\u5DF2\u53D1\u9001\u77ED\u4FE1\u81F3\u60A8\u7684\u624B\u673A\uFF1A", mobile] }), countdown > 0 ? null : _jsxs("div", { style: { marginTop: 8, display: 'flex', alignItems: 'center', width: 300 }, children: [_jsx(Input, { onChange: (e) => {
|
50
|
+
setCaptchCode(e.target.value);
|
51
|
+
} }), captchaImage && _jsx("img", { src: captchaImage, alt: "\u9A8C\u8BC1\u7801", style: { width: 100, height: 30, marginLeft: 8 }, onClick: getKey })] }), countdown > 0 ? null : _jsx("div", { children: "\u8BF7\u8F93\u5165\u56FE\u5F62\u9A8C\u8BC1\u7801\u540E\uFF0C\u91CD\u65B0\u53D1\u9001\u9A8C\u8BC1\u7801" }), _jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 8, marginTop: 8 }, children: [_jsx(Input.OTP, { disabled: !captchCode, length: 6, onChange: (val) => { console.log('change', val); } }), _jsx(Button, { disabled: countdown > 0 || !captchCode, onClick: handleResend, children: countdown > 0 ? `${countdown}秒` : '重新发送' })] })] }));
|
52
|
+
};
|
53
|
+
export default App;
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
@@ -1,48 +1,5 @@
|
|
1
|
-
import {
|
2
|
-
import
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
const { mobile } = data || {};
|
7
|
-
const [countdown, setCountdown] = useState(60);
|
8
|
-
const [visible, setVisible] = useState(false);
|
9
|
-
const [captchaImage, setCaptchaImage] = useState('');
|
10
|
-
const getKey = async () => {
|
11
|
-
const res = await Api.getCaptchaKey();
|
12
|
-
console.log('res', res);
|
13
|
-
const image = await Api.getCaptchaImage({ captchaKey: res.data.key });
|
14
|
-
console.log('image', image);
|
15
|
-
setCaptchaImage(image);
|
16
|
-
};
|
17
|
-
// const retryModal = async(config, http) =>{
|
18
|
-
// console.log('retryModal=>config', config);
|
19
|
-
// config.headers['sms-code'] = 'new-value';
|
20
|
-
// // 3. 重新发起请求
|
21
|
-
// await http(config);
|
22
|
-
// // console.log('response', response);
|
23
|
-
// };
|
24
|
-
useEffect(() => {
|
25
|
-
setVisible(true);
|
26
|
-
}, []);
|
27
|
-
useEffect(() => {
|
28
|
-
let timer = null;
|
29
|
-
if (visible && countdown > 0) {
|
30
|
-
timer = setInterval(() => {
|
31
|
-
setCountdown((prev) => prev - 1);
|
32
|
-
}, 1000);
|
33
|
-
}
|
34
|
-
if (countdown === 0) {
|
35
|
-
getKey();
|
36
|
-
}
|
37
|
-
return () => {
|
38
|
-
if (timer)
|
39
|
-
clearInterval(timer);
|
40
|
-
};
|
41
|
-
}, [visible, countdown]);
|
42
|
-
const handleResend = async () => {
|
43
|
-
setCountdown(60);
|
44
|
-
// retryModal()
|
45
|
-
};
|
46
|
-
return (_jsx(_Fragment, { children: _jsxs(Modal, { open: visible, onClose: () => setVisible(false), okText: '提交', cancelText: false, children: [_jsxs("div", { children: ["\u5DF2\u53D1\u9001\u77ED\u4FE1\u81F3\u60A8\u7684\u624B\u673A\uFF1A", mobile] }), _jsxs("div", { style: { marginTop: 8, display: 'flex', alignItems: 'center', width: 300 }, children: [_jsx(Input, { disabled: countdown > 0 }), _jsx("img", { src: captchaImage, alt: "\u9A8C\u8BC1\u7801", style: { width: 100, height: 30, marginLeft: 8 }, onClick: getKey })] }), _jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 8, marginTop: 8 }, children: [_jsx(Input.OTP, { length: 6, onChange: (val) => { console.log('change', val); } }), _jsx(Button, { disabled: countdown > 0, onClick: handleResend, style: countdown > 0 ? { marginLeft: 8 } : { marginLeft: 8, backgroundColor: '#1677ff', color: '#fff' }, children: countdown > 0 ? `${countdown}秒` : '重新发送' })] })] }) }));
|
47
|
-
};
|
48
|
-
export default App;
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
2
|
+
import App from './app';
|
3
|
+
export function createMessageVerify(props) {
|
4
|
+
return _jsx(App, { ...props });
|
5
|
+
}
|
package/dist/main.js
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
2
2
|
import { createRoot } from 'react-dom/client';
|
3
|
-
import App from './
|
3
|
+
import App from './app.js'; // 或 './index'
|
4
4
|
createRoot(document.getElementById('root')).render(_jsx(App, { data: {
|
5
5
|
mobile: '185****7760',
|
6
6
|
verifyCodeKey: 'e381c5f9-c7f4-4bf1-a948-744334fb0203',
|
package/dist/resource.js
CHANGED
@@ -1,9 +1,47 @@
|
|
1
|
-
import { assign,
|
1
|
+
import { assign, axios as instance, customPost } from '@yqg/resource';
|
2
2
|
const urlPrefix = '/admin/';
|
3
|
+
import { message } from 'antd';
|
4
|
+
import { YQG_SUCCESS } from './utils/status';
|
5
|
+
// axios.defaults.headers.common['Access-Control-Allow-Origin'] = '*';
|
6
|
+
instance.interceptors.response.use((res) => {
|
7
|
+
const { status } = res?.data || {};
|
8
|
+
const { code, detail } = status || {};
|
9
|
+
if (res?.config?.responseType === 'blob') {
|
10
|
+
if (res?.data?.type === 'application/json') {
|
11
|
+
// 没有拿到文件时,将拿到的 blob 流转为 js 对象,进而拿到错误信息(detail)并返回 reject 状态
|
12
|
+
// 不处理将默认下载一个 json 文件
|
13
|
+
const reader = new FileReader();
|
14
|
+
reader.readAsText(res.data, 'utf-8');
|
15
|
+
reader.onload = () => {
|
16
|
+
const parsedObj = JSON.parse(reader.result);
|
17
|
+
message.info(parsedObj?.status?.detail);
|
18
|
+
};
|
19
|
+
return Promise.reject();
|
20
|
+
}
|
21
|
+
else {
|
22
|
+
return res;
|
23
|
+
}
|
24
|
+
}
|
25
|
+
if (res.headers && res.headers['content-type'] === 'image/jpeg') {
|
26
|
+
return res;
|
27
|
+
}
|
28
|
+
switch (code) {
|
29
|
+
case YQG_SUCCESS:
|
30
|
+
return Promise.resolve(res);
|
31
|
+
default: {
|
32
|
+
message.error(detail);
|
33
|
+
return Promise.reject(res);
|
34
|
+
}
|
35
|
+
}
|
36
|
+
}, (err) => {
|
37
|
+
const detail = err?.data?.status?.detail || 'Unknown error';
|
38
|
+
message.error(detail);
|
39
|
+
return Promise.reject(err);
|
40
|
+
});
|
3
41
|
const api = {
|
4
42
|
urlPrefix,
|
5
43
|
getCaptchaKey: customPost('captcha/key'),
|
6
44
|
reSendCode: customPost('sms/send'),
|
7
|
-
getCaptchaImgUrl:
|
45
|
+
getCaptchaImgUrl: (captchaKey) => { return `/admin/captcha/image/${captchaKey}`; },
|
8
46
|
};
|
9
47
|
export default assign(api);
|
@@ -1 +1 @@
|
|
1
|
-
{"root":["../src/index.tsx","../src/main.tsx","../src/resource.ts","../src/vite-env.d.ts","../src/
|
1
|
+
{"root":["../src/app.tsx","../src/index.tsx","../src/main.tsx","../src/resource.ts","../src/vite-env.d.ts","../src/utils/getfingerprint.ts","../src/utils/index.ts","../src/utils/status.ts"],"version":"5.7.3"}
|
package/package.json
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
{
|
2
2
|
"name": "message-verify",
|
3
|
-
"version": "0.0.
|
3
|
+
"version": "0.0.25-beta.0",
|
4
4
|
"type": "module",
|
5
5
|
"main": "dist/index.js",
|
6
6
|
"dependencies": {
|
7
|
+
"@ant-design/v5-patch-for-react-19": "^1.0.3",
|
7
8
|
"@fingerprintjs/fingerprintjs": "^4.6.2",
|
8
9
|
"@yqg/resource": "^1.3.8",
|
9
10
|
"antd": "^5.24.8",
|
package/src/app.tsx
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
import { useEffect, useState } from 'react'
|
2
|
+
import { Input, Button, Modal, message } from 'antd';
|
3
|
+
import Api from './resource.js'
|
4
|
+
import '@ant-design/v5-patch-for-react-19';
|
5
|
+
|
6
|
+
interface Props {
|
7
|
+
data: {
|
8
|
+
mobile: string;
|
9
|
+
verifyCodeKey: string;
|
10
|
+
sendSuccess: boolean;
|
11
|
+
};
|
12
|
+
refresh: () => void;
|
13
|
+
}
|
14
|
+
const App: React.FC<Props> = ({ data }) => {
|
15
|
+
const { mobile } = data || {};
|
16
|
+
const [countdown, setCountdown] = useState(3);
|
17
|
+
const [visible, setVisible] = useState(false);
|
18
|
+
const [captchaImage, setCaptchaImage] = useState<string>('');
|
19
|
+
const [captchCode, setCaptchCode] = useState<string>('');
|
20
|
+
const [captchaKey, setCaptchaKey] = useState<string>('');
|
21
|
+
|
22
|
+
const getKey = async () => {
|
23
|
+
const res = await Api.getCaptchaKey();
|
24
|
+
const { body: key } = res.data || {};
|
25
|
+
setCaptchaKey(key);
|
26
|
+
if(key) {
|
27
|
+
console.log('res=>key', key);
|
28
|
+
const image = Api.getCaptchaImgUrl(key) as unknown;
|
29
|
+
console.log('image', image);
|
30
|
+
setCaptchaImage(image as string);
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
useEffect(() => {
|
35
|
+
setVisible(true);
|
36
|
+
}, [])
|
37
|
+
|
38
|
+
useEffect(() => {
|
39
|
+
let timer: number | null = null;
|
40
|
+
if (visible && countdown > 0) {
|
41
|
+
timer = setInterval(() => {
|
42
|
+
setCountdown((prev) => prev - 1);
|
43
|
+
}, 1000);
|
44
|
+
}
|
45
|
+
if (countdown === 0) {
|
46
|
+
getKey();
|
47
|
+
}
|
48
|
+
return () => {
|
49
|
+
if (timer) clearInterval(timer);
|
50
|
+
};
|
51
|
+
}, [visible, countdown]);
|
52
|
+
|
53
|
+
const handleResend = async() => {
|
54
|
+
setCountdown(60);
|
55
|
+
const res = await Api.reSendCode({captchaKey, captcha: captchCode});
|
56
|
+
console.log('handleResend=>res', res);
|
57
|
+
message.success('发送成功');
|
58
|
+
}
|
59
|
+
|
60
|
+
console.log('captchCode', captchCode);
|
61
|
+
return (
|
62
|
+
<Modal
|
63
|
+
open={visible}
|
64
|
+
onClose={() => setVisible(false)}
|
65
|
+
width={400}
|
66
|
+
footer={
|
67
|
+
<Button onClick={() => {/* 提交逻辑 */}}>
|
68
|
+
提交
|
69
|
+
</Button>
|
70
|
+
}
|
71
|
+
>
|
72
|
+
<div>已发送短信至您的手机:{mobile}</div>
|
73
|
+
{countdown > 0 ? null : <div style={{ marginTop: 8, display: 'flex', alignItems: 'center', width: 300 }}>
|
74
|
+
<Input onChange={(e) => {
|
75
|
+
setCaptchCode(e.target.value as string)
|
76
|
+
}} />
|
77
|
+
|
78
|
+
{captchaImage && <img src={captchaImage} alt="验证码" style={{ width: 100, height: 30, marginLeft: 8 }} onClick={getKey} />}
|
79
|
+
</div>}
|
80
|
+
{countdown > 0 ? null : <div>请输入图形验证码后,重新发送验证码</div>}
|
81
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 8 }}>
|
82
|
+
<Input.OTP
|
83
|
+
disabled={!captchCode}
|
84
|
+
length={6}
|
85
|
+
onChange={(val) => {console.log('change', val)}}
|
86
|
+
/>
|
87
|
+
<Button
|
88
|
+
disabled={countdown > 0 || !captchCode}
|
89
|
+
onClick={handleResend}
|
90
|
+
>
|
91
|
+
{countdown > 0 ? `${countdown}秒` : '重新发送'}
|
92
|
+
</Button>
|
93
|
+
</div>
|
94
|
+
</Modal>
|
95
|
+
)
|
96
|
+
}
|
97
|
+
|
98
|
+
export default App;
|
package/src/index.tsx
CHANGED
@@ -1,6 +1,5 @@
|
|
1
|
-
import
|
2
|
-
|
3
|
-
import Api from './resource.js'
|
1
|
+
import App from './app';
|
2
|
+
|
4
3
|
interface Props {
|
5
4
|
data: {
|
6
5
|
mobile: string;
|
@@ -8,80 +7,8 @@ interface Props {
|
|
8
7
|
sendSuccess: boolean;
|
9
8
|
};
|
10
9
|
refresh: () => void;
|
11
|
-
// axios: any;
|
12
|
-
}
|
13
|
-
const App: React.FC<Props> = ({ data }) => {
|
14
|
-
const { mobile } = data || {};
|
15
|
-
const [countdown, setCountdown] = useState(60);
|
16
|
-
const [visible, setVisible] = useState(false);
|
17
|
-
const [captchaImage, setCaptchaImage] = useState('');
|
18
|
-
|
19
|
-
const getKey = async () => {
|
20
|
-
const res = await Api.getCaptchaKey();
|
21
|
-
console.log('res', res);
|
22
|
-
const image = await Api.getCaptchaImage({ captchaKey: res.data.key });
|
23
|
-
console.log('image', image);
|
24
|
-
setCaptchaImage(image);
|
25
|
-
}
|
26
|
-
|
27
|
-
// const retryModal = async(config, http) =>{
|
28
|
-
// console.log('retryModal=>config', config);
|
29
|
-
// config.headers['sms-code'] = 'new-value';
|
30
|
-
|
31
|
-
// // 3. 重新发起请求
|
32
|
-
// await http(config);
|
33
|
-
// // console.log('response', response);
|
34
|
-
// };
|
35
|
-
|
36
|
-
useEffect(() => {
|
37
|
-
setVisible(true);
|
38
|
-
}, [])
|
39
|
-
|
40
|
-
useEffect(() => {
|
41
|
-
let timer: number | null = null;
|
42
|
-
if (visible && countdown > 0) {
|
43
|
-
timer = setInterval(() => {
|
44
|
-
setCountdown((prev) => prev - 1);
|
45
|
-
}, 1000);
|
46
|
-
}
|
47
|
-
if (countdown === 0) {
|
48
|
-
getKey();
|
49
|
-
}
|
50
|
-
return () => {
|
51
|
-
if (timer) clearInterval(timer);
|
52
|
-
};
|
53
|
-
}, [visible, countdown]);
|
54
|
-
|
55
|
-
const handleResend = async() => {
|
56
|
-
setCountdown(60);
|
57
|
-
// retryModal()
|
58
|
-
}
|
59
|
-
|
60
|
-
return (
|
61
|
-
<>
|
62
|
-
<Modal
|
63
|
-
open={visible}
|
64
|
-
onClose={() => setVisible(false)}
|
65
|
-
okText={'提交'}
|
66
|
-
cancelText={false}
|
67
|
-
>
|
68
|
-
<div>已发送短信至您的手机:{mobile}</div>
|
69
|
-
<div style={{ marginTop: 8, display: 'flex', alignItems: 'center', width: 300 }}>
|
70
|
-
<Input disabled={countdown > 0} />
|
71
|
-
<img src={captchaImage} alt="验证码" style={{ width: 100, height: 30, marginLeft: 8 }} onClick={getKey} />
|
72
|
-
</div>
|
73
|
-
<div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 8 }}>
|
74
|
-
<Input.OTP length={6} onChange={(val) => {console.log('change', val)}} />
|
75
|
-
<Button
|
76
|
-
disabled={countdown > 0}
|
77
|
-
onClick={handleResend}
|
78
|
-
style={countdown > 0 ? { marginLeft: 8 } : { marginLeft: 8, backgroundColor: '#1677ff', color: '#fff' }}
|
79
|
-
// btnText={countdown > 0 ? `${countdown}秒` : '重新发送'}
|
80
|
-
>{countdown > 0 ? `${countdown}秒` : '重新发送'}</Button>
|
81
|
-
</div>
|
82
|
-
</Modal>
|
83
|
-
</>
|
84
|
-
)
|
85
10
|
}
|
86
11
|
|
87
|
-
export
|
12
|
+
export function createMessageVerify(props: Props) {
|
13
|
+
return <App {...props} />;
|
14
|
+
}
|
package/src/main.tsx
CHANGED
package/src/resource.ts
CHANGED
@@ -1,12 +1,56 @@
|
|
1
|
-
import { assign,
|
1
|
+
import { assign, axios as instance, customPost } from '@yqg/resource';
|
2
2
|
const urlPrefix = '/admin/';
|
3
|
+
import { message } from 'antd';
|
4
|
+
import { YQG_SUCCESS } from './utils/status';
|
3
5
|
|
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
|
+
|
22
|
+
return Promise.reject();
|
23
|
+
} else {
|
24
|
+
return res;
|
25
|
+
}
|
26
|
+
}
|
27
|
+
|
28
|
+
if (res.headers && res.headers['content-type'] === 'image/jpeg') {
|
29
|
+
return res;
|
30
|
+
}
|
31
|
+
|
32
|
+
switch (code) {
|
33
|
+
case YQG_SUCCESS:
|
34
|
+
return Promise.resolve(res);
|
35
|
+
default: {
|
36
|
+
message.error(detail);
|
37
|
+
return Promise.reject(res);
|
38
|
+
}
|
39
|
+
}
|
40
|
+
},
|
41
|
+
(err: {data: {status: {detail: string}}}) => {
|
42
|
+
const detail = err?.data?.status?.detail || 'Unknown error';
|
43
|
+
message.error(detail);
|
44
|
+
|
45
|
+
return Promise.reject(err);
|
46
|
+
},
|
47
|
+
);
|
4
48
|
const api = {
|
5
49
|
urlPrefix,
|
6
50
|
|
7
51
|
getCaptchaKey: customPost('captcha/key'),
|
8
52
|
reSendCode: customPost('sms/send'),
|
9
|
-
getCaptchaImgUrl:
|
53
|
+
getCaptchaImgUrl: (captchaKey: string) => {return `/admin/captcha/image/${captchaKey}`},
|
10
54
|
};
|
11
55
|
|
12
56
|
export default assign(api);
|
package/vite.config.ts
CHANGED
@@ -11,7 +11,11 @@ export default defineConfig({
|
|
11
11
|
'/admin': {
|
12
12
|
target: 'https://chidori-admin-test.yangqianguan.com',
|
13
13
|
changeOrigin: true,
|
14
|
-
|
14
|
+
headers: {
|
15
|
+
host: 'chidori-admin-test.yangqianguan.com', // 和转发url一样 host不带协议头 origin带上
|
16
|
+
origin: 'http://chidori-admin-test.yangqianguan.com'
|
17
|
+
},
|
18
|
+
|
15
19
|
},
|
16
20
|
},
|
17
21
|
},
|
package/src/components/input.tsx
DELETED
@@ -1,35 +0,0 @@
|
|
1
|
-
import React from 'react';
|
2
|
-
|
3
|
-
interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
|
4
|
-
placeholder?: string;
|
5
|
-
}
|
6
|
-
|
7
|
-
const inputStyle: React.CSSProperties = {
|
8
|
-
padding: '8px 12px',
|
9
|
-
border: '1px solid #ccc',
|
10
|
-
borderRadius: 4,
|
11
|
-
fontSize: 16,
|
12
|
-
outline: 'none',
|
13
|
-
transition: 'border-color 0.2s',
|
14
|
-
};
|
15
|
-
|
16
|
-
const Input: React.FC<InputProps> = (props) => {
|
17
|
-
const { placeholder = '请输入' } = props;
|
18
|
-
return (
|
19
|
-
<input
|
20
|
-
style={inputStyle}
|
21
|
-
placeholder={placeholder}
|
22
|
-
{...props}
|
23
|
-
onFocus={e => {
|
24
|
-
props.onFocus?.(e);
|
25
|
-
(e.target as HTMLInputElement).style.borderColor = '#1677ff';
|
26
|
-
}}
|
27
|
-
onBlur={e => {
|
28
|
-
props.onBlur?.(e);
|
29
|
-
(e.target as HTMLInputElement).style.borderColor = '#ccc';
|
30
|
-
}}
|
31
|
-
/>
|
32
|
-
);
|
33
|
-
};
|
34
|
-
|
35
|
-
export default Input;
|
package/src/components/modal.tsx
DELETED
@@ -1,60 +0,0 @@
|
|
1
|
-
import React from 'react';
|
2
|
-
|
3
|
-
interface ModalProps {
|
4
|
-
visible: boolean;
|
5
|
-
onClose: () => void;
|
6
|
-
children: React.ReactNode;
|
7
|
-
}
|
8
|
-
|
9
|
-
const modalStyle: React.CSSProperties = {
|
10
|
-
position: 'fixed',
|
11
|
-
top: 0,
|
12
|
-
left: 0,
|
13
|
-
width: '100vw',
|
14
|
-
height: '100vh',
|
15
|
-
background: 'rgba(0,0,0,0.3)',
|
16
|
-
display: 'flex',
|
17
|
-
alignItems: 'center',
|
18
|
-
justifyContent: 'center',
|
19
|
-
zIndex: 1000,
|
20
|
-
};
|
21
|
-
|
22
|
-
const contentStyle: React.CSSProperties = {
|
23
|
-
position: 'relative',
|
24
|
-
background: '#fff',
|
25
|
-
borderRadius: 8,
|
26
|
-
padding: 24,
|
27
|
-
minWidth: 320,
|
28
|
-
minHeight: 120,
|
29
|
-
boxShadow: '0 2px 8px rgba(0,0,0,0.15)',
|
30
|
-
};
|
31
|
-
|
32
|
-
const closeBtnStyle: React.CSSProperties = {
|
33
|
-
position: 'absolute',
|
34
|
-
top: 12,
|
35
|
-
right: 12,
|
36
|
-
width: 24,
|
37
|
-
height: 24,
|
38
|
-
border: 'none',
|
39
|
-
background: 'transparent',
|
40
|
-
fontSize: 20,
|
41
|
-
cursor: 'pointer',
|
42
|
-
lineHeight: 1,
|
43
|
-
};
|
44
|
-
|
45
|
-
const Modal: React.FC<ModalProps> = ({ visible, onClose, children }) => {
|
46
|
-
if (!visible) return null;
|
47
|
-
|
48
|
-
return (
|
49
|
-
<div style={modalStyle}>
|
50
|
-
<div style={contentStyle}>
|
51
|
-
<button style={closeBtnStyle} onClick={onClose} aria-label="关闭">
|
52
|
-
×
|
53
|
-
</button>
|
54
|
-
{children}
|
55
|
-
</div>
|
56
|
-
</div>
|
57
|
-
);
|
58
|
-
};
|
59
|
-
|
60
|
-
export default Modal;
|