app.tsx 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. import { queryCurrentUser, queryPermData } from './services/user'
  2. import { history, createSearchParams } from '@umijs/max'
  3. import RightContent from '@/components/RightContent'
  4. import { message, notification } from 'antd'
  5. import logo from '../public/logo.svg'
  6. import { getToken } from '@/utils/auth'
  7. import { tryChangeWorkStatus } from './components/RightContent/Book'
  8. import { getAuthCache, setAuthCache } from './utils/auth'
  9. import { LAYOUT_COLLAPSED_KEY } from './utils/cache/cacheEnum'
  10. import consts from './consts'
  11. import ModalStore from './components/ModalStore'
  12. import MessageDetail from './pages/Hr/Notification/components/MessageDetail'
  13. import defaultSettings from '../config/defaultSettings'
  14. import type { ErrorShowType, RequestConfig } from '@umijs/max'
  15. const loginPath = '/user/login'
  16. export async function getInitialState() {
  17. // 如果是登录页面,不执行
  18. const fetchUserInfo = async () => {
  19. try {
  20. const res = await queryCurrentUser()
  21. return res.data
  22. } catch (error) {
  23. history.push(loginPath)
  24. }
  25. return undefined
  26. }
  27. const fetchPermData = async () => {
  28. try {
  29. const res = await queryPermData()
  30. return res.data
  31. } catch (error) {
  32. message.error('获取数据权限失败,请联系管理员')
  33. }
  34. return {}
  35. }
  36. // 如果是登录页面,不执行
  37. if (history.location.pathname !== loginPath) {
  38. const userInfo = (await fetchUserInfo()) || {}
  39. const permData = (await fetchPermData()) || {}
  40. const collapsed = getAuthCache(LAYOUT_COLLAPSED_KEY) || false
  41. return {
  42. fetchUserInfo,
  43. fetchPermData,
  44. permData,
  45. ...userInfo,
  46. settings: { ...defaultSettings, collapsed, defaultCollapsed: collapsed }
  47. }
  48. }
  49. return {
  50. fetchUserInfo,
  51. fetchPermData,
  52. settings: { ...defaultSettings }
  53. }
  54. }
  55. export const layout = ({ initialState, setInitialState }) => {
  56. const onCollapse = collapsed => {
  57. setInitialState({ ...initialState, settings: { ...initialState.settings, collapsed } })
  58. setAuthCache(LAYOUT_COLLAPSED_KEY, collapsed)
  59. }
  60. return {
  61. logo,
  62. rightContentRender: () => (
  63. <ModalStore _modalMap={{ D_NOTICE_DETAIL: MessageDetail }}>
  64. <RightContent />
  65. </ModalStore>
  66. ),
  67. disableContentMargin: false,
  68. waterMarkProps: initialState.currentUser && {
  69. fontColor: 'rgba(0,0,0,.1)',
  70. offsetTop: 200,
  71. content: `${initialState.currentUser?.username} ${initialState.currentUser?.telephone.slice(-4)}`
  72. },
  73. onPageChange: async location => {
  74. // 如果没有登录,重定向到 login
  75. if (!initialState?.currentUser?.staffId && location.pathname !== loginPath) {
  76. history.replace({
  77. pathname: loginPath,
  78. search: createSearchParams({ redirect: window.location.pathname }).toString()
  79. })
  80. } else {
  81. location.pathname !== loginPath &&
  82. tryChangeWorkStatus(initialState?.currentUser?.staffId, location.pathname)
  83. }
  84. },
  85. childrenRender: children => <ModalStore>{children}</ModalStore>,
  86. ...initialState?.settings,
  87. breakpoint: false,
  88. onCollapse
  89. }
  90. }
  91. let notificationLimit = 0 // 最大1
  92. const errorHandler = (error: any, opts: any) => {
  93. if (opts?.skipErrorHandler) throw error
  94. if (error.name === 'BizError') {
  95. const errorInfo = error.info
  96. if (errorInfo) {
  97. if (notificationLimit >= 1) {
  98. return
  99. }
  100. const { errorMessage = '请求失败', showType, errorCode } = info
  101. if (consts.TOKEN_INVALID_CODE.includes(errorCode) && window.location.pathname !== loginPath) {
  102. history.replace({
  103. pathname: loginPath,
  104. search: createSearchParams({ redirect: window.location.pathname }).toString()
  105. })
  106. }
  107. switch (showType) {
  108. case ErrorShowType.ERROR_MESSAGE:
  109. message.error(errorMessage)
  110. break
  111. case ErrorShowType.WARN_MESSAGE:
  112. message.warn(errorMessage)
  113. break
  114. case ErrorShowType.NOTIFICATION:
  115. if (!notificationLimit) {
  116. const title = consts.TOKEN_INVALID_CODE.includes(errorCode) ? '用户信息过期' : '请求失败'
  117. notification.error({
  118. message: title,
  119. description: errorMessage
  120. })
  121. notificationLimit++
  122. }
  123. break
  124. default:
  125. break
  126. }
  127. } else if (error.response) {
  128. // Axios 的错误
  129. // 请求成功发出且服务器也响应了状态码,但状态代码超出了 2xx 的范围
  130. notification.error({
  131. description: `状态码为${error.response.status}, 请联系管理员进行处理`,
  132. message: '请求异常'
  133. })
  134. } else {
  135. // 请求已经成功发起,但没有收到响应
  136. // 或请求根本没有发送出去
  137. notification.error({
  138. description: '您的网络发生异常,无法连接服务器',
  139. message: '网络异常'
  140. })
  141. }
  142. }
  143. }
  144. const authHeaderInterceptor = (options: any) => {
  145. const token = getToken()
  146. if (token) {
  147. // 在白名单里的请求放过
  148. if (consts.TOKEN_WHITE_LIST.includes(options.url)) {
  149. return options
  150. }
  151. options.headers[consts.TOKEN_HEADER] = `bearer ${token}`
  152. }
  153. return options
  154. }
  155. export const request: RequestConfig = {
  156. errorConfig: {
  157. // 错误抛出
  158. errorThrower: (res: ResponseStructure) => {
  159. const { data, code, msg, showType } = res
  160. if (code !== consts.RET_CODE.SUCCESS) {
  161. const error: any = new Error(errorMessage)
  162. error.name = 'BizError'
  163. error.info = { errorCode: code, errorMessage: msg, showType, data }
  164. throw error // 抛出自制的错误
  165. }
  166. },
  167. errorHandler
  168. },
  169. baseURL: consts.PREFIX_URL,
  170. requestInterceptors: [authHeaderInterceptor],
  171. responseInterceptors: [
  172. response => {
  173. // 处理notificationLimit,请求成功应重置
  174. if (
  175. notificationLimit >= 1 &&
  176. response.status === 200 &&
  177. response.data?.code === consts.RET_CODE.SUCCESS
  178. ) {
  179. notificationLimit = 0
  180. }
  181. const { code = -1 } = response?.data || {}
  182. if (code !== consts.RET_CODE.SUCCESS) {
  183. return Promise.reject(response?.data)
  184. }
  185. return Promise.resolve(response)
  186. }
  187. ]
  188. }