app.tsx 11 KB

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