app.tsx 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. /*
  2. * @Author: your name
  3. * @Date: 2021-09-03 14:28:27
  4. * @LastEditors: code4eat awesomedema@gmail.com
  5. * @Description: In User Settings Edit
  6. * @FilePath: /MedicalWisdomCheckSys/src/app.tsx
  7. */
  8. import type { Settings as LayoutSettings } from '@ant-design/pro-layout';
  9. import { RunTimeLayoutConfig } from 'umi';
  10. import { history, Link } from 'umi';
  11. import { notification, Modal } from 'antd';
  12. // import 'yet-another-abortcontroller-polyfill'
  13. import RightContent from '@/components/RightContent';
  14. import { BookOutlined, LinkOutlined } from '@ant-design/icons';
  15. import iconEnum from './menuIcons';
  16. import { loginOut } from '@/utils';
  17. import logoIcon from '../public/logo.png';
  18. import { getMenus } from './services/user';
  19. import { updateUserInfo } from '@/pages/user/Login/service';
  20. import type { RequestOptionsInit, Context } from 'umi-request';
  21. const isDev = process.env.NODE_ENV === 'development';
  22. const loginPath = '/user/login';
  23. let hospSign: any = '';
  24. let ifStopNextRequet: boolean = false; // 控制当出现token过期阻止后面弹窗提示
  25. if (history) {
  26. hospSign = history.location.query?.hospSign;
  27. if (!hospSign) {
  28. hospSign = localStorage.getItem('hospSign');
  29. }
  30. }
  31. /** 获取用户信息比较慢的时候会展示一个 loading */
  32. // export const initialStateConfig = {
  33. // loading: <PageLoading />,
  34. // };
  35. export type menuDataItemType = {
  36. path: string,
  37. name: string,
  38. icon: any,
  39. component: string,
  40. softUrl?: string, // 帆软url
  41. children?: menuDataItemType[]
  42. }
  43. /**
  44. * @see https://umijs.org/zh-CN/plugins/plugin-initial-state
  45. * */
  46. export async function getInitialState(): Promise<{
  47. settings?: Partial<LayoutSettings>;
  48. currentUser?: API.CurrentUserData;
  49. logo?: string;
  50. isDev?: boolean,
  51. spacicalPageParamsType?: any[];
  52. goSetting?: boolean,// 设置栏触发
  53. resetPasswordHandle?: (formData: any) => Promise<boolean>,
  54. fetchUserMenu?: () => Promise<menuDataItemType[]>,
  55. menu?: menuDataItemType[],
  56. clearUserData?: () => Promise<boolean>; // 清空用户数据
  57. fetchUserInfo?: () => Promise<API.CurrentUser | undefined>;
  58. postDataToTop?: (data: any) => Promise<boolean>,
  59. }> {
  60. const fetchUserInfo = async () => {
  61. try {
  62. const userData = localStorage.getItem('userData');
  63. if (userData) {
  64. return JSON.parse(userData);
  65. }
  66. throw Error;
  67. } catch (error) {
  68. // history.push(`${loginPath}?hospSign=${hospSign}`);
  69. }
  70. return undefined;
  71. };
  72. const fetchUserMenu = async () => {
  73. const localMasterData = localStorage.getItem('initialState');
  74. if (localMasterData) {
  75. const { openedSysLists } = JSON.parse(localMasterData);
  76. const currentSys = openedSysLists.filter((t:any) => t.name == '评审管理');
  77. const systemId = currentSys.length > 0 ? currentSys[0].id : 0;
  78. const menu = await getMenus(systemId);
  79. if (menu) {
  80. return menu;
  81. }
  82. }
  83. return [];
  84. }
  85. const resetPasswordHandle = async (data: API.EditUserInfoType) => {
  86. const resp = await updateUserInfo(data);
  87. if (resp) {
  88. return Promise.resolve(true);
  89. }
  90. return Promise.resolve(false);
  91. }
  92. const clearUserData = () => {
  93. localStorage.removeItem('userData');
  94. return Promise.resolve(true);
  95. };
  96. // 如果是登录页面,不执行
  97. if (history.location.pathname !== loginPath) {
  98. const currentUser = await fetchUserInfo();
  99. return {
  100. fetchUserInfo,
  101. currentUser,
  102. logo: logoIcon,
  103. clearUserData,
  104. menu: [],
  105. fetchUserMenu,
  106. resetPasswordHandle,
  107. isDev: process.env.NODE_ENV == 'development',
  108. settings: {
  109. navTheme: 'light',
  110. layout: 'side'
  111. },
  112. };
  113. }
  114. return {
  115. fetchUserInfo,
  116. settings: {},
  117. };
  118. }
  119. const authHeaderInterceptor = (url: string, options: RequestOptionsInit) => {
  120. const userData = localStorage.getItem('userData');
  121. const authHeader = { token: '' };
  122. if (userData) {
  123. const { token }: API.CurrentUserData = JSON.parse(userData);
  124. authHeader.token = token;
  125. }
  126. return {
  127. url: `${url}`,
  128. options: { ...options, interceptors: true, headers: authHeader },
  129. };
  130. };
  131. interface responseInterceptorsOptions extends RequestOptionsInit {
  132. isCloseNotify?: boolean, // 是否关闭POST请求后反馈
  133. responseSpecifyFeedback?: {
  134. successMessage: string,
  135. errorMessage: string,
  136. isShow: boolean, // 是否启用
  137. }
  138. }
  139. const responseInterceptors = async (response: Response, options: responseInterceptorsOptions) => {
  140. // console.log({response,options});
  141. const requestMethod = options.method;
  142. const { url, responseSpecifyFeedback, isCloseNotify = false } = options;
  143. try {
  144. const { status } = response;
  145. if (status == 200) {
  146. // 网络请求成功
  147. const _response = await response.clone().json();
  148. const restext = await response.clone().text();
  149. console.log({restext});
  150. const { status: dataStatus, errorCode, errorMessage, data } = _response;
  151. if (dataStatus == 200) {
  152. // 接口请求成功
  153. if (requestMethod == 'POST' && url != "/api/pfm/login" && !isCloseNotify) {
  154. if (responseSpecifyFeedback && responseSpecifyFeedback.isShow) {
  155. // 当指定了请求成功反馈时
  156. console.log({ responseSpecifyFeedback });
  157. console.log(responseSpecifyFeedback.successMessage);
  158. notification.success({
  159. message: responseSpecifyFeedback.successMessage
  160. });
  161. } else {
  162. // 否则用默认提示
  163. notification.success({
  164. message: '操作成功!'
  165. });
  166. }
  167. }
  168. if (data) {
  169. return data;
  170. }
  171. return true;
  172. } if (errorCode == 499) {
  173. if (!ifStopNextRequet) {
  174. Modal.confirm({
  175. title: '抱歉,登录已过期请重新登录!',
  176. onOk: () => {
  177. ifStopNextRequet = false;
  178. loginOut();
  179. }
  180. });
  181. }
  182. ifStopNextRequet = true;
  183. } else {
  184. // 接口请求信息错误
  185. notification.error({
  186. message: errorMessage
  187. });
  188. }
  189. } else {
  190. // 网络请求失败
  191. notification.error({
  192. message: '服务器错误!'
  193. });
  194. throw Error;
  195. }
  196. } catch (error) {
  197. console.log({ error });
  198. }
  199. };
  200. const demo1Middleware = async (ctx: Context, next: () => void) => {
  201. await next();
  202. };
  203. type RequestConfig = Record<string, any>
  204. export const request: RequestConfig = {
  205. // 新增自动添加AccessToken的请求前拦截器
  206. errorHandler: (error: any) => {
  207. console.log({ error });
  208. throw error;
  209. },
  210. middlewares: [demo1Middleware],
  211. requestInterceptors: [authHeaderInterceptor],
  212. responseInterceptors: [responseInterceptors],
  213. };
  214. // 将服务端获取的菜单 icon 字符串映射为对应的 icon Dom
  215. const mappingIcon = (menuData: menuDataItemType[]) => {
  216. if (menuData.length == 0) {
  217. return [
  218. {
  219. path: '',
  220. name: '',
  221. icon: '',
  222. component: './404',
  223. }
  224. ]
  225. }
  226. const mappingMenu: menuDataItemType[] = menuData.map(item => ({
  227. ...item,
  228. icon: item.icon && iconEnum[item.icon],
  229. children: item.children ? mappingIcon(item.children) : [],
  230. }));
  231. return mappingMenu;
  232. };
  233. // ProLayout 支持的api https://procomponents.ant.design/components/layout
  234. export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) => {
  235. return {
  236. logo: initialState?.logo,
  237. rightContentRender: () => <RightContent />,
  238. disableContentMargin: false,
  239. menuProps:{
  240. // onClick:({ key, keyPath, domEvent })=>{
  241. // console.log({ key, keyPath, domEvent});
  242. // history.push('/reports/a?w=1')
  243. // }
  244. },
  245. menu: {
  246. params: {
  247. currentUser: initialState?.currentUser
  248. },
  249. request: async () => {
  250. // initialState.currentUser 中包含了所有用户信息
  251. if (initialState) {
  252. const { currentUser, isDev } = initialState;
  253. if (false) {
  254. // 开发环境
  255. return []
  256. }
  257. if (currentUser) {
  258. const currentSelectedTab = localStorage.getItem('currentSelectedTab');
  259. if (currentSelectedTab) {
  260. const { menuId } = JSON.parse(currentSelectedTab);
  261. const systemId = menuId;
  262. const data: any[] = await getMenus(systemId);
  263. if (data) {
  264. await setInitialState(t => ({ ...t, menu: data }));
  265. /**
  266. *
  267. * 菜单跳转报表临时处理,后期统一换成中台调用
  268. */
  269. const getVFromTree = (data: any[], key: string) => {
  270. let result: any[] = [];
  271. function looper(data: any[], key: string) {
  272. data.forEach((t) => {
  273. if (t[key] && t[key] != 0) {
  274. //非一般页面
  275. result.push({
  276. contentType: t[key],
  277. path: t['path'],
  278. reportId: t['reportId'],
  279. url: t['youshuUrl'],
  280. });
  281. }
  282. if (t.children && t.children.length > 0) {
  283. looper(t.children, key);
  284. }
  285. });
  286. }
  287. looper(data, key);
  288. return result;
  289. };
  290. const _menu = getVFromTree(data, 'contentType');
  291. setInitialState((t) => ({ ...t, spacicalPageParamsType: _menu }));
  292. /////////////////////////////--------临时处理----------///////////////////////////////////////////////
  293. return mappingIcon(data);
  294. }
  295. }
  296. } else {
  297. return [
  298. {
  299. component: './404',
  300. }
  301. ]
  302. }
  303. }
  304. return []
  305. },
  306. },
  307. links: isDev
  308. ? [
  309. <Link to="/umi/plugin/openapi" target="_blank">
  310. <LinkOutlined />
  311. <span>OpenAPI 文档</span>
  312. </Link>,
  313. <Link to="/~docs">
  314. <BookOutlined />
  315. <span>业务组件文档</span>
  316. </Link>,
  317. ]
  318. : [],
  319. menuHeaderRender: undefined,
  320. // 自定义 403 页面
  321. // unAccessible: <div>unAccessible</div>,
  322. ...initialState?.settings,
  323. };
  324. };