diff --git a/components/aside/footer.tsx b/components/aside/footer.tsx index e3091f6..a8d6d9c 100644 --- a/components/aside/footer.tsx +++ b/components/aside/footer.tsx @@ -1,14 +1,14 @@ -import React, { FC, useMemo, useContext } from 'react' import { Popconfirm } from 'antd' +import React, { FC, useContext, useMemo } from 'react' +import getLoginInfo from '../utils/getLoginInfo' +import { toConsoleLogin } from '../utils/token' +import WrapperContext from '../wrapper/wrapperContext' import { PoweroffOutlined, DoubleRightOutlined, DoubleLeftOutlined, AppstoreOutlined, } from '@ant-design/icons' -import { toConsoleLogin } from 'auto-libs' -import getLoginInfo from '../utils/getLoginInfo' -import WrapperContext from '../wrapper/wrapperContext' const Footer: FC<{ collapsed: boolean diff --git a/components/dev-login/index.tsx b/components/dev-login/index.tsx index bb5cf99..e78aed5 100644 --- a/components/dev-login/index.tsx +++ b/components/dev-login/index.tsx @@ -1,6 +1,7 @@ +import { Button, Form, Input, message, Spin } from 'antd' import React from 'react' -import { Input, Form, Button, message, Spin } from 'antd' -import { httpConsole, setConsoleToken } from 'auto-libs' +import httpConsole from '../utils/httpConsole' +import { setConsoleToken } from '../utils/token' interface IProps { history: any @@ -38,13 +39,9 @@ class View extends React.PureComponent { }) const { username, password } = values - const res: any = await httpConsole({ - url: '/casService/login', - method: 'POST', - data: { - username, - password, - }, + const res: any = await httpConsole.post('/casService/login', { + username, + password, }) const { token, ...userInfo } = res diff --git a/components/header/index.tsx b/components/header/index.tsx index 63455ab..44c9ca9 100644 --- a/components/header/index.tsx +++ b/components/header/index.tsx @@ -1,10 +1,8 @@ -/* eslint-disable prefer-template,react/destructuring-assignment */ -import React from 'react' -import { clearConsoleToken } from 'auto-libs' -import { Layout } from 'antd' import Icon from '@ant-design/compatible/lib/icon' -// @ts-ignore +import { Layout } from 'antd' import cn from 'classnames' +import React from 'react' +import { clearConsoleToken } from '../utils/token' interface IProps { breakpoint: boolean diff --git a/components/upload/index.tsx b/components/upload/index.tsx index f96e3c9..78db19f 100644 --- a/components/upload/index.tsx +++ b/components/upload/index.tsx @@ -1,9 +1,8 @@ import { UploadOutlined } from '@ant-design/icons' import { Button, message, Upload as AntdUpload } from 'antd' import { UploadProps as AntdUploadProps } from 'antd/lib/upload' -import { httpConsole } from 'auto-libs' import React, { FC, useEffect, useState } from 'react' -/* eslint-disable no-param-reassign */ +import httpConsole from '../utils/httpConsole' export interface UploadProps extends AntdUploadProps { ticket: string diff --git a/components/utils/desensitize.ts b/components/utils/desensitize.ts new file mode 100644 index 0000000..c3761f8 --- /dev/null +++ b/components/utils/desensitize.ts @@ -0,0 +1,103 @@ +/** + * 数据脱敏 + */ +const Desensitize = { + /** + * 身份证号脱敏 + * @param str 身份证号码 + * @returns 脱敏后的身份证码 + */ + idCard(str: string): string { + return Desensitize.custom(str, 3, 4) + }, + + /** + * 手机号脱敏 + * @param str 11位手机号 + * @returns 脱敏后的11位手机号 + */ + mobile(str: string): string { + return Desensitize.custom(str, 3, 4) + }, + + /** + * 姓名脱敏 + * @param str 姓名 + * @returns 脱敏后的姓名 + */ + name(str: string): string { + return Desensitize.custom(str, 1, 0) + }, + + /** + * 车架号 + * @param str 车架号 + * @returns 脱敏后的车架号 + */ + vin(str: string): string { + return Desensitize.custom(str, 3, 3) + }, + + /** + * 车牌号 + * @param str 车牌 + * @returns 脱敏后的车牌 + */ + plateCode(str: string): string { + return Desensitize.custom(str, 2, 2) + }, + + /** + * 银行卡 + * @param str 银行卡 + * @returns 脱敏后的银行卡 + */ + bankCard(str: string): string { + return Desensitize.custom(str, str.length - 8, 0) + }, + + /** + * 邮箱 + * @param str 邮箱 + * @returns 脱敏后的邮箱 + */ + email(str: string): string { + if (str.indexOf('@') > -1) { + const [str1, str2] = str.split('@') + return Desensitize.custom(str1, 1, 0) + '@' + Desensitize.custom(str2, 0, 0) + } + + return Desensitize.custom(str, 1, 0) + }, + + /** + * 自定义脱敏 + * @param str 需要脱敏的字符串 + * @param showPrefix 显示前几位 + * @param showSuffix 显示后几位 + * @param hider 隐藏替换符,默认为 * + * @returns 脱敏后的字符串 + */ + custom(str: string, showPrefix: number, showSuffix: number, hider = '*'): string { + const sstr = String(str) + + // 传参错误的情况,不处理 + if (!sstr || showPrefix < 0 || showSuffix < 0 || !hider) { + return sstr + } + + // 需要显示的内容大于等于字符串长度,不处理 + if (showPrefix + showSuffix >= sstr.length) { + return sstr + } + + // 进行隐藏替换 + const hiderCount = Math.max(sstr.length - showPrefix - showSuffix, 0) + + const allHider = Array(hiderCount).fill(hider).join('') + + return sstr.substr(0, showPrefix) + allHider + (showSuffix > 0 ? sstr.substr(-showSuffix) : '') + }, +} + +export default Desensitize diff --git a/components/utils/httpConsole.ts b/components/utils/httpConsole.ts new file mode 100644 index 0000000..8540aa1 --- /dev/null +++ b/components/utils/httpConsole.ts @@ -0,0 +1,196 @@ +import axios, { AxiosError, AxiosResponse } from 'axios' +import Cookie from 'js-cookie' +import { clearConsoleCookie, clearConsoleToken, getConsoleToken, toConsoleLogin } from './token' + +export type ToLoginType = ((config?: AxiosResponse) => boolean) | undefined +let toLogin: ToLoginType + +interface HttpConfig { + resCode?: string + resMsg?: string + data?: any +} + +class HttpError extends Error { + msg: string + name = 'HttpError' + data: any + code = '0' + constructor(message: string, data?: HttpConfig) { + super(message) + + this.msg = message + if (data) { + this.data = data ? (data.data ? data.data : data) : null + this.code = data.resCode || '' + } + } + + toString() { + return this.message + } +} + +export interface HttpConsoleExtendParams { + /** + * return true 不执行下一步 + */ + toLogin: ToLoginType +} + +export function httpConsoleExtend(params: HttpConsoleExtendParams) { + const { toLogin: initialToLogin } = params || {} + + if (initialToLogin) { + toLogin = initialToLogin + } +} + +/** + * 配置axios + */ + +const httpConsole = axios.create({ + baseURL: '/', + headers: { + Accept: 'application/json;version=3.0;compress=false', + 'Content-Type': 'application/json;charset=utf-8', + }, + data: {}, +}) + +/** + * 请求拦截器,在发起请求之前 + */ +httpConsole.interceptors.request.use(config => { + const token = getConsoleToken() + const utmSource = Cookie.get('utm_source') + const utmMedium = Cookie.get('utm_medium') + const utmCampaign = Cookie.get('utm_campaign') + const utmTerm = Cookie.get('utm_term') + + const method = (config.method as string).toLocaleLowerCase() + if (token) { + config.headers.Authorization = token + } + if (method === 'get') { + if (typeof config.params !== 'object') { + config.params = {} + } + + // 兼容appserver的接口,appserver的接口token需要带在参数中,post请求也是一样 + if (token) { + config.params.token = token + } + if (utmSource) { + config.params.utmSource = utmSource + } + if (utmMedium) { + config.params.utmMedium = utmMedium + } + if (utmCampaign) { + config.params.utmCampaign = utmCampaign + } + if (utmTerm) { + config.params.utmTerm = utmTerm + } + + config.params.requestId = Number(new Date()) + } + + const methods: string[] = ['post', 'put', 'patch', 'delete'] + if (methods.indexOf(method) > -1 && typeof config.data !== 'string') { + if (token) { + config.data.token = token + } + if (utmSource) { + config.data.utmSource = utmSource + } + if (utmMedium) { + config.data.utmMedium = utmMedium + } + if (utmCampaign) { + config.data.utmCampaign = utmCampaign + } + if (utmTerm) { + config.data.utmTerm = utmTerm + } + config.data.requestId = Number(new Date()) + } + + ;(config as any).____t = new Date().valueOf() + + return config +}) + +/** + * 接口响应拦截器,在接口响应之后 + */ +httpConsole.interceptors.response.use( + config => { + let strictModel = true // 严格模式 + const data = config.data || {} + + if (toLogin && toLogin(config) === true) { + return + } + + // 目前的判断方式:因为resCode与resMsg是java端必给的字段,所以认为没有该两个字段时,走标准的http status模式 + if (typeof data.resCode !== 'undefined' && typeof data.resMsg !== 'undefined') { + strictModel = false + } + + if (strictModel) { + if (config.status >= 200 && config.status < 300) { + return data + } else { + if (config.status === 401) { + clearConsoleCookie() + clearConsoleToken() + toConsoleLogin() + return false + } + + return Promise.reject(new HttpError(data.message || '', data)) + } + } + + // atcz java端的模式 + + // 响应正常 + if (data.resCode === '000000') { + return data.data + } + // 需要登录(没登录或登录过期) + else if (data.resCode === '200008') { + clearConsoleCookie() + clearConsoleToken() + toConsoleLogin() + return false + } + + // reject错误处理 + return Promise.reject(new HttpError(data.resMsg || data.msg || data.message, data)) + }, + (error: AxiosError) => { + console.error('http:reject', error) + + if (toLogin && toLogin(error.response) === true) { + return + } + + if (error.response && error.response.status === 401) { + clearConsoleCookie() + clearConsoleToken() + toConsoleLogin() + return false + } + + // reject错误处理 + const { data } = error.response || {} + const { message = '系统错误', msg, resMsg } = data || {} + return Promise.reject(new HttpError(resMsg || msg || message)) + }, +) + +export default httpConsole diff --git a/components/utils/showDesensitize.ts b/components/utils/showDesensitize.ts index e2e0c82..453fdcf 100644 --- a/components/utils/showDesensitize.ts +++ b/components/utils/showDesensitize.ts @@ -1,5 +1,5 @@ -import { Desensitize } from 'auto-libs' import { ReactNode } from 'react' +import Desensitize from '../utils/desensitize' import { isFunc } from './is' export type DesensitizeType = diff --git a/components/utils/token.ts b/components/utils/token.ts new file mode 100644 index 0000000..7d88dc7 --- /dev/null +++ b/components/utils/token.ts @@ -0,0 +1,56 @@ +import Cookie from 'js-cookie' +import qs from 'qs' + +const consoleToken = '_app_console_token_' +const oldConsoleToken = 'auto_system_token' +const consoleInfoToken = '_app_console_userinfo_' +const oldConsoleInfoToken = 'auto_system_userData' +const ls = window.localStorage + +// 获取管理后台token方法,即jwt +const getConsoleToken = () => ls.getItem(consoleToken) +const setConsoleToken = (e: string) => ls.setItem(consoleToken, e) +const clearConsoleToken = () => { + ls.removeItem(oldConsoleToken) + ls.removeItem(consoleToken) +} + +// 跳转管理后台登录 +const toConsoleLogin = () => { + clearConsoleToken() + const search = { + redirect: window.location.href, + } + window.location.href = '/system/login/?' + qs.stringify(search) +} + +// 获取管理后台登录cookie +const getConsoleCookie = () => Cookie.get(consoleToken) +const setConsoleCookie = (e: string) => Cookie.set(consoleToken, e) +const clearConsoleCookie = () => { + Cookie.remove(oldConsoleToken) + Cookie.remove(consoleToken) +} + +const getConsoleLoginInfo = () => { + const value = window.localStorage.getItem(consoleInfoToken) + const oldValue = window.localStorage.getItem(oldConsoleInfoToken) + const emptyObj = {} + + try { + return value ? JSON.parse(value) : oldValue ? JSON.parse(oldValue) : emptyObj + } catch (error) { + return emptyObj + } +} + +export { + getConsoleToken, + setConsoleToken, + clearConsoleToken, + toConsoleLogin, + getConsoleCookie, + setConsoleCookie, + clearConsoleCookie, + getConsoleLoginInfo, +} diff --git a/components/wrapper/index.tsx b/components/wrapper/index.tsx index dd016cd..6cdc2db 100644 --- a/components/wrapper/index.tsx +++ b/components/wrapper/index.tsx @@ -1,12 +1,12 @@ +import { Breadcrumb, message, Skeleton } from 'antd' import React, { FC, useEffect, useLayoutEffect, useState } from 'react' -import { message, Breadcrumb, Skeleton } from 'antd' -import { httpConsole } from 'auto-libs' -import { useLocation, Link } from 'react-router-dom' +import { Link, useLocation } from 'react-router-dom' import Aside from '../aside' import useStates from '../hooks/useStates' -import { IMenu, getMenusTree, getMenuPaths } from '../utils/menusHandler' -import WrapperContext from './wrapperContext' +import httpConsole from '../utils/httpConsole' import { isFunc } from '../utils/is' +import { getMenuPaths, getMenusTree, IMenu } from '../utils/menusHandler' +import WrapperContext from './wrapperContext' export interface WrapperProps { /** diff --git a/package.json b/package.json index 638306e..4170b06 100644 --- a/package.json +++ b/package.json @@ -56,8 +56,9 @@ "@ant-design/compatible": "^1.0.8", "@ant-design/icons": "^4.3.0", "@babel/runtime": "^7.12.5", - "auto-libs": "^0.3.53", + "@types/js-cookie": "^3.0.3", "classnames": "^2.2.6", + "js-cookie": "^3.0.5", "lodash": "^4.17.19" }, "peerDependencies": { diff --git a/yarn.lock b/yarn.lock index 2881e19..6b0d23a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2417,6 +2417,11 @@ jest-diff "^26.0.0" pretty-format "^26.0.0" +"@types/js-cookie@^3.0.3": + version "3.0.3" + resolved "https://registry.npmmirror.com/@types/js-cookie/-/js-cookie-3.0.3.tgz#d6bfbbdd0c187354ca555213d1962f6d0691ff4e" + integrity sha512-Xe7IImK09HP1sv2M/aI+48a20VX+TdRJucfq4vfRVy6nWN8PYPOEnlMRSgxJAgYQIXJVL8dZ4/ilAM7dWNaOww== + "@types/json-schema@^7.0.3", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.6": version "7.0.6" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.6.tgz#f4c7ec43e81b319a9815115031709f26987891f0" @@ -4273,11 +4278,6 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= -at-js-bridge@^1.0.22: - version "1.0.26" - resolved "https://registry.yarnpkg.com/at-js-bridge/-/at-js-bridge-1.0.26.tgz#062efea72fe3fe6b3e8c56bdd90d3e141b435281" - integrity sha512-Hgm6uII5PeaVqXUpv2YzLMZ6/zdQBCnckcVf5SO25pazJIgpOd5rYwr4opXZN715j4WC/EvOHNL5dcdcNPAGQA== - at-least-node@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" @@ -4288,19 +4288,6 @@ atob@^2.1.2: resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== -auto-libs@^0.3.53: - version "0.3.53" - resolved "https://registry.nlark.com/auto-libs/download/auto-libs-0.3.53.tgz#5123a38cc3a11a46cd9746cfd75b1fe9f462e154" - integrity sha1-USOjjMOhGkbNl0bP11sf6fRi4VQ= - dependencies: - "@babel/runtime" "^7.12.5" - at-js-bridge "^1.0.22" - axios "0.18.0" - crypto-js "^4.0.0" - js-cookie "^2.2.0" - qs "^6.5.2" - weixin-js-sdk "^1.4.0-test" - autoprefixer@9.6.0: version "9.6.0" resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.6.0.tgz#0111c6bde2ad20c6f17995a33fad7cf6854b4c87" @@ -4337,14 +4324,6 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== -axios@0.18.0: - version "0.18.0" - resolved "https://registry.npm.taobao.org/axios/download/axios-0.18.0.tgz?cache=0&sync_timestamp=1608611162952&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Faxios%2Fdownload%2Faxios-0.18.0.tgz#32d53e4851efdc0a11993b6cd000789d70c05102" - integrity sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI= - dependencies: - follow-redirects "^1.3.0" - is-buffer "^1.1.5" - babel-code-frame@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" @@ -6186,11 +6165,6 @@ crypto-browserify@^3.11.0: randombytes "^2.0.0" randomfill "^1.0.3" -crypto-js@^4.0.0: - version "4.0.0" - resolved "https://registry.npm.taobao.org/crypto-js/download/crypto-js-4.0.0.tgz#2904ab2677a9d042856a2ea2ef80de92e4a36dcc" - integrity sha1-KQSrJnep0EKFai6i74DekuSjbcw= - crypto-random-string@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" @@ -8135,11 +8109,6 @@ follow-redirects@^1.0.0: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db" integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA== -follow-redirects@^1.3.0: - version "1.14.1" - resolved "https://registry.nlark.com/follow-redirects/download/follow-redirects-1.14.1.tgz?cache=0&sync_timestamp=1620555292056&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ffollow-redirects%2Fdownload%2Ffollow-redirects-1.14.1.tgz#d9114ded0a1cfdd334e164e6662ad02bfd91ff43" - integrity sha1-2RFN7Qoc/dM04WTmZirQK/2R/0M= - for-in@^0.1.3: version "0.1.8" resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1" @@ -10639,10 +10608,10 @@ joi2types@~1.0.7: "@types/json-schema" "^7.0.4" json-schema-to-typescript "^8.2.0" -js-cookie@^2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8" - integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ== +js-cookie@^3.0.5: + version "3.0.5" + resolved "https://registry.npmmirror.com/js-cookie/-/js-cookie-3.0.5.tgz#0b7e2fd0c01552c58ba86e0841f94dc2557dcdbc" + integrity sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw== "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" @@ -14356,7 +14325,7 @@ qs@6.7.0: resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== -qs@^6.5.2, qs@^6.9.1: +qs@^6.9.1: version "6.9.4" resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.4.tgz#9090b290d1f91728d3c22e54843ca44aea5ab687" integrity sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ== @@ -18488,11 +18457,6 @@ websocket-extensions@>=0.1.1: resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== -weixin-js-sdk@^1.4.0-test: - version "1.6.0" - resolved "https://registry.yarnpkg.com/weixin-js-sdk/-/weixin-js-sdk-1.6.0.tgz#ff50484d8118ce1208f11248cf4a1c0831577514" - integrity sha512-3IYQH7aalJGFJrwdT3epvTdR1MboMiH7vIZ5BRL2eYOJ12BNah7csoMkmSZzkq1+l92sSq29XdTCVjCJoK2sBQ== - whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0"