Yansen 1年前
父节点
当前提交
ea1a044d74
共有 5 个文件被更改,包括 156 次插入2 次删除
  1. 27
    0
      src/components/Captcha/CaptchaImage.jsx
  2. 65
    0
      src/components/Captcha/index.jsx
  3. 24
    2
      src/pages/user/Login/index.jsx
  4. 13
    0
      src/services/login.js
  5. 27
    0
      src/utils/request.js

+ 27
- 0
src/components/Captcha/CaptchaImage.jsx 查看文件

@@ -0,0 +1,27 @@
1
+import React from 'react';
2
+import { Spin } from 'antd';
3
+import { useRequest } from '@/utils/request';
4
+import { getCaptchaImage } from '@/services/login';
5
+
6
+export default (props) => {
7
+  const { onChange, ...leftProps } = props;
8
+
9
+  const [info, setInfo] = React.useState();
10
+  const [loading, getCaptcha] = useRequest(getCaptchaImage, setInfo);
11
+
12
+  React.useEffect(() => {
13
+    getCaptcha();
14
+  }, []);
15
+
16
+  React.useEffect(() => {
17
+    if (onChange) {
18
+      onChange(info);
19
+    }
20
+  }, [info]);
21
+
22
+  return (
23
+    <Spin spinning={loading}>
24
+      <img src={info?.image} onClick={getCaptcha} {...leftProps} />
25
+    </Spin>
26
+  );
27
+};

+ 65
- 0
src/components/Captcha/index.jsx 查看文件

@@ -0,0 +1,65 @@
1
+import React from 'react';
2
+import classNames from 'classnames';
3
+import { SyncOutlined, CheckCircleTwoTone, CloseCircleTwoTone } from '@ant-design/icons';
4
+import { Input } from 'antd';
5
+import { checkCaptch } from '@/services/login';
6
+import CaptchaImage from './CaptchaImage';
7
+
8
+export default (props) => {
9
+  const { style, className, onChange, onBlur, ...leftProps } = props;
10
+
11
+  const [captcha, setCaptcha] = React.useState();
12
+  const [value, setValue] = React.useState();
13
+  const [isOk, setIsOk] = React.useState(-1);
14
+
15
+  const handleChange = (e) => {
16
+    setValue(e.target.value);
17
+  };
18
+
19
+  const handleBlur = (e) => {
20
+    if (onBlur) {
21
+      onBlur(e);
22
+    }
23
+
24
+    checkCaptch({ id: captcha?.id, value }).then((res) => {
25
+      setIsOk(res);
26
+    });
27
+  };
28
+
29
+  const onCaptchaChange = (e) => {
30
+    setIsOk(-1);
31
+    setValue();
32
+    setCaptcha(e);
33
+  };
34
+
35
+  React.useEffect(() => {
36
+    if (onChange) {
37
+      onChange({
38
+        id: captcha?.id,
39
+        value,
40
+      });
41
+    }
42
+  }, [value, captcha]);
43
+
44
+  return (
45
+    <div className={classNames(className, 'flex', 'v-center')} style={style}>
46
+      <div className="flex-1">
47
+        <Input
48
+          allowClear
49
+          {...leftProps}
50
+          value={value}
51
+          onChange={handleChange}
52
+          onBlur={handleBlur}
53
+        />
54
+      </div>
55
+      <div className="flex-0" style={{ width: '130px', marginLeft: '8px' }}>
56
+        <CaptchaImage onChange={onCaptchaChange} />
57
+      </div>
58
+      <div className="flex-0" style={{ width: '24px', marginLeft: '8px' }}>
59
+        {isOk === -1 && <SyncOutlined style={{ fontSize: '16px', color: '#096dd9' }} />}
60
+        {isOk === 1 && <CheckCircleTwoTone twoToneColor="#00ff00" style={{ fontSize: '18px' }} />}
61
+        {isOk === 0 && <CloseCircleTwoTone twoToneColor="#ff0000" style={{ fontSize: '18px' }} />}
62
+      </div>
63
+    </div>
64
+  );
65
+};

+ 24
- 2
src/pages/user/Login/index.jsx 查看文件

@@ -1,9 +1,10 @@
1
-import { LockOutlined, UserOutlined } from '@ant-design/icons';
1
+import { LockOutlined, UserOutlined, SafetyCertificateOutlined } from '@ant-design/icons';
2 2
 import { Alert, message, Tabs } from 'antd';
3 3
 import React, { useState } from 'react';
4 4
 import md5 from 'md5';
5 5
 import ProForm, { ProFormText } from '@ant-design/pro-form';
6 6
 import { useIntl, Link, history, FormattedMessage, SelectLang, useModel } from 'umi';
7
+import Captcha from '@/components/Captcha';
7 8
 import Footer from '@/components/Footer';
8 9
 import { login } from '@/services/login';
9 10
 import styles from './index.less';
@@ -116,8 +117,29 @@ const Login = () => {
116 117
                   ),
117 118
                 },
118 119
               ]}
119
-
120 120
             />
121
+
122
+            <ProForm.Item
123
+              name="captcha"
124
+              placeholder="验证码"
125
+              rules={[
126
+                {
127
+                  required: true,
128
+                  message: (
129
+                    <FormattedMessage
130
+                      id="pages.login.captcha.required"
131
+                      defaultMessage="请输入验证码!"
132
+                    />
133
+                  ),
134
+                },
135
+              ]}
136
+            >
137
+              <Captcha
138
+                prefix={<SafetyCertificateOutlined />}
139
+                size="large"
140
+                placeholder="请输入验证码"
141
+              />
142
+            </ProForm.Item>
121 143
           </ProForm>
122 144
         </div>
123 145
       </div>

+ 13
- 0
src/services/login.js 查看文件

@@ -1,3 +1,16 @@
1 1
 import request from '@/utils/request';
2 2
 
3 3
 export const login = (data) => request('/login', { method: 'post', data });
4
+
5
+/**
6
+ * 获取验证码
7
+ * @returns
8
+ */
9
+export const getCaptchaImage = (admin) => request(`/captcha`);
10
+
11
+/**
12
+ * 校验验证码
13
+ * @param {*} data
14
+ * @returns
15
+ */
16
+export const checkCaptch = (data) => request(`/captcha`, { data, method: 'post', silent: 1 });

+ 27
- 0
src/utils/request.js 查看文件

@@ -1,3 +1,4 @@
1
+import React from 'react';
1 2
 import { request } from 'umi';
2 3
 import { downloadBlob } from './download';
3 4
 
@@ -99,3 +100,29 @@ export function queryTable(apiRequest) {
99 100
       });
100 101
   };
101 102
 }
103
+
104
+export function useRequest(fn, onSuccess, onError) {
105
+  const [loading, setLoading] = React.useState(false);
106
+
107
+  const p = (...args) =>
108
+    new Promise((resolve, reject) => {
109
+      setLoading(true);
110
+      fn(...args)
111
+        .then((res) => {
112
+          setLoading(false);
113
+          if (onSuccess) {
114
+            onSuccess(res);
115
+          }
116
+          resolve(res);
117
+        })
118
+        .catch((e) => {
119
+          setLoading(false);
120
+          if (onError) {
121
+            onError(e);
122
+          }
123
+          reject(e);
124
+        });
125
+    });
126
+
127
+  return [loading, p];
128
+}