# loginTimeout

登录超时前,提示客户是否退出。

# 核心思想

自客户登录接口调用成功之后,开始倒计时,到达约定的时间前,弹框提示用户,继续(调接口刷新token时间)还是退出。客户每次调接口的操作都会刷新倒计时时间,后端同步刷新token时间。

import React from 'react';
import ReactDOM from 'react-dom';
import TimeOutModal from '@/components/TimeOutModal';

const HandleWithLoginTimeout = () => {
  const maxTime = 60 * 60; // 60min
  const minValve = 60 * 2;
  let leaveTime = maxTime;
  let interval: any = null;

  const setRootEle = () => {
    const attr = document.createAttribute('class');
    attr.value = 'loginTimeoutRoot';

    const node = document.createElement('div');
    node.setAttributeNode(attr);

    setTimeout(() => {
      document?.querySelector('#root')?.appendChild(node);
    }, 0);
  };

  // const modalUnmount = () => {
  //   ReactDOM.unmountComponentAtNode(
  //     document.querySelector('.loginTimeoutRoot'),
  //   );
  // };
  const cancelInterval = () => {
    interval && clearInterval(interval);
    interval = null;
  };

  const resetTime = (resetTokenTime: boolean) => {
    if (resetTokenTime) {
      leaveTime = maxTime;
      // eslint-disable-next-line no-use-before-define
      !interval && startInterval();
    }
  };

  const modalMount = () => {
    ReactDOM.render(
      <TimeOutModal cancelInterval={cancelInterval} leaveTime={leaveTime} minValve={minValve} />,
      document.querySelector('.loginTimeoutRoot')
    );
  };

  const startInterval = () => {
    interval = setInterval(() => {
      leaveTime--;
      modalMount();
    }, 1000);
  };


  // start
  setRootEle();

  return resetTime;
};

export default HandleWithLoginTimeout;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

# 应用

import { request } from 'umi';
import handleLoading from '../utils/handleFullScreenLoading';
import handleWithLoginTimeout from '../utils/handleWithLoginTimeout';

type Method = 'GET' | 'POST' | 'DELETE' | 'PUT' | 'PATCH';

const resetInterval = handleWithLoginTimeout();

const calcParams = (param: { method: Method; [key: string]: any }) => {
  const { method } = param || {};
  const key = (method === 'GET' && 'params') || 'data';
  const { withoutLoading, resetTokenTime = true, ...restParams } = param[key] || {};

  const loadingId = (!withoutLoading && `request_loading_${Date.now().toString(36)}`) || '';

  return {
    params: {
      ...param,
      [key]: restParams,
    },
    loadingId,
    resetTokenTime,
  };
};

const requestWithLoading = <Res>(url: string, originParam: { method: Method; [key: string]: any }) => {
  const { params, loadingId, resetTokenTime } = calcParams(originParam);
  // loading start;
  const { closeLoading } = handleLoading(loadingId);

  return (
    request<{
      success: boolean;
      code: string;
      ext: string;
      msg: string;
      result: Res;
    }>(url, params)
      .then((res) => {
        resetInterval(resetTokenTime);
        return Promise.resolve(res);
      })
      // eslint-disable-next-line arrow-body-style
      .catch((error) => {
        return Promise.resolve({ success: false, code: '', msg: error, result: null });
      })
      .finally(() => {
        // loading end;
        closeLoading(loadingId);
      })
  );
};

export default requestWithLoading;

export function Request<T, Res>(url: string, method: Method = 'GET') {
  return (params?: T, options?: Record<string, unknown>) => {
    const key = (method === 'GET' && 'params') || 'data';

    return requestWithLoading<Res>(url, {
      method,
      [key]: params,
      ...options,
    });
  };
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66