Browse Source

feat: 三方登录及系统基础配置

wzyyy 3 years ago
parent
commit
fada27a268

+ 6 - 2
src/app.tsx

@@ -114,7 +114,12 @@ export async function getInitialState(): Promise<{
  * @param url
  * @param options
  */
-const filterUrl = ['/authorize/captcha/config', '/authorize/login', '/sso/bind-code/'];
+const filterUrl = [
+  '/authorize/captcha/config',
+  '/authorize/login',
+  '/sso/bind-code/',
+  '/sso/providers',
+];
 const requestInterceptor = (url: string, options: RequestOptionsInit) => {
   // const {params} = options;
   let authHeader = {};
@@ -196,7 +201,6 @@ export const layout: RunTimeLayoutConfig = ({ initialState }) => {
     onPageChange: () => {
       const { location } = history;
       // 如果没有登录,重定向到 login
-      console.log(location.pathname);
       if (
         !initialState?.currentUser &&
         location.pathname !== loginPath &&

+ 1 - 0
src/pages/account/Center/bind/index.tsx

@@ -85,6 +85,7 @@ const Bind = () => {
         Token.set(userInfo.token);
         await fetchUserInfo();
         localStorage.setItem('onLogin', 'yes');
+        message.success('登录成功');
         setTimeout(() => window.close(), 1000);
       },
       error: () => {

+ 16 - 12
src/pages/account/Center/index.tsx

@@ -22,14 +22,16 @@ import PasswordEdit from './edit/passwordEdit';
 import Service from '@/pages/account/Center/service';
 import moment from 'moment';
 import { useModel } from 'umi';
+import usePermissions from '@/hooks/permission';
+import { PermissionButton } from '@/components';
 
 export const service = new Service();
 
 const Center = () => {
   const { initialState, setInitialState } = useModel('@@initialState');
+  const { permission: userPermission } = usePermissions('system/User');
   const [data, setData] = useState<any>();
   const [imageUrl, setImageUrl] = useState<string>('');
-  // const [loading, setLoading] = useState<boolean>(false)
   const [infos, setInfos] = useState<boolean>(false);
   const [password, setPassword] = useState<boolean>(false);
   const [bindList, setBindList] = useState<any>([]);
@@ -82,12 +84,6 @@ const Center = () => {
     service.getUserDetail().subscribe((res) => {
       setData(res.result);
       setImageUrl(res.result.avatar);
-      // setInitialState({
-      //   ...initialState,
-      //   currentUser:{
-
-      //   }
-      // })
     });
   };
   const saveInfo = (parms: UserDetail) => {
@@ -198,14 +194,22 @@ const Center = () => {
           </div>
         }
         extra={
-          <a>
-            {' '}
-            <EditOutlined
+          <>
+            <PermissionButton
+              type="link"
+              key="password"
+              style={{ padding: 0 }}
+              tooltip={{
+                title: '重置密码',
+              }}
               onClick={() => {
                 setPassword(true);
               }}
-            />
-          </a>
+              isPermission={userPermission.update}
+            >
+              <EditOutlined />
+            </PermissionButton>
+          </>
         }
       >
         <div style={{ display: 'flex', alignItems: 'flex-end' }}>

+ 28 - 10
src/pages/link/Channel/Opcua/Save/index.tsx

@@ -6,7 +6,10 @@ import type { ISchema } from '@formily/json-schema';
 import { service } from '@/pages/link/Channel/Opcua';
 import { Modal } from '@/components';
 import { message } from 'antd';
-import { useEffect, useMemo, useState } from 'react';
+import { useMemo } from 'react';
+import { action } from '@formily/reactive';
+import type { Response } from '@/utils/typings';
+import type { Field } from '@formily/core';
 
 interface Props {
   data: Partial<OpaUa>;
@@ -16,8 +19,8 @@ interface Props {
 
 const Save = (props: Props) => {
   const intl = useIntl();
-  const [policies, setPolicies] = useState<any>([]);
-  const [modes, setModes] = useState<any>([]);
+  // const [policies, setPolicies] = useState<any>([]);
+  // const [modes, setModes] = useState<any>([]);
 
   const form = useMemo(
     () =>
@@ -31,6 +34,21 @@ const Save = (props: Props) => {
     [props.data.id],
   );
 
+  const useAsyncDataSource = (api: any) => (field: Field) => {
+    field.loading = true;
+    api(field).then(
+      action.bound!((resp: Response<any>) => {
+        field.dataSource = resp.result?.map((item: Record<string, unknown>) => ({
+          label: item,
+          value: item,
+        }));
+        field.loading = false;
+      }),
+    );
+  };
+
+  const getPolicies = () => service.policies();
+  const getModes = () => service.modes();
   const SchemaField = createSchemaField({
     components: {
       FormItem,
@@ -125,7 +143,7 @@ const Save = (props: Props) => {
                 message: '请选择安全策略',
               },
             ],
-            enum: policies,
+            'x-reactions': ['{{useAsyncDataSource(getPolicies)}}'],
           },
           'clientConfigs.securityMode': {
             title: '安全模式',
@@ -145,7 +163,7 @@ const Save = (props: Props) => {
               },
             ],
             required: true,
-            enum: modes,
+            'x-reactions': ['{{useAsyncDataSource(getModes)}}'],
           },
           'clientConfigs.username': {
             title: '用户名',
@@ -253,10 +271,10 @@ const Save = (props: Props) => {
     }
   };
 
-  useEffect(() => {
-    service.policies().then((res) => setPolicies(res.result));
-    service.modes().then((res) => setModes(res.result));
-  }, []);
+  // useEffect(() => {
+  //   service.policies().then((res) => setPolicies(res.result));
+  //   service.modes().then((res) => setModes(res.result));
+  // }, []);
   return (
     <Modal
       title={intl.formatMessage({
@@ -272,7 +290,7 @@ const Save = (props: Props) => {
       permission={['add', 'edit']}
     >
       <Form form={form} layout="vertical">
-        <SchemaField schema={schema} />
+        <SchemaField schema={schema} scope={{ useAsyncDataSource, getPolicies, getModes }} />
       </Form>
     </Modal>
   );

+ 9 - 0
src/pages/system/Basis/index.less

@@ -0,0 +1,9 @@
+.content {
+  margin-left: 30px;
+  :global {
+    .ant-upload.ant-upload-select-picture-card {
+      width: 150px;
+      height: 150px;
+    }
+  }
+}

+ 137 - 0
src/pages/system/Basis/index.tsx

@@ -0,0 +1,137 @@
+import { Card, Form, Input, Select, Upload, message } from 'antd';
+import { useModel } from '@@/plugin-model/useModel';
+import { useEffect, useState } from 'react';
+import usePermissions from '@/hooks/permission';
+import { PermissionButton } from '@/components';
+import { UploadProps } from 'antd/lib/upload';
+import Token from '@/utils/token';
+import SystemConst from '@/utils/const';
+import { LoadingOutlined, PlusOutlined } from '@ant-design/icons';
+import styles from './index.less';
+
+const Basis = () => {
+  const [form] = Form.useForm();
+  const { initialState } = useModel('@@initialState');
+  const { permission: userPermission } = usePermissions('system/Basis');
+  const [imageUrl, setImageUrl] = useState<string>('');
+  const [loading, setLoading] = useState(false);
+
+  const uploadProps: UploadProps = {
+    showUploadList: false,
+    listType: 'picture-card',
+    accept: 'image/jpeg,image/png',
+    action: `/${SystemConst.API_BASE}/file/static`,
+    headers: {
+      'X-Access-Token': Token.get(),
+    },
+    beforeUpload(file) {
+      const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
+      if (!isJpgOrPng) {
+        message.error('请上传.png.jpg格式的文件');
+      }
+      return isJpgOrPng;
+    },
+    onChange(info) {
+      if (info.file.status === 'uploading') {
+        setLoading(true);
+      }
+      if (info.file.status === 'done') {
+        setImageUrl(info.file.response.result);
+        setLoading(false);
+      }
+    },
+  };
+  const uploadButton = (
+    <div>
+      {loading ? <LoadingOutlined /> : <PlusOutlined />}
+      <div style={{ marginTop: 8 }}>Upload</div>
+    </div>
+  );
+
+  useEffect(() => {
+    console.log(initialState);
+  }, []);
+
+  return (
+    <Card>
+      <div
+        style={{
+          display: 'flex',
+          alignItems: 'flex-start',
+          justifyContent: 'flex-start',
+        }}
+      >
+        <div style={{ width: 400 }}>
+          <Form layout="vertical" form={form}>
+            <Form.Item
+              label="系统名称"
+              name="title"
+              rules={[{ required: true, message: '请输入系统名称' }]}
+            >
+              <Input />
+            </Form.Item>
+            <Form.Item
+              label="主题色"
+              name="navTheme"
+              rules={[{ required: true, message: '请选择主题色' }]}
+            >
+              <Select
+                onChange={() => {
+                  // setInitialState({
+                  //     ...initialState,
+                  //     settings:{
+                  //         navTheme:e,
+                  //         headerTheme:e,
+                  //         title:'hahahah'
+                  //     }
+                  // })
+                }}
+              >
+                <Select.Option value="light">light</Select.Option>
+                <Select.Option value="dark">dark</Select.Option>
+              </Select>
+            </Form.Item>
+            <Form.Item label="高德API Key" name="apikey" tooltip="配置后平台可调用高德地图GIS服务">
+              <Input />
+            </Form.Item>
+          </Form>
+        </div>
+        <div className={styles.content}>
+          <div style={{ marginBottom: 8 }}>系统logo</div>
+          <Upload {...uploadProps}>
+            {imageUrl ? (
+              <img src={imageUrl} alt="avatar" style={{ width: '100%' }} />
+            ) : (
+              uploadButton
+            )}
+          </Upload>
+        </div>
+      </div>
+      <div>
+        <PermissionButton
+          type="primary"
+          key="basis"
+          onClick={async () => {
+            // setPassword(true);
+            const data = await form.validateFields();
+            if (data) {
+              if (imageUrl !== '') {
+                console.log({
+                  ...data,
+                  imageUrl,
+                });
+              } else {
+                message.error('请上传图片');
+              }
+            }
+          }}
+          isPermission={userPermission.update}
+        >
+          保存
+        </PermissionButton>
+      </div>
+    </Card>
+  );
+};
+
+export default Basis;

+ 0 - 0
src/pages/system/Basis/service.ts


+ 36 - 14
src/pages/user/Login/index.tsx

@@ -1,4 +1,4 @@
-import { Checkbox, message, Spin } from 'antd';
+import { Button, Checkbox, message, Spin } from 'antd';
 import React, { useEffect, useRef, useState } from 'react';
 import { Link } from 'umi';
 import styles from './index.less';
@@ -10,14 +10,15 @@ import { Form, FormItem, Input, Password, Submit } from '@formily/antd';
 import { catchError, filter, mergeMap } from 'rxjs/operators';
 import * as ICONS from '@ant-design/icons';
 import { useModel } from '@@/plugin-model/useModel';
-// import SystemConst from '@/utils/const';
+import SystemConst from '@/utils/const';
 import { useIntl } from '@@/plugin-locale/localeExports';
 import { SelectLang } from '@@/plugin-locale/SelectLang';
 import Footer from '@/components/Footer';
+import { DingdingOutlined, WechatOutlined } from '@ant-design/icons';
 
 const Login: React.FC = () => {
   const [captcha, setCaptcha] = useState<{ key?: string; base64?: string }>({});
-
+  const [bindings, setBindings] = useState<any>([]);
   const { initialState, setInitialState } = useModel('@@initialState');
   const intl = useIntl();
 
@@ -62,6 +63,13 @@ const Login: React.FC = () => {
   };
 
   useEffect(getCode, []);
+  useEffect(() => {
+    Service.bindInfo().then((res) => {
+      if (res.status === 200) {
+        setBindings(res.result);
+      }
+    });
+  }, []);
 
   const SchemaField = createSchemaField({
     components: {
@@ -187,17 +195,31 @@ const Login: React.FC = () => {
                       defaultMessage: '登录',
                     })}
                   </Submit>
-                  {/* <Button
-                      onClick={()=>{
-                        localStorage.setItem('onLogin', 'no');
-                        window.open(`/${SystemConst.API_BASE}/sso/dingd2rgqrqnbvgbvi9x/login`);
-                        window.onstorage = (e) => {
-                          if (e.newValue) {
-                            window.location.href = '/';
-                          }
-                        };
-                      }}
-                  >三方登录</Button> */}
+                  <div style={{ marginTop: 10 }}>
+                    <div>其他方式登录</div>
+                    <div>
+                      {bindings.map((item: any) => (
+                        <Button
+                          type="link"
+                          onClick={() => {
+                            localStorage.setItem('onLogin', 'no');
+                            window.open(`/${SystemConst.API_BASE}/sso/${item.provider}/login`);
+                            window.onstorage = (e) => {
+                              if (e.newValue) {
+                                window.location.href = '/';
+                              }
+                            };
+                          }}
+                        >
+                          {item.type === 'dingtalk' ? (
+                            <DingdingOutlined style={{ color: '#009BF5', fontSize: '20px' }} />
+                          ) : (
+                            <WechatOutlined style={{ color: '#2AAE67', fontSize: '20px' }} />
+                          )}
+                        </Button>
+                      ))}
+                    </div>
+                  </div>
                 </Form>
               </div>
             </div>

+ 5 - 0
src/pages/user/Login/service.ts

@@ -47,6 +47,11 @@ const Service = {
     request(`${SystemConst.API_BASE}/user-token/reset`, {
       method: 'GET',
     }),
+  bindInfo: (params?: any) =>
+    request(`/${SystemConst.API_BASE}/sso/providers`, {
+      method: 'GET',
+      params,
+    }),
 };
 
 export default Service;

+ 1 - 0
src/utils/menu/router.ts

@@ -89,6 +89,7 @@ export enum MENUS_CODE {
   'system/Tenant' = 'system/Tenant',
   'system/User' = 'system/User',
   'system/Relationship' = 'system/Relationship',
+  'system/Basis' = 'system/Basis',
   'user/Login' = 'user/Login',
   'visualization/Category' = 'visualization/Category',
   'visualization/Configuration' = 'visualization/Configuration',