[baozhangchao] 3 jaren geleden
bovenliggende
commit
691e5178f9

+ 5
- 8
.eslintrc.js Bestand weergeven

@@ -1,11 +1,8 @@
1 1
 module.exports = {
2
-  parserOptions: {
3
-    ecmaVersion: 7,
4
-    sourceType: 'module',
5
-    ecmaFeatures: {
6
-      experimentalObjectRestSpread: true,
7
-      jsx: true,
8
-    },
2
+  extends: [require.resolve('@umijs/fabric/dist/eslint')],
3
+  globals: {
4
+    ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: true,
5
+    page: true,
6
+    REACT_APP_ENV: true,
9 7
   },
10
-  parser: 'babel-eslint',
11 8
 };

+ 0
- 1
.npmrc Bestand weergeven

@@ -1 +0,0 @@
1
-registry=https://registry.npmmirror.com

+ 57
- 0
README.md Bestand weergeven

@@ -0,0 +1,57 @@
1
+# Ant Design Pro
2
+
3
+This project is initialized with [Ant Design Pro](https://pro.ant.design). Follow is the quick guide for how to use.
4
+
5
+## Environment Prepare
6
+
7
+Install `node_modules`:
8
+
9
+```bash
10
+npm install
11
+```
12
+
13
+or
14
+
15
+```bash
16
+yarn
17
+```
18
+
19
+## Provided Scripts
20
+
21
+Ant Design Pro provides some useful script to help you quick start and build with web project, code style check and test.
22
+
23
+Scripts provided in `package.json`. It's safe to modify or add additional script:
24
+
25
+### Start project
26
+
27
+```bash
28
+npm start
29
+```
30
+
31
+### Build project
32
+
33
+```bash
34
+npm run build
35
+```
36
+
37
+### Check code style
38
+
39
+```bash
40
+npm run lint
41
+```
42
+
43
+You can also use script to auto fix some lint error:
44
+
45
+```bash
46
+npm run lint:fix
47
+```
48
+
49
+### Test code
50
+
51
+```bash
52
+npm test
53
+```
54
+
55
+## More
56
+
57
+You can view full document on our [official website](https://pro.ant.design). And welcome any feedback in our [github](https://github.com/ant-design/ant-design-pro).

+ 1
- 5
config/config.js Bestand weergeven

@@ -1,20 +1,16 @@
1 1
 // https://umijs.org/config/
2 2
 import { defineConfig } from 'umi';
3
-import { join, resolve } from 'path';
3
+import { join } from 'path';
4 4
 import defaultSettings from './defaultSettings';
5 5
 import proxy from './proxy';
6 6
 import routes from './routes';
7 7
 const { REACT_APP_ENV } = process.env;
8 8
 export default defineConfig({
9
-  history: { type: 'hash' },
10 9
   hash: true,
11 10
   antd: {},
12 11
   dva: {
13 12
     hmr: true,
14 13
   },
15
-  alias: {
16
-    '@': resolve('src'),
17
-  },
18 14
   layout: {
19 15
     // https://umijs.org/zh-CN/plugins/plugin-layout
20 16
     locale: true,

+ 1
- 4
config/defaultSettings.js Bestand weergeven

@@ -7,12 +7,9 @@ const Settings = {
7 7
   fixedHeader: false,
8 8
   fixSiderbar: true,
9 9
   colorWeak: false,
10
-  title: '智慧农用机管理平台',
10
+  title: 'Ant Design Pro',
11 11
   pwa: false,
12 12
   logo: 'https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg',
13 13
   iconfontUrl: '',
14
-  menu: {
15
-    locale: false,
16
-  },
17 14
 };
18 15
 export default Settings;

+ 1
- 1
config/proxy.js Bestand weergeven

@@ -11,7 +11,7 @@ export default {
11 11
     // localhost:8000/api/** -> https://preview.pro.ant.design/api/**
12 12
     '/api/': {
13 13
       // 要代理的地址
14
-      target: 'http://sgl-v2-test.njyunzhi.com',
14
+      target: 'https://preview.pro.ant.design',
15 15
       // 配置了这个可以从 http 代理到 https
16 16
       // 依赖 origin 的功能可能需要这个,比如 cookie
17 17
       changeOrigin: true,

+ 2
- 4
config/routes.js Bestand weergeven

@@ -1,5 +1,3 @@
1
-import BasicLayout from '../src/layouts/BasicLayout';
2
-
3 1
 export default [
4 2
   {
5 3
     path: '/user',
@@ -22,8 +20,8 @@ export default [
22 20
   },
23 21
   {
24 22
     path: '/welcome',
25
-    name: '工作台',
26
-    icon: 'DashboardOutlined',
23
+    name: 'welcome',
24
+    icon: 'smile',
27 25
     component: './Welcome',
28 26
   },
29 27
   {

+ 1
- 1
mock/user.js Bestand weergeven

@@ -118,7 +118,7 @@ export default {
118 118
   'POST /api/login/account': async (req, res) => {
119 119
     const { password, username, type } = req.body;
120 120
     await waitTime(2000);
121
-    console.log(666);
121
+
122 122
     if (password === 'ant.design' && username === 'admin') {
123 123
       res.send({
124 124
         status: 'ok',

+ 5
- 16
package.json Bestand weergeven

@@ -37,15 +37,9 @@
37 37
   "lint-staged": {
38 38
     "**/*.less": "stylelint --syntax less",
39 39
     "**/*.{js,jsx,ts,tsx}": "npm run lint-staged:js",
40
-    "**/*.{js,jsx,tsx,ts,less,md,json}": [
41
-      "prettier --write"
42
-    ]
40
+    "**/*.{js,jsx,tsx,ts,less,md,json}": ["prettier --write"]
43 41
   },
44
-  "browserslist": [
45
-    "> 1%",
46
-    "last 2 versions",
47
-    "not ie <= 10"
48
-  ],
42
+  "browserslist": ["> 1%", "last 2 versions", "not ie <= 10"],
49 43
   "dependencies": {
50 44
     "@ant-design/icons": "^4.7.0",
51 45
     "@ant-design/pro-descriptions": "^1.10.0",
@@ -56,7 +50,6 @@
56 50
     "antd": "^4.17.0",
57 51
     "classnames": "^2.3.0",
58 52
     "lodash": "^4.17.0",
59
-    "md5": "^2.3.0",
60 53
     "moment": "^2.29.0",
61 54
     "omit.js": "^2.0.2",
62 55
     "rc-menu": "^9.1.0",
@@ -65,7 +58,7 @@
65 58
     "react-dev-inspector": "^1.7.0",
66 59
     "react-dom": "^17.0.0",
67 60
     "react-helmet-async": "^1.2.0",
68
-    "umi": "^3.5.15"
61
+    "umi": "^3.5.0"
69 62
   },
70 63
   "devDependencies": {
71 64
     "@ant-design/pro-cli": "^2.1.0",
@@ -104,10 +97,6 @@
104 97
     "typescript": "^4.5.0",
105 98
     "umi-serve": "^1.9.10"
106 99
   },
107
-  "engines": {
108
-    "node": ">=10.0.0"
109
-  },
110
-  "gitHooks": {
111
-    "commit-msg": "fabric verify-commit"
112
-  }
100
+  "engines": { "node": ">=10.0.0" },
101
+  "gitHooks": { "commit-msg": "fabric verify-commit" }
113 102
 }

+ 28
- 9
src/app.jsx Bestand weergeven

@@ -1,10 +1,11 @@
1
+import { SettingDrawer } from '@ant-design/pro-layout';
1 2
 import { PageLoading } from '@ant-design/pro-layout';
2 3
 import { history, Link } from 'umi';
3 4
 import RightContent from '@/components/RightContent';
4 5
 import Footer from '@/components/Footer';
5 6
 import { currentUser as queryCurrentUser } from './services/ant-design-pro/api';
6
-import { requestConfig } from '@/utils/request';
7 7
 import { BookOutlined, LinkOutlined } from '@ant-design/icons';
8
+import defaultSettings from '../config/defaultSettings';
8 9
 const isDev = process.env.NODE_ENV === 'development';
9 10
 const loginPath = '/user/login';
10 11
 /** 获取用户信息比较慢的时候会展示一个 loading */
@@ -19,8 +20,8 @@ export const initialStateConfig = {
19 20
 export async function getInitialState() {
20 21
   const fetchUserInfo = async () => {
21 22
     try {
22
-      const { user } = await queryCurrentUser();
23
-      return user;
23
+      const msg = await queryCurrentUser();
24
+      return msg.data;
24 25
     } catch (error) {
25 26
       history.push(loginPath);
26 27
     }
@@ -33,21 +34,23 @@ export async function getInitialState() {
33 34
     return {
34 35
       fetchUserInfo,
35 36
       currentUser,
36
-      settings: {},
37
+      settings: defaultSettings,
37 38
     };
38 39
   }
39 40
 
40 41
   return {
41 42
     fetchUserInfo,
42
-    settings: {},
43
+    settings: defaultSettings,
43 44
   };
44 45
 } // ProLayout 支持的api https://procomponents.ant.design/components/layout
45 46
 
46
-export const layout = ({ initialState }) => {
47
+export const layout = ({ initialState, setInitialState }) => {
47 48
   return {
48 49
     rightContentRender: () => <RightContent />,
49 50
     disableContentMargin: false,
50
-
51
+    waterMarkProps: {
52
+      content: initialState?.currentUser?.name,
53
+    },
51 54
     footerRender: () => <Footer />,
52 55
     onPageChange: () => {
53 56
       const { location } = history; // 如果没有登录,重定向到 login
@@ -71,8 +74,24 @@ export const layout = ({ initialState }) => {
71 74
     menuHeaderRender: undefined,
72 75
     // 自定义 403 页面
73 76
     // unAccessible: <div>unAccessible</div>,
77
+    // 增加一个 loading 的状态
78
+    childrenRender: (children, props) => {
79
+      // if (initialState?.loading) return <PageLoading />;
80
+      return (
81
+        <>
82
+          {children}
83
+          {!props.location?.pathname?.includes('/login') && (
84
+            <SettingDrawer
85
+              enableDarkTheme
86
+              settings={initialState?.settings}
87
+              onSettingChange={(settings) => {
88
+                setInitialState((preInitialState) => ({ ...preInitialState, settings }));
89
+              }}
90
+            />
91
+          )}
92
+        </>
93
+      );
94
+    },
74 95
     ...initialState?.settings,
75 96
   };
76 97
 };
77
-
78
-export const request = requestConfig;

+ 36
- 5
src/components/Footer/index.jsx Bestand weergeven

@@ -1,8 +1,39 @@
1
+import { useIntl } from 'umi';
2
+import { GithubOutlined } from '@ant-design/icons';
1 3
 import { DefaultFooter } from '@ant-design/pro-layout';
2 4
 
3
-const year = new Date().getFullYear();
4
-const copyright = `${year} 南京云致科技服务有限公司`;
5
-
6
-export default () => {
7
-  return <DefaultFooter copyright={copyright} links={[]} />;
5
+const Footer = () => {
6
+  const intl = useIntl();
7
+  const defaultMessage = intl.formatMessage({
8
+    id: 'app.copyright.produced',
9
+    defaultMessage: '蚂蚁集团体验技术部出品',
10
+  });
11
+  const currentYear = new Date().getFullYear();
12
+  return (
13
+    <DefaultFooter
14
+      copyright={`${currentYear} ${defaultMessage}`}
15
+      links={[
16
+        {
17
+          key: 'Ant Design Pro',
18
+          title: 'Ant Design Pro',
19
+          href: 'https://pro.ant.design',
20
+          blankTarget: true,
21
+        },
22
+        {
23
+          key: 'github',
24
+          title: <GithubOutlined />,
25
+          href: 'https://github.com/ant-design/ant-design-pro',
26
+          blankTarget: true,
27
+        },
28
+        {
29
+          key: 'Ant Design',
30
+          title: 'Ant Design',
31
+          href: 'https://ant.design',
32
+          blankTarget: true,
33
+        },
34
+      ]}
35
+    />
36
+  );
8 37
 };
38
+
39
+export default Footer;

+ 0
- 1
src/layouts/BasicLayout.jsx Bestand weergeven

@@ -1 +0,0 @@
1
-export default props => props.children

+ 65
- 0
src/pages/Welcome.jsx Bestand weergeven

@@ -0,0 +1,65 @@
1
+import React from 'react';
2
+import { PageContainer } from '@ant-design/pro-layout';
3
+import { Card, Alert, Typography } from 'antd';
4
+import { useIntl, FormattedMessage } from 'umi';
5
+import styles from './Welcome.less';
6
+
7
+const CodePreview = ({ children }) => (
8
+  <pre className={styles.pre}>
9
+    <code>
10
+      <Typography.Text copyable>{children}</Typography.Text>
11
+    </code>
12
+  </pre>
13
+);
14
+
15
+const Welcome = () => {
16
+  const intl = useIntl();
17
+  return (
18
+    <PageContainer>
19
+      <Card>
20
+        <Alert
21
+          message={intl.formatMessage({
22
+            id: 'pages.welcome.alertMessage',
23
+            defaultMessage: 'Faster and stronger heavy-duty components have been released.',
24
+          })}
25
+          type="success"
26
+          showIcon
27
+          banner
28
+          style={{
29
+            margin: -12,
30
+            marginBottom: 24,
31
+          }}
32
+        />
33
+        <Typography.Text strong>
34
+          <FormattedMessage id="pages.welcome.advancedComponent" defaultMessage="Advanced Form" />{' '}
35
+          <a
36
+            href="https://procomponents.ant.design/components/table"
37
+            rel="noopener noreferrer"
38
+            target="__blank"
39
+          >
40
+            <FormattedMessage id="pages.welcome.link" defaultMessage="Welcome" />
41
+          </a>
42
+        </Typography.Text>
43
+        <CodePreview>yarn add @ant-design/pro-table</CodePreview>
44
+        <Typography.Text
45
+          strong
46
+          style={{
47
+            marginBottom: 12,
48
+          }}
49
+        >
50
+          <FormattedMessage id="pages.welcome.advancedLayout" defaultMessage="Advanced layout" />{' '}
51
+          <a
52
+            href="https://procomponents.ant.design/components/layout"
53
+            rel="noopener noreferrer"
54
+            target="__blank"
55
+          >
56
+            <FormattedMessage id="pages.welcome.link" defaultMessage="Welcome" />
57
+          </a>
58
+        </Typography.Text>
59
+        <CodePreview>yarn add @ant-design/pro-layout</CodePreview>
60
+      </Card>
61
+    </PageContainer>
62
+  );
63
+};
64
+
65
+export default Welcome;

+ 8
- 0
src/pages/Welcome.less Bestand weergeven

@@ -0,0 +1,8 @@
1
+@import (reference) '~antd/es/style/themes/index';
2
+
3
+.pre {
4
+  margin: 12px 0;
5
+  padding: 12px 20px;
6
+  background: @input-bg;
7
+  box-shadow: @card-shadow;
8
+}

+ 0
- 26
src/pages/Welcome/Welcome.less Bestand weergeven

@@ -1,26 +0,0 @@
1
-@import '~antd/lib/style/themes/default.less';
2
-
3
-.pre {
4
-  margin: 12px 0;
5
-  padding: 12px 20px;
6
-  background: @input-bg;
7
-  box-shadow: @card-shadow;
8
-}
9
-
10
-.dashboard-header {
11
-  display: flex;
12
-
13
-  .avatar {
14
-    flex: none;
15
-  }
16
-
17
-  .title {
18
-    flex: none;
19
-    margin-left: 2em;
20
-    padding-top: .5em;
21
-  }
22
-
23
-  .actions {
24
-    flex: auto;
25
-  }
26
-}

+ 0
- 1
src/pages/Welcome/index.jsx Bestand weergeven

@@ -1 +0,0 @@
1
-export default () => <div />;

+ 241
- 96
src/pages/user/Login/index.jsx Bestand weergeven

@@ -1,11 +1,18 @@
1
-import { LockOutlined, UserOutlined } from '@ant-design/icons';
1
+import {
2
+  AlipayCircleOutlined,
3
+  LockOutlined,
4
+  MobileOutlined,
5
+  TaobaoCircleOutlined,
6
+  UserOutlined,
7
+  WeiboCircleOutlined,
8
+} from '@ant-design/icons';
2 9
 import { Alert, message, Tabs } from 'antd';
3 10
 import React, { useState } from 'react';
4
-import md5 from 'md5';
5
-import ProForm, { ProFormText } from '@ant-design/pro-form';
6
-import { useIntl, Link, history, FormattedMessage, SelectLang, useModel } from 'umi';
11
+import { ProFormCaptcha, ProFormCheckbox, ProFormText, LoginForm } from '@ant-design/pro-form';
12
+import { useIntl, history, FormattedMessage, SelectLang, useModel } from 'umi';
7 13
 import Footer from '@/components/Footer';
8
-import { login } from '@/services/login';
14
+import { login } from '@/services/ant-design-pro/api';
15
+import { getFakeCaptcha } from '@/services/ant-design-pro/login';
9 16
 import styles from './index.less';
10 17
 
11 18
 const LoginMessage = ({ content }) => (
@@ -20,120 +27,258 @@ const LoginMessage = ({ content }) => (
20 27
 );
21 28
 
22 29
 const Login = () => {
23
-  const [submitting, setSubmitting] = useState(false);
30
+  const [userLoginState, setUserLoginState] = useState({});
31
+  const [type, setType] = useState('account');
24 32
   const { initialState, setInitialState } = useModel('@@initialState');
25 33
   const intl = useIntl();
26 34
 
27
-  const handleSubmit = async (values) => {
28
-    setSubmitting(true);
35
+  const fetchUserInfo = async () => {
36
+    const userInfo = await initialState?.fetchUserInfo?.();
37
+
38
+    if (userInfo) {
39
+      await setInitialState((s) => ({ ...s, currentUser: userInfo }));
40
+    }
41
+  };
29 42
 
43
+  const handleSubmit = async (values) => {
30 44
     try {
31 45
       // 登录
32
-      const { user } = await login({ ...values, password: md5(values.password) });
46
+      const msg = await login({ ...values, type });
47
+
48
+      if (msg.status === 'ok') {
49
+        const defaultLoginSuccessMessage = intl.formatMessage({
50
+          id: 'pages.login.success',
51
+          defaultMessage: '登录成功!',
52
+        });
53
+        message.success(defaultLoginSuccessMessage);
54
+        await fetchUserInfo();
55
+        /** 此方法会跳转到 redirect 参数所在的位置 */
33 56
 
34
-      await setInitialState((s) => ({ ...s, currentUser: user }));
57
+        if (!history) return;
58
+        const { query } = history.location;
59
+        const { redirect } = query;
60
+        history.push(redirect || '/');
61
+        return;
62
+      }
35 63
 
36
-      message.success('登录成功!');
37
-      /** 此方法会跳转到 redirect 参数所在的位置 */
64
+      console.log(msg); // 如果失败去设置用户错误信息
38 65
 
39
-      if (!history) return;
40
-      const { query } = history.location;
41
-      const { redirect } = query;
42
-      history.push(redirect || '/');
43
-      return;
66
+      setUserLoginState(msg);
44 67
     } catch (error) {
45
-      console.error(error);
46
-      // const defaultLoginFailureMessage = intl.formatMessage({
47
-      //   id: 'pages.login.failure',
48
-      //   defaultMessage: '登录失败,请重试!',
49
-      // });
50
-      // message.error(defaultLoginFailureMessage);
68
+      const defaultLoginFailureMessage = intl.formatMessage({
69
+        id: 'pages.login.failure',
70
+        defaultMessage: '登录失败,请重试!',
71
+      });
72
+      message.error(defaultLoginFailureMessage);
51 73
     }
52
-
53
-    setSubmitting(false);
54 74
   };
55 75
 
76
+  const { status, type: loginType } = userLoginState;
56 77
   return (
57 78
     <div className={styles.container}>
58 79
       <div className={styles.lang} data-lang>
59 80
         {SelectLang && <SelectLang />}
60 81
       </div>
61 82
       <div className={styles.content}>
62
-        <div className={styles.top}>
63
-          <div className={styles.header}>
64
-            <Link to="/">
65
-              <img alt="logo" className={styles.logo} src="/logo.svg" />
66
-              <span className={styles.title}>智慧农用机管理平台</span>
67
-            </Link>
68
-          </div>
69
-          <div className={styles.desc}>我们是一群被打了鸡血的小伙伴</div>
70
-        </div>
83
+        <LoginForm
84
+          logo={<img alt="logo" src="/logo.svg" />}
85
+          title="Ant Design"
86
+          subTitle={intl.formatMessage({
87
+            id: 'pages.layouts.userLayout.title',
88
+          })}
89
+          initialValues={{
90
+            autoLogin: true,
91
+          }}
92
+          actions={[
93
+            <FormattedMessage
94
+              key="loginWith"
95
+              id="pages.login.loginWith"
96
+              defaultMessage="其他登录方式"
97
+            />,
98
+            <AlipayCircleOutlined key="AlipayCircleOutlined" className={styles.icon} />,
99
+            <TaobaoCircleOutlined key="TaobaoCircleOutlined" className={styles.icon} />,
100
+            <WeiboCircleOutlined key="WeiboCircleOutlined" className={styles.icon} />,
101
+          ]}
102
+          onFinish={async (values) => {
103
+            await handleSubmit(values);
104
+          }}
105
+        >
106
+          <Tabs activeKey={type} onChange={setType}>
107
+            <Tabs.TabPane
108
+              key="account"
109
+              tab={intl.formatMessage({
110
+                id: 'pages.login.accountLogin.tab',
111
+                defaultMessage: '账户密码登录',
112
+              })}
113
+            />
114
+            <Tabs.TabPane
115
+              key="mobile"
116
+              tab={intl.formatMessage({
117
+                id: 'pages.login.phoneLogin.tab',
118
+                defaultMessage: '手机号登录',
119
+              })}
120
+            />
121
+          </Tabs>
71 122
 
72
-        <div className={styles.main}>
73
-          <ProForm
74
-            initialValues={{
75
-              autoLogin: true,
76
-            }}
77
-            submitter={{
78
-              searchConfig: {
79
-                submitText: intl.formatMessage({
80
-                  id: 'pages.login.submit',
81
-                  defaultMessage: '登录',
82
-                }),
83
-              },
84
-              render: (_, dom) => dom.pop(),
85
-              submitButtonProps: {
86
-                loading: submitting,
87
-                size: 'large',
88
-                style: {
89
-                  width: '100%',
90
-                },
91
-              },
92
-            }}
93
-            onFinish={async (values) => {
94
-              handleSubmit(values);
123
+          {status === 'error' && loginType === 'account' && (
124
+            <LoginMessage
125
+              content={intl.formatMessage({
126
+                id: 'pages.login.accountLogin.errorMessage',
127
+                defaultMessage: '账户或密码错误(admin/ant.design)',
128
+              })}
129
+            />
130
+          )}
131
+          {type === 'account' && (
132
+            <>
133
+              <ProFormText
134
+                name="username"
135
+                fieldProps={{
136
+                  size: 'large',
137
+                  prefix: <UserOutlined className={styles.prefixIcon} />,
138
+                }}
139
+                placeholder={intl.formatMessage({
140
+                  id: 'pages.login.username.placeholder',
141
+                  defaultMessage: '用户名: admin or user',
142
+                })}
143
+                rules={[
144
+                  {
145
+                    required: true,
146
+                    message: (
147
+                      <FormattedMessage
148
+                        id="pages.login.username.required"
149
+                        defaultMessage="请输入用户名!"
150
+                      />
151
+                    ),
152
+                  },
153
+                ]}
154
+              />
155
+              <ProFormText.Password
156
+                name="password"
157
+                fieldProps={{
158
+                  size: 'large',
159
+                  prefix: <LockOutlined className={styles.prefixIcon} />,
160
+                }}
161
+                placeholder={intl.formatMessage({
162
+                  id: 'pages.login.password.placeholder',
163
+                  defaultMessage: '密码: ant.design',
164
+                })}
165
+                rules={[
166
+                  {
167
+                    required: true,
168
+                    message: (
169
+                      <FormattedMessage
170
+                        id="pages.login.password.required"
171
+                        defaultMessage="请输入密码!"
172
+                      />
173
+                    ),
174
+                  },
175
+                ]}
176
+              />
177
+            </>
178
+          )}
179
+
180
+          {status === 'error' && loginType === 'mobile' && <LoginMessage content="验证码错误" />}
181
+          {type === 'mobile' && (
182
+            <>
183
+              <ProFormText
184
+                fieldProps={{
185
+                  size: 'large',
186
+                  prefix: <MobileOutlined className={styles.prefixIcon} />,
187
+                }}
188
+                name="mobile"
189
+                placeholder={intl.formatMessage({
190
+                  id: 'pages.login.phoneNumber.placeholder',
191
+                  defaultMessage: '手机号',
192
+                })}
193
+                rules={[
194
+                  {
195
+                    required: true,
196
+                    message: (
197
+                      <FormattedMessage
198
+                        id="pages.login.phoneNumber.required"
199
+                        defaultMessage="请输入手机号!"
200
+                      />
201
+                    ),
202
+                  },
203
+                  {
204
+                    pattern: /^1\d{10}$/,
205
+                    message: (
206
+                      <FormattedMessage
207
+                        id="pages.login.phoneNumber.invalid"
208
+                        defaultMessage="手机号格式错误!"
209
+                      />
210
+                    ),
211
+                  },
212
+                ]}
213
+              />
214
+              <ProFormCaptcha
215
+                fieldProps={{
216
+                  size: 'large',
217
+                  prefix: <LockOutlined className={styles.prefixIcon} />,
218
+                }}
219
+                captchaProps={{
220
+                  size: 'large',
221
+                }}
222
+                placeholder={intl.formatMessage({
223
+                  id: 'pages.login.captcha.placeholder',
224
+                  defaultMessage: '请输入验证码',
225
+                })}
226
+                captchaTextRender={(timing, count) => {
227
+                  if (timing) {
228
+                    return `${count} ${intl.formatMessage({
229
+                      id: 'pages.getCaptchaSecondText',
230
+                      defaultMessage: '获取验证码',
231
+                    })}`;
232
+                  }
233
+
234
+                  return intl.formatMessage({
235
+                    id: 'pages.login.phoneLogin.getVerificationCode',
236
+                    defaultMessage: '获取验证码',
237
+                  });
238
+                }}
239
+                name="captcha"
240
+                rules={[
241
+                  {
242
+                    required: true,
243
+                    message: (
244
+                      <FormattedMessage
245
+                        id="pages.login.captcha.required"
246
+                        defaultMessage="请输入验证码!"
247
+                      />
248
+                    ),
249
+                  },
250
+                ]}
251
+                onGetCaptcha={async (phone) => {
252
+                  const result = await getFakeCaptcha({
253
+                    phone,
254
+                  });
255
+
256
+                  if (result === false) {
257
+                    return;
258
+                  }
259
+
260
+                  message.success('获取验证码成功!验证码为:1234');
261
+                }}
262
+              />
263
+            </>
264
+          )}
265
+          <div
266
+            style={{
267
+              marginBottom: 24,
95 268
             }}
96 269
           >
97
-            <ProFormText
98
-              name="userName"
99
-              fieldProps={{
100
-                size: 'large',
101
-                prefix: <UserOutlined className={styles.prefixIcon} />,
102
-              }}
103
-              placeholder="用户名"
104
-              rules={[
105
-                {
106
-                  required: true,
107
-                  message: (
108
-                    <FormattedMessage
109
-                      id="pages.login.username.required"
110
-                      defaultMessage="请输入用户名!"
111
-                    />
112
-                  ),
113
-                },
114
-              ]}
115
-            />
116
-            <ProFormText.Password
117
-              name="password"
118
-              fieldProps={{
119
-                size: 'large',
120
-                prefix: <LockOutlined className={styles.prefixIcon} />,
270
+            <ProFormCheckbox noStyle name="autoLogin">
271
+              <FormattedMessage id="pages.login.rememberMe" defaultMessage="自动登录" />
272
+            </ProFormCheckbox>
273
+            <a
274
+              style={{
275
+                float: 'right',
121 276
               }}
122
-              placeholder="密码"
123
-              rules={[
124
-                {
125
-                  required: true,
126
-                  message: (
127
-                    <FormattedMessage
128
-                      id="pages.login.password.required"
129
-                      defaultMessage="请输入密码!"
130
-                    />
131
-                  ),
132
-                },
133
-              ]}
134
-            />
135
-          </ProForm>
136
-        </div>
277
+            >
278
+              <FormattedMessage id="pages.login.forgotPassword" defaultMessage="忘记密码" />
279
+            </a>
280
+          </div>
281
+        </LoginForm>
137 282
       </div>
138 283
       <Footer />
139 284
     </div>

+ 9
- 73
src/pages/user/Login/index.less Bestand weergeven

@@ -1,4 +1,4 @@
1
-@import '~antd/es/style/themes/default.less';
1
+@import (reference) '~antd/es/style/themes/index';
2 2
 
3 3
 .container {
4 4
   display: flex;
@@ -36,79 +36,15 @@
36 36
   }
37 37
 }
38 38
 
39
-.top {
40
-  text-align: center;
41
-}
42
-
43
-.header {
44
-  height: 44px;
45
-  line-height: 44px;
46
-  a {
47
-    text-decoration: none;
48
-  }
49
-}
50
-
51
-.logo {
52
-  height: 44px;
53
-  margin-right: 16px;
54
-  vertical-align: top;
55
-}
56
-
57
-.title {
58
-  position: relative;
59
-  top: 2px;
60
-  color: @heading-color;
61
-  font-weight: 600;
62
-  font-size: 33px;
63
-  font-family: Avenir, 'Helvetica Neue', Arial, Helvetica, sans-serif;
64
-}
65
-
66
-.desc {
67
-  margin-top: 12px;
68
-  margin-bottom: 40px;
69
-  color: @text-color-secondary;
70
-  font-size: @font-size-base;
71
-}
72
-
73
-.main {
74
-  width: 328px;
75
-  margin: 0 auto;
76
-  @media screen and (max-width: @screen-sm) {
77
-    width: 95%;
78
-    max-width: 328px;
79
-  }
80
-
81
-  :global {
82
-    .@{ant-prefix}-tabs-nav-list {
83
-      margin: auto;
84
-      font-size: 16px;
85
-    }
86
-  }
87
-
88
-  .icon {
89
-    margin-left: 16px;
90
-    color: rgba(0, 0, 0, 0.2);
91
-    font-size: 24px;
92
-    vertical-align: middle;
93
-    cursor: pointer;
94
-    transition: color 0.3s;
95
-
96
-    &:hover {
97
-      color: @primary-color;
98
-    }
99
-  }
100
-
101
-  .other {
102
-    margin-top: 24px;
103
-    line-height: 22px;
104
-    text-align: left;
105
-    .register {
106
-      float: right;
107
-    }
108
-  }
39
+.icon {
40
+  margin-left: 8px;
41
+  color: rgba(0, 0, 0, 0.2);
42
+  font-size: 24px;
43
+  vertical-align: middle;
44
+  cursor: pointer;
45
+  transition: color 0.3s;
109 46
 
110
-  .prefixIcon {
47
+  &:hover {
111 48
     color: @primary-color;
112
-    font-size: @font-size-base;
113 49
   }
114 50
 }

+ 0
- 1
src/services/ant-design-pro/api.js Bestand weergeven

@@ -21,7 +21,6 @@ export async function outLogin(options) {
21 21
 /** 登录接口 POST /api/login/account */
22 22
 
23 23
 export async function login(body, options) {
24
-  console.log(555);
25 24
   return request('/api/login/account', {
26 25
     method: 'POST',
27 26
     headers: {

+ 0
- 3
src/services/login.js Bestand weergeven

@@ -1,3 +0,0 @@
1
-import request from '@/utils/request'
2
-
3
-export const login = (data) => request('/login', { method: 'post', data })

+ 0
- 17
src/utils/download.js Bestand weergeven

@@ -1,17 +0,0 @@
1
-
2
-export function fetchBlob(url) {
3
-  return window.fetch(url).then(response => response.blob())
4
-}
5
-
6
-export function downloadBlob(blob, fileName) {
7
-  const url = window.URL.createObjectURL(blob);
8
-  const link = document.createElement('a');
9
-  link.href = url;
10
-  link.setAttribute('download', fileName);
11
-  link.click();
12
-  window.URL.revokeObjectURL(url);
13
-}
14
-
15
-export function downloadUrl(url, fileName) {
16
-  return fetchBlob(url).then(blob => downloadBlob(blob, fileName))
17
-};

+ 0
- 83
src/utils/request.js Bestand weergeven

@@ -1,83 +0,0 @@
1
-import { request } from 'umi'
2
-import { downloadBlob } from './download'
3
-
4
-function requestInterceptor(url, options) {
5
-  const headers = options.headers || {};
6
-  const token = localStorage.getItem('token')
7
-    ? { 'X-Authorization-JWT': localStorage.getItem('token') }
8
-    : {};
9
-  const prefix = process.env.NODE_ENV === 'production' ? 'http://sgl-v2.njyunzhi.com/api/admin' : '/api/admin';
10
-
11
-  return {
12
-    url: `${prefix}${url}`,
13
-    options: {
14
-      ...options,
15
-      headers: {
16
-        ...headers,
17
-        ...token,
18
-      },
19
-    },
20
-  };
21
-}
22
-
23
-async function responseInterceptor(response) {
24
-  const contextType = response.headers.get('content-type');
25
-  if (contextType.indexOf('json') > -1) {
26
-    const result = await response.clone().json();
27
-    if (result?.token || result?.data?.token) {
28
-      localStorage.setItem('token', result?.token || result?.data?.token);
29
-    }
30
-
31
-    if (result.code === 1000) {
32
-      return result;
33
-    }
34
-    return Promise.reject(result);
35
-  }
36
-
37
-  if (contextType.indexOf('application/vnd.ms-excel') > -1) {
38
-    const data = await response.clone().blob();
39
-    const content = response.headers.get('content-disposition');
40
-    const fileName = content.replace('attachment;filename=', '')
41
-    downloadBlob(data, decodeURIComponent(fileName));
42
-  }
43
-
44
-  return response;
45
-}
46
-
47
-// https://umijs.org/plugins/plugin-request
48
-export const requestConfig = {
49
-  errorConfig: {
50
-    adaptor: (resData) => {
51
-      return {
52
-        ...resData,
53
-        success: resData.code === 1000,
54
-        errorMessage: resData.message,
55
-        showType: 0,  // 静默处理错误
56
-      };
57
-    },
58
-  },
59
-  requestInterceptors: [requestInterceptor],
60
-  responseInterceptors: [responseInterceptor],
61
-}
62
-
63
-export default (...args) => request(...args).then(r => r.data);
64
-
65
-
66
-export function queryTable(apiRequest) {
67
-  return function(params) {
68
-    return apiRequest({
69
-      ...params,
70
-      pageNum: params.current,
71
-    }).then((res) => {
72
-      return {
73
-        data: res.records,
74
-        success: true,
75
-        total: res.total,
76
-      }
77
-    }).catch((err) => {
78
-      return {
79
-        success: false,
80
-      }
81
-    })
82
-  }  
83
-}