xjj 2 роки тому
батько
коміт
78ea6d2a43

+ 1 - 2
package.json

@@ -14,8 +14,7 @@
     "@ant-design/icons": "^4.7.0",
     "@ant-design/pro-components": "^2.0.1",
     "@umijs/max": "^4.0.41",
-    "antd": "^5.0.0",
-    "qs": "^6.11.0"
+    "antd": "^5.0.0"
   },
   "devDependencies": {
     "@types/react": "^18.0.0",

+ 11 - 10
src/Engine/Drag/index.tsx

@@ -1,7 +1,7 @@
 import React from 'react';
 import './index.less';
 import Loading from '@/loading';
-import { getDvaApp } from 'umi';
+import { getDvaApp, useAccess, useModel } from 'umi';
 
 const app = getDvaApp();
 
@@ -20,13 +20,6 @@ const defaultOptions: GT.IPageOptions = {
   name: '金科环境',
 };
 
-interface IDragProps {
-  options: GT.IPageOptions;
-  router: any;
-  id: number;
-  onActive: Function;
-}
-
 class DragComponent extends React.PureComponent<any> {
   state = {
     mask: true,
@@ -48,7 +41,7 @@ class DragComponent extends React.PureComponent<any> {
   newWidth: any;
   newHeight: any;
 
-  constructor(props: IDragProps) {
+  constructor(props: GT.IDragProps) {
     super(props);
     // this.myRef = React.createRef();
     this.targetRef = React.createRef();
@@ -419,6 +412,8 @@ export default function SysPage(RouteOption: GT.IRouterOptions) {
       options: propsOptions,
       onActive,
     } = props;
+    const access = useAccess();
+    const initState = useModel('@@initialState');
 
     let newOptions = propsOptions || options;
 
@@ -431,7 +426,13 @@ export default function SysPage(RouteOption: GT.IRouterOptions) {
         zoomOut={zoomOut}
       >
         <React.Suspense fallback={<Loading />}>
-          <DynamicComponent params={params} router={router} id={id} />
+          <DynamicComponent
+            params={params}
+            router={router}
+            id={id}
+            access={access}
+            initState={initState}
+          />
         </React.Suspense>
       </DragComponent>
     );

+ 4 - 4
src/Engine/Storage/index.ts

@@ -1,11 +1,11 @@
-import { SysStorage } from '@/Frameworks/SysStorage';
+import { STORAGE_TYPE } from '@/Frameworks/SysStorage';
 
 const useStorage = (storage: Storage) => {
-  const setItem = <T>(key: SysStorage, value: T) => {
+  const setItem = <T>(key: STORAGE_TYPE, value: T) => {
     storage.setItem(key, value ? JSON.stringify(value) : '');
   };
 
-  const getItem = (key: SysStorage) => {
+  const getItem = (key: STORAGE_TYPE) => {
     let value: string = storage.getItem(key) || '';
     try {
       value = JSON.parse(value);
@@ -15,7 +15,7 @@ const useStorage = (storage: Storage) => {
     }
   };
 
-  const removeItem = (key: SysStorage) => {
+  const removeItem = (key: STORAGE_TYPE) => {
     storage.removeItem(key);
   };
 

+ 7 - 0
src/Engine/typings.d.ts

@@ -59,6 +59,13 @@ declare namespace GT {
     // 根据id回退页面
     back: (id: number) => void;
   }
+
+  interface IDragProps {
+    options: GT.IPageOptions;
+    router: any;
+    id: number;
+    onActive: Function;
+  }
 }
 
 interface IStateHandler {

+ 0 - 1
src/Frameworks/SysPage.ts

@@ -6,7 +6,6 @@ class SysRouter extends System {
   dispatch: any;
   constructor(name: string) {
     super(name);
-    console.log('init SysPage');
     this.dispatch = getDvaApp()._store.dispatch;
   }
 

+ 38 - 2
src/Frameworks/SysStorage.ts

@@ -1,4 +1,40 @@
-export enum SysStorage {
+export enum STORAGE_TYPE {
   token = 'token',
 }
-// export {}
+const useStorage = (storage: Storage) => {
+  const setItem = <T>(key: STORAGE_TYPE, value: T) => {
+    storage.setItem(key, value ? JSON.stringify(value) : '');
+  };
+
+  const getItem = (key: STORAGE_TYPE) => {
+    let value: string = storage.getItem(key) || '';
+    try {
+      value = JSON.parse(value);
+      return value;
+    } catch {
+      return value;
+    }
+  };
+
+  const removeItem = (key: STORAGE_TYPE) => {
+    storage.removeItem(key);
+  };
+
+  const clearAll = () => {
+    for (const key in storage) {
+      if (key) {
+        storage.removeItem(key);
+      }
+    }
+  };
+  return {
+    setItem,
+    getItem,
+    removeItem,
+    clearAll,
+  };
+};
+const SessionService = useStorage(window.sessionStorage || sessionStorage);
+const LocalService = useStorage(window.localStorage || sessionStorage);
+
+export { SessionService, LocalService };

+ 11 - 3
src/Project/Functions/LevelAFunctions/FuncLogin.ts

@@ -1,5 +1,6 @@
 import Func from '@/Engine/ECS/Function';
 import SysPage from '@/Frameworks/SysPage';
+import { STORAGE_TYPE, LocalService } from '@/Frameworks/SysStorage';
 import { PAGE_KEY } from '@/Project/constants';
 import { FuncMainState } from '../FuncMain';
 
@@ -20,13 +21,20 @@ export default class FuncLogin extends Func<FuncLoginState> {
     });
   }
   onIdleStateIn(): void {
+    const login = (token: string) => {
+      
+      LocalService.setItem(STORAGE_TYPE.token, token);
+      window.GT_APP.funcMain.changeState(FuncMainState.PlatformMenu);
+    };
     SysPage.add(PAGE_KEY.Login, {
-      test: 11111,
-      gotoA: () =>
-        window.GT_APP.funcMain.changeState(FuncMainState.PlatformMenu),
+      login,
     });
   }
   onIdleStateExit(): void {
     SysPage.removeByKey(PAGE_KEY.Login);
   }
+  login(token: string) {
+    LocalService.setItem(STORAGE_TYPE.token, token);
+    window.GT_APP.funcMain.changeState(FuncMainState.PlatformMenu);
+  }
 }

+ 7 - 4
src/Project/pages/Access/index.tsx

@@ -1,7 +1,10 @@
 import { EventBus, useEventBus } from '@/Engine/EventBus/EventBus';
-import { LocalService, SessionService } from '@/Engine/Storage';
 import { MessageType } from '@/Frameworks/MessageType';
-import { SysStorage } from '@/Frameworks/SysStorage';
+import {
+  STORAGE_TYPE,
+  LocalService,
+  SessionService,
+} from '@/Frameworks/SysStorage';
 import { FuncMainState } from '@/Project/Functions/FuncMain';
 import { PageContainer } from '@ant-design/pro-components';
 import { Access, useAccess } from '@umijs/max';
@@ -51,14 +54,14 @@ const AccessPage: React.FC<GT.IPageProps> = (props) => {
       </Button>
       <Button
         onClick={() => {
-          SessionService.setItem(SysStorage.token, 'token11111');
+          SessionService.setItem(STORAGE_TYPE.token, 'token11111');
         }}
       >
         存Session地址
       </Button>
       <Button
         onClick={() => {
-          LocalService.setItem(SysStorage.token, 'token11111');
+          LocalService.setItem(STORAGE_TYPE.token, 'token11111');
         }}
       >
         存Local地址

+ 108 - 107
src/Project/pages/Login/index.js

@@ -1,141 +1,142 @@
-import React, { Component } from 'react';
+import React, { useRef, useState } from 'react';
 import { connect } from 'umi';
-import { Checkbox, Form, Select, Input, Button } from 'antd';
+import { Form, Select, Input, Button, message } from 'antd';
 import { queryDepList } from '@/Project/services/user';
 import styles from './index.less';
 import { UserOutlined, LockOutlined } from '@ant-design/icons';
 
 const { Option } = Select;
 
-class LoginPage extends Component {
-  formRef = null;
-  state = {
-    type: 'account',
-    depList: [],
-    hasName: false,
-  };
-  constructor(props) {
-    super(props);
-    this.formRef = React.createRef();
-  }
-  componentDidMount = () => {};
-  onHandleChange = async (name) => {
-    var res = await queryDepList(name);
-    this.setState({
-      depList: res.data,
-      hasName: true,
-    });
-    this.formRef.current.setFieldsValue({
-      DepId: res.data[0]?.ID + '',
-    });
+function Login(props) {
+  const {
+    submitting,
+    params,
+    dispatch,
+    initState: { refresh },
+  } = props;
+  const [depList, setDepList] = useState([]);
+  const [hasName, setHasName] = useState(false);
+  const formRef = useRef();
+
+  const onHandleChange = async (name) => {
+    if (!name) {
+      setDepList([]);
+      setHasName(false);
+      return;
+    }
+    try {
+      var res = await queryDepList(name);
+      setDepList(res.data);
+      setHasName(true);
+      formRef.current.setFieldsValue({
+        DepId: res.data[0]?.ID + '',
+      });
+    } catch (error) {
+      setDepList([]);
+      setHasName(true);
+      message.error('用户名不存在');
+    }
   };
 
-  handleSubmit = (values) => {
-    const { type } = this.state;
-    const { dispatch } = this.props;
+  const handleSubmit = (values) => {
     dispatch({
       type: 'login/login',
       payload: {
         ...values,
         // 防止浏览器自动填充
         password: values.password2,
-        type,
       },
-      callback: () => {
-        this.props.params.gotoA();
+      callback: (token) => {
+        params.login(token);
+        refresh();
       },
     });
   };
-
-  render() {
-    const { depList, hasName } = this.state;
-    const { submitting } = this.props;
-    return (
-      <div className={styles.main}>
-        <div className={styles.content}>
-          <Form
-            name="basic"
-            className={styles.inp_box}
-            labelCol={{ span: 0 }}
-            wrapperCol={{ span: 24 }}
-            onFinish={this.handleSubmit}
-            autoComplete="new-password"
-            ref={this.formRef}
+  return (
+    <div className={styles.main}>
+      <div className={styles.content}>
+        <Form
+          name="basic"
+          className={styles.inp_box}
+          labelCol={{ span: 0 }}
+          wrapperCol={{ span: 24 }}
+          onFinish={handleSubmit}
+          autoComplete="new-password"
+          ref={formRef}
+        >
+          <Form.Item
+            label=""
+            name="username"
+            autoComplete="off"
+            rules={[{ required: true, message: '请输入用户名' }]}
           >
-            <Form.Item
-              label=""
-              name="username"
+            <Input
+              prefix={<UserOutlined className={styles.prefixIcon} />}
+              className={styles.inp}
+              size="large"
               autoComplete="off"
-              rules={[{ required: true, message: '请输入用户名' }]}
-            >
-              <Input
-                prefix={<UserOutlined className={styles.prefixIcon} />}
-                className={styles.inp}
-                size="large"
-                autoComplete="off"
-                placeholder="请输入用户名"
-                onBlur={(e) => this.onHandleChange(e.target.value)}
-              />
-            </Form.Item>
-            {hasName && (
-              <Form.Item
-                label=""
-                name="DepId"
-                rules={[{ required: true, message: '请输入用户名' }]}
-              >
-                <Select placeholder="请选择部门" size="large">
-                  {depList.map((item) => (
-                    <Option value={item.ID + ''} key={item.ID}>
-                      {item.Name}
-                    </Option>
-                  ))}
-                </Select>
-              </Form.Item>
-            )}
-
+              placeholder="请输入用户名"
+              onBlur={(e) => onHandleChange(e.target.value)}
+            />
+          </Form.Item>
+          {hasName && (
             <Form.Item
               label=""
-              // 不使用password,防止浏览器自动填充表单
-              name="password2"
-              className={styles.inp}
-              rules={[{ required: true, message: '请输入密码' }]}
+              name="DepId"
+              rules={[{ required: true, message: '请选择部门' }]}
             >
-              <Input.Password
-                prefix={<LockOutlined className={styles.prefixIcon} />}
-                className={styles.inp}
-                size="large"
-                placeholder="请输入密码"
-                autoComplete="new-password"
-              />
+              <Select placeholder="请选择部门" size="large">
+                {depList.map((item) => (
+                  <Option value={item.ID + ''} key={item.ID}>
+                    {item.Name}
+                  </Option>
+                ))}
+              </Select>
             </Form.Item>
+          )}
 
-            {/* <Form.Item
-            name="remember"
-            valuePropName="checked"
-            wrapperCol={{ offset: 8, span: 16 }}
+          <Form.Item
+            label=""
+            // 不使用password,防止浏览器自动填充表单
+            name="password2"
+            className={styles.inp}
+            rules={[{ required: true, message: '请输入密码' }]}
           >
-            <Checkbox>自动登录</Checkbox>
-          </Form.Item> */}
+            <Input.Password
+              prefix={<LockOutlined className={styles.prefixIcon} />}
+              className={styles.inp}
+              size="large"
+              placeholder="请输入密码"
+              autoComplete="new-password"
+            />
+          </Form.Item>
 
-            <Form.Item>
-              <Button
-                size="large"
-                style={{ width: '100%', marginTop: 24 }}
-                loading={submitting}
-                type="primary"
-                htmlType="submit"
-              >
-                登录
-              </Button>
-            </Form.Item>
-          </Form>
-        </div>
+          {/* <Form.Item
+          name="remember"
+          valuePropName="checked"
+          wrapperCol={{ offset: 8, span: 16 }}
+        >
+          <Checkbox>自动登录</Checkbox>
+        </Form.Item> */}
+
+          <Form.Item>
+            <Button
+              size="large"
+              style={{ width: '100%', marginTop: 24 }}
+              loading={submitting}
+              type="primary"
+              htmlType="submit"
+            >
+              登录
+            </Button>
+          </Form.Item>
+        </Form>
       </div>
-    );
-  }
+    </div>
+  );
 }
 
 export default connect(({ login, loading }) => ({
   login,
   submitting: loading.effects['login/login'],
-}))(LoginPage);
+}))(Login);

+ 2 - 3
src/Project/pages/Login/models/login.js

@@ -1,5 +1,4 @@
 import { Login } from '@/Project/services/user';
-import { FuncMainState } from '@/Project/Functions/FuncMain';
 
 export default {
   namespace: 'login',
@@ -12,8 +11,8 @@ export default {
         let response = null;
         response = yield call(Login, payload);
         const { user, token } = response.data;
-        
-        callback?.();
+
+        callback?.(token);
         // yield put({
         //   type: 'changeLoginStatus',
         //   payload: response,

+ 2 - 2
src/Project/pages/PlatformMenu/models/menu.js

@@ -1,5 +1,5 @@
 import { getMenuData } from '@/Project/services/platformMenu';
-import { queryCurrentV2 } from '@/Project/services/user';
+import { queryCurrent } from '@/Project/services/user';
 
 const filterWaterMenuData = (menuData) => {
   if (!menuData) {
@@ -24,7 +24,7 @@ export default {
   effects: {
     *getPlatformMenu({ callback, payload }, { put, call }) {
       const allMenu = yield call(getMenuData, payload);
-      const response = yield call(queryCurrentV2);
+      const response = yield call(queryCurrent);
       let permission = {};
       if (response && allMenu) {
         for (let i = 0; i < response?.data?.Permissions?.length; i++) {

+ 4 - 3
src/Project/services/platformMenu.js

@@ -1,6 +1,7 @@
-import { stringify } from 'qs';
 import { request } from 'umi';
-// import { stringify } from 'qs';
+
 export async function getMenuData(params = {}) {
-  return request(`/api/v1/menu?${stringify(params)}`);
+  return request(`/api/v1/menu`, {
+    params: params,
+  });
 }

+ 18 - 1
src/Project/services/typings.d.ts

@@ -2,9 +2,26 @@ declare namespace Api {
   interface IUser {
     CName: string;
     IsSuper: boolean;
-    isLogin: boolean;
+    DefaultProject: string;
+    Email: string;
+    ForbiddenModule: number;
+    ID: number;
+    Mobile: string;
+    UserName: string;
+    IsDepLeader: number;
+    Status: number;
+    UserType: number;
+    is_accountant: number;
+    is_leader: number;
+    is_opt_mgr: number;
+    is_wty_mgr: number;
   }
   interface IAccess {
     [key: string]: boolean;
   }
+  interface IResponseStructure {
+    code: number;
+    data: any;
+    msg?: string;
+  }
 }

+ 0 - 3
src/Project/services/user.ts

@@ -25,9 +25,6 @@ export async function queryDepList(userName: string) {
 export async function queryCurrent(): Promise<Api.IUser> {
   return request('/api/v2/user/current-user');
 }
-export async function queryCurrentV2() {
-  return request('/api/v2/user/current-user', { method: 'GET' });
-}
 
 // 获取角色在此项目下的权限
 export async function queryAccess(

+ 5 - 7
src/access.ts

@@ -1,11 +1,9 @@
-
 export default (initialState: any) => {
   // 在这里按照初始化数据定义项目中的权限,统一管理
   // 参考文档 https://next.umijs.org/docs/max/access
-  const canSeeAdmin = !!(
-    initialState && initialState.name !== 'dontHaveAccess'
-  );
-  return {
-    canSeeAdmin,
-  };
+
+  if (!initialState || !initialState.access) return {};
+  const { access } = initialState;
+
+  return access;
 };

+ 69 - 13
src/app.ts

@@ -1,24 +1,80 @@
 // 运行时配置
 import type { RequestConfig } from 'umi';
 import { queryCurrent, queryAccess } from '@/Project/services/user';
-import { LocalService } from './Engine/Storage';
-import { SysStorage } from './Frameworks/SysStorage';
+import { STORAGE_TYPE, LocalService } from './Frameworks/SysStorage';
+import { message } from 'antd';
 // 全局初始化数据配置,用于 Layout 用户信息和权限初始化
 // 更多信息见文档:https://next.umijs.org/docs/api/runtime-config#getinitialstate
 export async function getInitialState(): Promise<any> {
-  // const currentUser = await queryCurrent();
-  // const access = await queryAccess(46);
-
-  return { currentUser: {}, access: {}, projectId: 0 };
+  let currentUser = {},
+    access = {};
+  // 非登录页获取用户信息
+  if (!window.GT_APP.funcLogin.IsActive) {
+    try {
+      currentUser = await queryCurrent();
+    } catch (error) {}
+    try {
+      access = await queryAccess(46);
+    } catch (error) {}
+  }
+  return { currentUser, access, projectId: 0 };
 }
 
 // axios配置
 export const request: RequestConfig = {
-  headers: { 'JWT-TOKEN': LocalService.getItem(SysStorage.token) },
-  // errorConfig: {
-  //   errorHandler() {},
-  //   errorThrower() {},
-  // },
-  // requestInterceptors: [],
-  // responseInterceptors: [],
+  errorConfig: {
+    errorThrower(res: Api.IResponseStructure) {
+      // const { data, code, msg } = res;
+      // if (code !== 200) {
+      //   const error: any = new Error(msg);
+      //   error.name = 'AjaxError';
+      //   error.info = { code, msg, data };
+      //   throw error;
+      // }
+      console.log('errorThrower', res);
+    },
+    errorHandler(error: any, opts: any) {
+      if (opts?.skipErrorHandler) throw error;
+      // 我们的 errorThrower 抛出的错误。
+      if (error.name === 'AjaxError') {
+        const errorInfo: Api.IResponseStructure | undefined = error.info;
+        const inLoginPage = window.GT_APP.funcLogin.IsActive;
+        if (!inLoginPage && errorInfo) {
+          message.error(errorInfo.msg || errorInfo.data);
+        }
+      } else if (error.response) {
+        // Axios 的错误
+        // 请求成功发出且服务器也响应了状态码,但状态代码超出了 2xx 的范围
+        message.error(`网络连接错误,请稍后重试(${error.response.status})`);
+      } else if (error.request) {
+        // 请求已经成功发起,但没有收到响应
+        // \`error.request\` 在浏览器中是 XMLHttpRequest 的实例,
+        // 而在node.js中是 http.ClientRequest 的实例
+        message.error('网络连接错误,请稍后重试(服务器未返回数据)。');
+      } else {
+        // 发送请求时出了点问题
+        message.error('网络连接错误,请稍后重试(请求发送失败)。');
+      }
+    },
+  },
+  requestInterceptors: [
+    (config: any) => {
+      if (!config.headers) config.headers = {};
+      config.headers['JWT-TOKEN'] = LocalService.getItem(STORAGE_TYPE.token);
+      return config;
+    },
+  ],
+  responseInterceptors: [
+    (res) => {
+      const resData = res.data as Api.IResponseStructure;
+      const { code, msg, data } = resData;
+      if (code !== 200) {
+        const error: any = new Error(msg);
+        error.name = 'AjaxError';
+        error.info = { code, msg, data };
+        throw error;
+      }
+      return res;
+    },
+  ],
 };