Forráskód Böngészése

重新设计个人设置界面/优化部分代码

code4eat 3 éve
szülő
commit
9cef0d7e1e
50 módosított fájl, 3557 hozzáadás és 775 törlés
  1. 9 1
      config/config.ts
  2. 4 2
      config/proxy.ts
  3. 1 0
      package.json
  4. 25 18
      src/app.tsx
  5. 9 7
      src/components/KCUpload/index.tsx
  6. 11 5
      src/components/topBar/index.tsx
  7. 2 1
      src/components/topBar/typings.d.ts
  8. 4 0
      src/global.less
  9. 2 2
      src/global.tsx
  10. 12 51
      src/layouts/index.tsx
  11. 0 68
      src/pages/index/components/iframePage/index.tsx
  12. 0 30
      src/pages/index/components/iframePage/style.less
  13. 0 150
      src/pages/index/components/topBar/index.tsx
  14. 0 222
      src/pages/index/components/topBar/style.less
  15. 5 7
      src/pages/index/index.tsx
  16. 0 1
      src/pages/login/index.tsx
  17. 79 0
      src/pages/personalCenter/_mock.ts
  18. 65 0
      src/pages/personalCenter/components/BaseView.less
  19. 42 0
      src/pages/personalCenter/components/PhoneView.tsx
  20. 235 0
      src/pages/personalCenter/components/base.tsx
  21. 46 0
      src/pages/personalCenter/components/binding.tsx
  22. 44 0
      src/pages/personalCenter/components/notification.tsx
  23. 190 0
      src/pages/personalCenter/components/security.tsx
  24. 43 0
      src/pages/personalCenter/data.d.ts
  25. 1784 0
      src/pages/personalCenter/geographic/city.json
  26. 138 0
      src/pages/personalCenter/geographic/province.json
  27. 111 0
      src/pages/personalCenter/index.tsx
  28. 18 0
      src/pages/personalCenter/service.ts
  29. 98 0
      src/pages/personalCenter/style.less
  30. 50 5
      src/pages/platform/_layout.tsx
  31. 33 40
      src/pages/platform/components/menuEditer/menu.tsx
  32. 1 0
      src/pages/platform/components/menuEditer/style.less
  33. 28 13
      src/pages/platform/setting/hospManage/index.tsx
  34. 150 33
      src/pages/platform/setting/hospManage/modals/modal.tsx
  35. 38 9
      src/pages/platform/setting/hospManage/model.ts
  36. 9 23
      src/pages/platform/setting/menuManage/index.tsx
  37. 73 15
      src/pages/platform/setting/menuManage/modals/modal.tsx
  38. 55 0
      src/pages/platform/setting/reports/index.tsx
  39. 7 13
      src/pages/platform/setting/roleManage/index.tsx
  40. 24 7
      src/pages/platform/setting/roleManage/modals/modal.tsx
  41. 3 14
      src/pages/platform/setting/userManage/index.tsx
  42. 2 6
      src/pages/platform/setting/userManage/model.ts
  43. 19 0
      src/password-quality-calculator.d.ts
  44. 2 1
      src/service/api.d.ts
  45. 44 5
      src/service/hospList.ts
  46. 8 6
      src/service/login.ts
  47. 4 9
      src/service/role.ts
  48. 19 7
      src/service/user.ts
  49. 9 1
      src/typings.d.ts
  50. 2 3
      src/utils.ts

+ 9 - 1
config/config.ts

@@ -1,7 +1,7 @@
 /*
  * @Author: your name
  * @Date: 2022-01-07 10:04:20
- * @LastEditTime: 2022-02-14 16:28:05
+ * @LastEditTime: 2022-03-04 15:53:22
  * @LastEditors: Please set LastEditors
  * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  * @FilePath: /KC-MiddlePlatform/config/config.ts
@@ -67,8 +67,16 @@ export default defineConfig({
               path: '/platform/setting/roleManage',
               component: '@/pages/platform/setting/roleManage/index.tsx',
             },
+            {
+              path: '/platform/setting/reports',
+              component: '@/pages/platform/setting/reports/index.tsx',
+            },
           ],
         },
+        {
+          path: '/personalCenter',
+          component: '@/pages/personalCenter/index.tsx',
+        },
         { path: '/login', layout: false, component: '@/pages/login/index' },
       ],
     },

+ 4 - 2
config/proxy.ts

@@ -1,7 +1,7 @@
 /*
  * @Author: your name
  * @Date: 2022-01-07 10:00:52
- * @LastEditTime: 2022-02-14 16:17:25
+ * @LastEditTime: 2022-03-03 18:50:54
  * @LastEditors: Please set LastEditors
  * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  * @FilePath: /KC-MiddlePlatform/config/proxy.ts
@@ -10,6 +10,8 @@
 //118.31.245.65   线上
 //112.124.59.133  测试
 
+//192.168.50.190:7001
+
 const proxy: { [key: string]: any } = {
   dev: {
     '/master': {
@@ -18,7 +20,7 @@ const proxy: { [key: string]: any } = {
       pathRewrite: { '^/master': '' },
     },
     '/api': {
-      target: 'http://192.168.50.176:8083/',
+      target: 'http://112.124.59.133:8083/',
       changeOrigin: true,
       pathRewrite: { '^/api': '' },
     },

+ 1 - 0
package.json

@@ -29,6 +29,7 @@
     "@ant-design/pro-layout": "^6.15.3",
     "@ant-design/pro-table": "^2.30.8",
     "cross-env": "^7.0.3",
+    "password-quality-calculator": "^1.0.4",
     "react": "16.x",
     "react-dev-inspector": "^1.1.1",
     "react-dom": "16.x",

+ 25 - 18
src/app.tsx

@@ -1,7 +1,7 @@
 /*
  * @Author: your name
  * @Date: 2021-11-09 13:57:41
- * @LastEditTime: 2022-02-14 17:33:26
+ * @LastEditTime: 2022-03-08 17:12:17
  * @LastEditors: Please set LastEditors
  * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  * @FilePath: /KC-MiddlePlatform/src/app.ts
@@ -12,13 +12,12 @@ import { PageLoading } from '@ant-design/pro-layout';
 import { notification, Modal } from 'antd';
 import { RequestConfig, history } from 'umi';
 import type { RequestOptionsInit } from 'umi-request';
-import { getHospSubSystemList } from '@/service/login';
+import { getHospSubSystemList, UserDataType } from '@/service/login';
 
-import { BasicLayoutProps, Settings as LayoutSettings } from '@ant-design/pro-layout';
+import { BasicLayoutProps } from '@ant-design/pro-layout';
 import { logoutHandle } from './global';
-
-import platformIcon from '../public/images/platformIcon.png';
 import { Platforms } from './constant';
+import { SpacicalPageParamsType } from './typings';
 
 const loginPath = '/login';
 
@@ -38,15 +37,12 @@ export const initialStateConfig = {
 };
 
 type InitialStateType = {
-  userData?: {
-    name: string;
-    token: string;
-    userId: number;
-  };
+  userData?: UserDataType;
   systemLists?: userRelationInfo.OwnAppsItem[]; //当前医院可选子系统列表
   openedSysLists?: userRelationInfo.OwnAppsItem[]; //当前已打开的系统列表
   currentSelectedSys?: userRelationInfo.OwnAppsItem; //当前选中的tab
   logout?: () => Promise<boolean>;
+  spacicalPageParamsType?: SpacicalPageParamsType[];
   getHospSubSystemListFunc?: () => Promise<any[]>;
 };
 
@@ -77,7 +73,7 @@ export async function getInitialState(): Promise<InitialStateType> {
       const _data = data.map((t) => ({
         ...t,
         icon: getAppIcon(t.name),
-        url: t.name == '业务中台' ? '/platform/setting/userManage' : '/app1',
+        path: t.path,
       }));
 
       return _data;
@@ -103,6 +99,7 @@ export async function getInitialState(): Promise<InitialStateType> {
     ...JSON.parse(localInitData ? localInitData : '{}'), //覆盖,恢复tab状态
     userData,
     logout,
+    spacicalPageParamsType: [],
     getHospSubSystemListFunc,
     systemLists: systemLists,
   };
@@ -156,7 +153,7 @@ interface ErrorInfoStructure {
   success: boolean; // if request is success
   data?: any; // response data
   status?: number;
-  errorCode: string;
+  errorCode: number;
   errorMessage: string;
   showType?: number;
   traceId?: string;
@@ -169,12 +166,25 @@ interface ResponseErr extends Error {
 }
 
 const errorHandlerFunc = (error: ResponseErr) => {
-  console.log({ error });
-
   try {
     const { info } = error;
     const { errorCode, errorMessage } = info;
 
+    if (errorCode == 499) {
+      //token过期
+      Modal.confirm({
+        title: '抱歉,你的登录已过期,请重新登录!',
+        // closable:false,
+        maskClosable: false,
+        // cancelButtonProps:
+        onOk: () => {
+          logoutHandle();
+          return Promise.resolve(true);
+        },
+      });
+      return;
+    }
+
     if (errorMessage.length > 20) {
       notification.error({
         message: ` ${errorCode}:出现错误!`,
@@ -214,14 +224,10 @@ export const request: RequestConfig = {
   errorHandler: (err: any) => errorHandlerFunc(err),
   middlewares: [
     async function middlewareA(ctx, next) {
-      // console.log('A before');
       await next();
-      // console.log('A after');
     },
     async function middlewareB(ctx, next) {
-      // console.log('B before');
       await next();
-      // console.log('B after');
     },
   ],
   requestInterceptors: [requestInterceptorsHandle],
@@ -234,6 +240,7 @@ export const qiankun = fetch('/config').then(() => ({
   apps: [
     {
       name: 'app1', // 唯一 id
+      // entry: '//112.124.59.133:8804',
       entry: '//localhost:8804', // html entry
     },
   ],

+ 9 - 7
src/components/KCUpload/index.tsx

@@ -1,7 +1,7 @@
 /*
  * @Author: your name
  * @Date: 2022-01-18 09:15:26
- * @LastEditTime: 2022-01-18 11:23:33
+ * @LastEditTime: 2022-03-07 15:04:21
  * @LastEditors: Please set LastEditors
  * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  * @FilePath: /KC-MiddlePlatform/src/components/KCUpload/index.tsx
@@ -13,16 +13,18 @@ import { KCUploadType } from './typings';
 import './style.less';
 import { DownloadOutlined } from '@ant-design/icons';
 
-const KCUpload: React.FC<KCUploadType> = ({
-  title,
-  fieldProps,
-  ...restProps
-}) => {
+const KCUpload: React.FC<KCUploadType> = ({ title, fieldProps, ...restProps }) => {
   return (
     <div className="KCUpload">
       <ProFormUploadButton
         title={title}
-        fieldProps={fieldProps}
+        fieldProps={{
+          customRequest: (resp) => {
+            const { onSuccess, file } = resp;
+            onSuccess && onSuccess(file);
+          },
+          ...fieldProps,
+        }}
         icon={<DownloadOutlined />}
         {...restProps}
       />

+ 11 - 5
src/components/topBar/index.tsx

@@ -1,7 +1,7 @@
 /*
  * @Author: your name
  * @Date: 2021-11-16 09:12:37
- * @LastEditTime: 2022-02-14 11:39:52
+ * @LastEditTime: 2022-03-09 10:26:06
  * @LastEditors: Please set LastEditors
  * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  * @FilePath: /KC-MiddlePlatform/src/pages/index/components/topBar/index.tsx
@@ -50,7 +50,7 @@ const TopBar: React.FC<TopBarType> = (props) => {
 
   const _systemTabClickHandle = (item: TopBar.Tab) => {
     //导航栏tab点击
-    // console.log('tab click');
+
     setCurrentSelectedTab(item);
     onTabClick && onTabClick(item);
   };
@@ -106,20 +106,26 @@ const TopBar: React.FC<TopBarType> = (props) => {
   };
 
   useEffect(() => {
+    console.log({ openedTabs });
     if (openedTabs.length == 1) {
       //当有且仅当只有一个的时候,默认激活
-      setCurrentSelectedTab(openedTabs[0]);
-      history.push(openedTabs[0].url);
+      // setCurrentSelectedTab(openedTabs[0]);
+      // history.push(openedTabs[0].path);
     }
     if (openedTabs.length == 0) {
       //当所有tab都关闭时
       setCurrentSelectedTab(undefined);
-      history.push('/index');
+      history.replace('/index');
     }
   }, [openedTabs]);
 
   useEffect(() => {
     // console.log('Topbar props',props);
+    currentSelectedTab && _systemTabClickHandle(currentSelectedTab);
+    currentSelectedTab && setSystemTabs([...systemTabs, currentSelectedTab]);
+  }, [currentSelectedTab]);
+
+  useEffect(() => {
     setSystemTabs(openedTabs);
     currentTab && setCurrentSelectedTab(currentTab);
   }, [props]);

+ 2 - 1
src/components/topBar/typings.d.ts

@@ -1,7 +1,7 @@
 /*
  * @Author: your name
  * @Date: 2022-01-10 13:56:19
- * @LastEditTime: 2022-01-10 14:41:51
+ * @LastEditTime: 2022-03-04 11:47:59
  * @LastEditors: Please set LastEditors
  * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  * @FilePath: /KC-MiddlePlatform/src/components/topBar/typings.d.ts
@@ -13,5 +13,6 @@ declare namespace TopBar {
     name: string;
     icon: string;
     url: string;
+    path: string;
   };
 }

+ 4 - 0
src/global.less

@@ -12,4 +12,8 @@ input {
   border-right: 1px solid #f5f3f3;
 }
 
+.kcmp-ant-col-12 {
+  max-width: 100%;
+}
+
 //--------------------

+ 2 - 2
src/global.tsx

@@ -1,7 +1,7 @@
 /*
  * @Author: your name
  * @Date: 2021-12-21 11:05:37
- * @LastEditTime: 2022-02-14 15:53:08
+ * @LastEditTime: 2022-03-04 09:42:15
  * @LastEditors: Please set LastEditors
  * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  * @FilePath: /KC-MiddlePlatform/src/global.tsx
@@ -17,7 +17,7 @@ interface EventType extends Event {
 const loginPath = '/login';
 
 export const logoutHandle = async () => {
-  await logout();
+  // await logout();
   localStorage.removeItem('userData');
 };
 

+ 12 - 51
src/layouts/index.tsx

@@ -1,7 +1,7 @@
 /*
  * @Author: your name
  * @Date: 2021-11-09 13:56:33
- * @LastEditTime: 2022-02-14 17:02:18
+ * @LastEditTime: 2022-03-09 14:54:50
  * @LastEditors: Please set LastEditors
  * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  * @FilePath: /KC-MiddlePlatform/src/layouts/index.tsx
@@ -32,14 +32,11 @@ const TopHoc = ({
 
   const onTabChangeHandle = async (data: TopBar.Tab[]) => {
     await setInitialState((s) => ({ ...s, openedSysLists: [...data] }));
-    if (data.length == 0) {
-      history.push('/');
-    }
   };
 
   const onTabClickHandle = async (data: TopBar.Tab) => {
     await setInitialState((s) => ({ ...s, currentSelectedSys: data }));
-    history.push(data.url);
+    history.push(data.path);
   };
 
   const userPannelTabClickhandle = (tag: string) => {
@@ -51,52 +48,16 @@ const TopHoc = ({
     }
     if (tag == 'SETTING') {
       if (initialState) {
-        const { userData } = initialState;
-        const editUserInfoHandle = async () => {
-          const pswd = formRef.current?.getFieldValue('password');
-          if (userData) {
-            const resp = await editUsers({
-              id: userData.userId,
-              password: pswd,
-            });
-            console.log({ resp, pswd });
-          }
-        };
-
-        Modal.confirm({
-          title: '设置个人信息',
-          icon: false,
-          onOk: editUserInfoHandle,
-          width: 500,
-          okText: '确定',
-          cancelText: '取消',
-          content: (
-            <ProForm<{ password: string }>
-              formRef={formRef}
-              initialValues={{ password: null }}
-              submitter={{
-                resetButtonProps: {
-                  style: {
-                    display: 'none',
-                  },
-                },
-                submitButtonProps: {
-                  style: {
-                    display: 'none',
-                  },
-                },
-              }}
-            >
-              <ProFormText
-                width="md"
-                name="password"
-                label="修改密码"
-                tooltip="最长为10位"
-                placeholder="请输入密码"
-              />
-            </ProForm>
-          ),
-        });
+        setInitialState((s) => ({
+          ...s,
+          currentSelectedSys: {
+            id: -1,
+            name: '个人中心',
+            icon: '',
+            url: '',
+            path: '/personalCenter',
+          },
+        }));
       }
     }
   };

+ 0 - 68
src/pages/index/components/iframePage/index.tsx

@@ -1,68 +0,0 @@
-/*
- * @Author: your name
- * @Date: 2021-11-19 15:20:40
- * @LastEditTime: 2021-12-21 16:29:08
- * @LastEditors: Please set LastEditors
- * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
- * @FilePath: /KC-MiddlePlatform/src/pages/index/components/iframePage/index.tsx
- */
-
-import React, { useState, useRef } from 'react';
-import { Spin } from 'antd';
-
-import { LoadingOutlined } from '@ant-design/icons';
-
-import './style.less';
-
-export interface IframePage {
-  activedItem?: SystemListItem;
-  list: SystemListItem[];
-  onload?:()=>void,
-}
-//http://118.31.245.65:8804/user/login/?redirect=%2FDataManagement%2FpublicData&hospSign=tYAoFaa20yCAgaiy
-
-interface A extends SystemListItem {
-      onload?:()=>void
-}
-
-const Iframe = ({ id, url,onload }:A ) => {
-  const [loading, setLoading] = useState(true);
-
-  const onLoadHandle = () => {
-      onload&&onload();
-    setLoading(false);
-  };
-
-  return (
-    <iframe
-      key={id}
-      onLoad={onLoadHandle}
-      className={`iframe`}
-      src={url}
-    ></iframe>
-  );
-};
-
-const IframePage: React.FC<IframePage> = (props) => {
-  const { list, activedItem,onload } = props;
-
-  return (
-    <div className="iframeContainer">
-      {list.map((item) => (
-        <div
-          key={item.id}
-          style={{
-            position: 'absolute',
-            height: '100%',
-            width: '100%',
-            zIndex: activedItem && activedItem.id == item.id ? 9 : 1,
-          }}
-        >
-          <Iframe {...item} onload={onload} />
-        </div>
-      ))}
-    </div>
-  );
-};
-
-export default IframePage;

+ 0 - 30
src/pages/index/components/iframePage/style.less

@@ -1,30 +0,0 @@
-
-
-
-.iframeContainer {
-    position: relative;
-    .content {
-        position: absolute;
-        display: flex;
-        top:0;
-        left:0;
-        width: 100%;
-        height: 100%;
-        justify-content: center;
-        align-items: center;
-        height: calc(100vh - 48px);
-        background-color: rgb(238, 237, 237);
-        opacity: 0.8;
-        .spin {
-            display: flex;
-            flex-direction: column;
-            justify-content: center;
-            align-items: center;
-        }
-    } 
-    .iframe {
-        width: 100%;
-        height: calc(100vh - 48px);
-        border: none;
-    }
-}

+ 0 - 150
src/pages/index/components/topBar/index.tsx

@@ -1,150 +0,0 @@
-/*
- * @Author: your name
- * @Date: 2021-11-16 09:12:37
- * @LastEditTime: 2021-12-16 16:18:44
- * @LastEditors: Please set LastEditors
- * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
- * @FilePath: /KC-MiddlePlatform/src/pages/index/components/topBar/index.tsx
- */
-
-import React, { useEffect, useState } from 'react';
-import './style.less';
-
-import { Tooltip } from 'antd';
-import { LogoutOutlined, SettingOutlined } from '@ant-design/icons';
-
-import logo from '../../../../../public/images/kc-logo.png';
-import platFormMenuIcon from '../../../../../public/images/platformMenu.png';
-import tabCloseIcon from '../../../../../public/images/tabCloseIcon.png';
-
-interface TopBarType {
-  onTabChange?: (data: SystemListItem) => void; //当tab切换时回调
-  sysList?: SystemListItem[]; //可选系统列表
-  openedTabs: SystemListItem[]; //已打开的列表
-  currentTab?: SystemListItem; //当前tab
-  userPannelTabClick?: (tag: 'SETTING' | 'LOGOUT') => void;
-}
-
-const TopBar: React.FC<TopBarType> = (props) => {
-  const {
-    onTabChange,
-    sysList = [],
-    openedTabs = [],
-    currentTab,
-    userPannelTabClick,
-  } = props;
-  const [systemTabs, setSystemTabs] = useState<SystemListItem[]>([]); //已打开的tab
-  const [currentSelectedTab, setCurrentSelectedTab] =
-    useState<SystemListItem>();
-  const [ifOpenPannel, setIfOpenPannel] = useState(false);
-  const [arrowRotate, setArrowRotate] = useState(false);
-
-  const _systemTabClickHandle = (item: SystemListItem) => {
-    //导航栏tab点击
-    setCurrentSelectedTab(item);
-    onTabChange && onTabChange(item);
-  };
-
-  const _systemListClickHandle = (data: SystemListItem) => {
-    //导航栏系统菜单列表点击回调
-    onTabChange && onTabChange(data);
-  };
-
-  const _userPannelTabClick = (tag: 'SETTING' | 'LOGOUT') => {
-    //用户菜单tab点击回调
-    userPannelTabClick && userPannelTabClick(tag);
-  };
-
-  const UserPannel = () => {
-    return (
-      <div className="userPannel">
-        <div
-          className="userPannelTab"
-          onClick={() => _userPannelTabClick('SETTING')}
-        >
-          <SettingOutlined />
-          设置
-        </div>
-        <div
-          className="userPannelTab"
-          onClick={() => _userPannelTabClick('LOGOUT')}
-        >
-          <LogoutOutlined />
-          退出
-        </div>
-      </div>
-    );
-  };
-
-  useEffect(() => {
-    setSystemTabs(openedTabs);
-    currentTab && setCurrentSelectedTab(currentTab);
-  }, [props]);
-
-  return (
-    <div className="topBar">
-      <div className="logoWrap">
-        <img className="logo" src={logo} />
-      </div>
-      <div
-        className={ifOpenPannel ? 'platformMenu on' : 'platformMenu'}
-        onClick={() => setIfOpenPannel(!ifOpenPannel)}
-      >
-        <img src={platFormMenuIcon} />
-        <div className="systemPannel">
-          {sysList.map((item) => (
-            <div
-              key={item.id}
-              className="systemList"
-              onClick={() => _systemListClickHandle(item)}
-            >
-              <img src={item.icon} alt="" />
-              <span className="name">{item.name}</span>
-            </div>
-          ))}
-        </div>
-      </div>
-      {/**
-       * 已打开的tab
-       */}
-      <div className="tabWrap">
-        {systemTabs.map((item) => (
-          <div
-            key={item.id}
-            className={currentSelectedTab?.id == item.id ? 'tab on' : 'tab'}
-            onClick={() => _systemTabClickHandle(item)}
-          >
-            {item.name} <img src={tabCloseIcon} alt="close" />
-          </div>
-        ))}
-      </div>
-      <div className="userRelaInfoWrap">
-        <div className="notification">
-          <img
-            className="notificationIcon"
-            src={require('../../../../../public/images/notificationIcon.png')}
-          />
-        </div>
-        <Tooltip
-          title={<UserPannel />}
-          color="#fff"
-          onVisibleChange={(visible) => setArrowRotate(visible)}
-        >
-          <div className="user">
-            <img
-              className="avator"
-              src={require('../../../../../public/images/Mask.png')}
-            />
-            <span className="name">Mr Lawrence</span>
-            <img
-              className={arrowRotate ? 'arrow on' : 'arrow'}
-              src={require('../../../../../public/images/arrow_white.png')}
-            />
-          </div>
-        </Tooltip>
-      </div>
-    </div>
-  );
-};
-
-export default TopBar;

+ 0 - 222
src/pages/index/components/topBar/style.less

@@ -1,222 +0,0 @@
-.userPannel {
-  width: 100px;
-  background-color: white;
-  .userPannelTab {
-    display: flex;
-    flex-direction: row;
-    justify-content: space-evenly;
-    align-items: center;
-    height: 30px;
-    font-size: 14px;
-    font-family: SourceHanSansCN-Normal, SourceHanSansCN;
-    font-weight: 400;
-    color: rgb(131, 127, 127);
-    cursor: pointer;
-    border-bottom: 1px solid #eee;
-
-    &:hover {
-      background-color: #eee;
-    }
-
-    &:last-child {
-      border-bottom: none;
-    }
-  }
-}
-
-.topBar {
-  display: flex;
-  flex-direction: row;
-  justify-content: flex-start;
-  align-items: center;
-  width: 100%;
-  height: 48px;
-  padding-left: 16px;
-  background: #3071f2;
-
-  .logoWrap {
-    width: 200px;
-
-    .logo {
-      width: 108px;
-      height: 18px;
-    }
-  }
-
-  .platformMenu {
-    position: relative;
-    display: flex;
-    justify-content: center;
-    align-items: center;
-    width: 32px;
-    height: 32px;
-    border-radius: 4px;
-    cursor: pointer;
-    margin-right: 16px;
-
-    img {
-      width: 16px;
-      height: 16px;
-    }
-
-    .systemPannel {
-      display: none;
-      position: absolute;
-      left: 0;
-      top: 50px;
-      z-index: 99;
-      flex-direction: row;
-      justify-content: flex-start;
-      align-items: center;
-      background: #ffffff;
-      padding: 16px 20px;
-      box-shadow: 0px 6px 10px 0px rgba(26, 34, 51, 0.2);
-      border-radius: 8px;
-      border: 1px solid #e6eaf2;
-
-      .systemList {
-        display: flex;
-        flex-direction: column;
-        justify-content: center;
-        align-items: center;
-        width: 80px;
-        height: 98px;
-        margin-right: 10px;
-        border-radius: 8px;
-        line-height: normal;
-        .name {
-          font-size: 12px;
-          font-family: SourceHanSansCN-Normal, SourceHanSansCN;
-          font-weight: 400;
-          color: #666e80;
-        }
-
-        & > img {
-          width: 40px;
-          height: 40px;
-          background: #ffb44d;
-          border-radius: 10px;
-          margin-bottom: 16px;
-        }
-
-        &:last-child {
-          margin-right: 0;
-        }
-
-        &:hover {
-          background: #f7f8fa;
-
-          .name {
-            font-size: 12px;
-            font-family: SourceHanSansCN-Bold, SourceHanSansCN;
-            font-weight: bold;
-            color: #334466;
-          }
-        }
-      }
-    }
-
-    &.on {
-      background: #0b54e6;
-
-      .systemPannel {
-        display: flex;
-      }
-    }
-  }
-
-  .tabWrap {
-    display: flex;
-    flex-direction: row;
-    justify-content: flex-start;
-    align-items: center;
-
-    .tab {
-      padding: 8px 9px;
-      border-radius: 4px;
-      font-size: 14px;
-      font-family: SourceHanSansCN-Medium, SourceHanSansCN;
-      font-weight: 500;
-      color: #ffffff;
-      opacity: 0.8;
-      margin-right: 16px;
-      cursor: pointer;
-      box-sizing: border-box;
-
-      & > img {
-        width: 8px;
-        height: 8px;
-        margin-left: 16px;
-      }
-
-      &:hover {
-        background: #5387ee;
-      }
-
-      &.on {
-        opacity: 1;
-        background: #0b54e6;
-      }
-
-      &:last-child {
-        margin-right: 0;
-      }
-    }
-  }
-
-  .userRelaInfoWrap {
-    display: flex;
-    flex-direction: row;
-    justify-content: center;
-    align-items: center;
-    position: fixed;
-    right: 0;
-    padding-right: 16px;
-
-    .notification {
-      display: flex;
-      flex-direction: row;
-      justify-content: center;
-      align-items: center;
-      width: 18px;
-      height: 18px;
-      margin-right: 16px;
-      cursor: pointer;
-
-      .notificationIcon {
-        width: 100%;
-      }
-    }
-
-    .user {
-      cursor: pointer;
-      display: flex;
-      flex-direction: row;
-      justify-content: center;
-      align-items: center;
-      .avator {
-        width: 26px;
-        height: 26px;
-        margin-right: 8px;
-      }
-
-      .name {
-        font-size: 14px;
-        font-family: SourceHanSansCN-Normal, SourceHanSansCN;
-        font-weight: 400;
-        color: #ffffff;
-        margin-right: 10px;
-      }
-
-      .arrow {
-        width: 11px;
-        height: 7px;
-        transition: all 0.3s ease-in;
-
-        &.on {
-          transform: rotate(180deg);
-        }
-      }
-    }
-  }
-}

+ 5 - 7
src/pages/index/index.tsx

@@ -1,7 +1,7 @@
 /*
  * @Author: your name
  * @Date: 2021-11-10 09:33:30
- * @LastEditTime: 2022-02-09 15:23:59
+ * @LastEditTime: 2022-03-04 14:17:22
  * @LastEditors: Please set LastEditors
  * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  * @FilePath: /KC-MiddlePlatform/src/pages/index.tsx
@@ -35,7 +35,9 @@ const IndexPage: React.FC<IndexPageType> = ({ location }) => {
     const { query } = history.location;
     const { redirect } = query as { redirect: string };
 
-    history.push(redirect || systemInfo.url);
+    // console.log({systemInfo,redirect});
+
+    history.push(redirect || systemInfo.path);
   };
 
   return (
@@ -44,11 +46,7 @@ const IndexPage: React.FC<IndexPageType> = ({ location }) => {
         <div className="block">
           <div className="systemSelector">
             {systemLists?.map((t) => (
-              <div
-                className="sysItem"
-                key={t.id}
-                onClick={() => selectSysHandle(t)}
-              >
+              <div className="sysItem" key={t.id} onClick={() => selectSysHandle(t)}>
                 <img className="icon" src={t.icon} alt="" />
                 <span className="sysName">{t.name}</span>
               </div>

+ 0 - 1
src/pages/login/index.tsx

@@ -51,7 +51,6 @@ const LoginPage: React.FC<LoginPageType> = ({ location, children }) => {
       let percentageX = deltaX / centerX, //向左或向右的 偏差率
         percentageY = deltaY / centerY;
       let deg = 20; //控制 偏差的 程度
-      // console.log(percentageX*20,percentageY*20);
       setTransformObj(`translate(${percentageX * deg}px,${percentageY * deg}px)`);
       // setTransformObj('rotateX(' + percentageY * deg + 'deg)');
     }

+ 79 - 0
src/pages/personalCenter/_mock.ts

@@ -0,0 +1,79 @@
+// eslint-disable-next-line import/no-extraneous-dependencies
+import type { Request, Response } from 'express';
+
+const city = require('./geographic/city.json');
+const province = require('./geographic/province.json');
+
+function getProvince(_: Request, res: Response) {
+  return res.json({
+    data: province,
+  });
+}
+
+function getCity(req: Request, res: Response) {
+  return res.json({
+    data: city[req.params.province],
+  });
+}
+
+function getCurrentUse(req: Request, res: Response) {
+  return res.json({
+    data: {
+      name: 'Serati Ma',
+      avatar: 'https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png',
+      userid: '00000001',
+      email: 'antdesign@alipay.com',
+      signature: '海纳百川,有容乃大',
+      title: '交互专家',
+      group: '蚂蚁金服-某某某事业群-某某平台部-某某技术部-UED',
+      tags: [
+        {
+          key: '0',
+          label: '很有想法的',
+        },
+        {
+          key: '1',
+          label: '专注设计',
+        },
+        {
+          key: '2',
+          label: '辣~',
+        },
+        {
+          key: '3',
+          label: '大长腿',
+        },
+        {
+          key: '4',
+          label: '川妹子',
+        },
+        {
+          key: '5',
+          label: '海纳百川',
+        },
+      ],
+      notifyCount: 12,
+      unreadCount: 11,
+      country: 'China',
+      geographic: {
+        province: {
+          label: '浙江省',
+          key: '330000',
+        },
+        city: {
+          label: '杭州市',
+          key: '330100',
+        },
+      },
+      address: '西湖区工专路 77 号',
+      phone: '0752-268888888',
+    },
+  });
+}
+// 代码中会兼容本地 service mock 以及部署站点的静态数据
+export default {
+  // 支持值为 Object 和 Array
+  'GET  /api/accountSettingCurrentUser': getCurrentUse,
+  'GET  /api/geographic/province': getProvince,
+  'GET  /api/geographic/city/:province': getCity,
+};

+ 65 - 0
src/pages/personalCenter/components/BaseView.less

@@ -0,0 +1,65 @@
+@import '~antd/es/style/themes/default.less';
+
+.baseView {
+  display: flex;
+  padding-top: 12px;
+
+  :global {
+    .ant-legacy-form-item .ant-legacy-form-item-control-wrapper {
+      width: 100%;
+    }
+  }
+
+  .left {
+    min-width: 224px;
+    max-width: 448px;
+  }
+  .right {
+    flex: 1;
+    padding-left: 104px;
+    .avatar_title {
+      height: 22px;
+      margin-bottom: 8px;
+      color: @heading-color;
+      font-size: @font-size-base;
+      line-height: 22px;
+    }
+    .avatar {
+      width: 144px;
+      height: 144px;
+      margin-bottom: 12px;
+      overflow: hidden;
+      img {
+        width: 100%;
+      }
+    }
+    .button_view {
+      width: 144px;
+      text-align: center;
+    }
+  }
+}
+
+.area_code {
+  width: 72px;
+}
+.phone_number {
+  width: 214px;
+}
+
+@media screen and (max-width: @screen-xl) {
+  .baseView {
+    flex-direction: column-reverse;
+
+    .right {
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      max-width: 448px;
+      padding: 20px;
+      .avatar_title {
+        display: none;
+      }
+    }
+  }
+}

+ 42 - 0
src/pages/personalCenter/components/PhoneView.tsx

@@ -0,0 +1,42 @@
+import React from 'react';
+
+import { Input } from 'antd';
+import styles from './PhoneView.less';
+
+type PhoneViewProps = {
+  value?: string;
+  onChange?: (value: string) => void;
+};
+
+const PhoneView: React.FC<PhoneViewProps> = (props) => {
+  const { value, onChange } = props;
+  let values = ['', ''];
+  if (value) {
+    values = value.split('-');
+  }
+
+  return (
+    <>
+      <Input
+        className={styles.area_code}
+        value={values[0]}
+        onChange={(e) => {
+          if (onChange) {
+            onChange(`${e.target.value}-${values[1]}`);
+          }
+        }}
+      />
+      <Input
+        className={styles.phone_number}
+        onChange={(e) => {
+          if (onChange) {
+            onChange(`${values[0]}-${e.target.value}`);
+          }
+        }}
+        value={values[1]}
+      />
+    </>
+  );
+};
+
+export default PhoneView;

+ 235 - 0
src/pages/personalCenter/components/base.tsx

@@ -0,0 +1,235 @@
+import React from 'react';
+import { UploadOutlined } from '@ant-design/icons';
+import { Button, Input, Upload, message } from 'antd';
+import ProForm, {
+  ProFormDependency,
+  ProFormFieldSet,
+  ProFormSelect,
+  ProFormText,
+  ProFormTextArea,
+} from '@ant-design/pro-form';
+import { useRequest } from 'umi';
+import { queryCurrent } from '../service';
+import { queryProvince, queryCity } from '../service';
+
+import styles from './BaseView.less';
+
+const validatorPhone = (rule: any, value: string, callback: (message?: string) => void) => {
+  const values = value.split('-');
+  if (!values[0]) {
+    callback('Please input your area code!');
+  }
+  if (!values[1]) {
+    callback('Please input your phone number!');
+  }
+  callback();
+};
+// 头像组件 方便以后独立,增加裁剪之类的功能
+const AvatarView = ({ avatar }: { avatar: string }) => (
+  <>
+    <div className={styles.avatar_title}>头像</div>
+    <div className={styles.avatar}>
+      <img src={avatar} alt="avatar" />
+    </div>
+    <Upload showUploadList={false}>
+      <div className={styles.button_view}>
+        <Button>
+          <UploadOutlined />
+          更换头像
+        </Button>
+      </div>
+    </Upload>
+  </>
+);
+
+const BaseView: React.FC = () => {
+  const { data: currentUser, loading } = useRequest(() => {
+    return queryCurrent();
+  });
+
+  const getAvatarURL = () => {
+    if (currentUser) {
+      if (currentUser.avatar) {
+        return currentUser.avatar;
+      }
+      const url = 'https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png';
+      return url;
+    }
+    return '';
+  };
+
+  const handleFinish = async () => {
+    message.success('更新基本信息成功');
+  };
+  return (
+    <div className={styles.baseView}>
+      {loading ? null : (
+        <>
+          <div className={styles.left}>
+            <ProForm
+              layout="vertical"
+              onFinish={handleFinish}
+              submitter={{
+                resetButtonProps: {
+                  style: {
+                    display: 'none',
+                  },
+                },
+                submitButtonProps: {
+                  children: '更新基本信息',
+                },
+              }}
+              initialValues={{
+                ...currentUser,
+                phone: currentUser?.phone.split('-'),
+              }}
+              hideRequiredMark
+            >
+              <ProFormText
+                width="md"
+                name="email"
+                label="邮箱"
+                rules={[
+                  {
+                    required: true,
+                    message: '请输入您的邮箱!',
+                  },
+                ]}
+              />
+              <ProFormText
+                width="md"
+                name="name"
+                label="昵称"
+                rules={[
+                  {
+                    required: true,
+                    message: '请输入您的昵称!',
+                  },
+                ]}
+              />
+              <ProFormTextArea
+                name="profile"
+                label="个人简介"
+                rules={[
+                  {
+                    required: true,
+                    message: '请输入个人简介!',
+                  },
+                ]}
+                placeholder="个人简介"
+              />
+              <ProFormSelect
+                width="sm"
+                name="country"
+                label="国家/地区"
+                rules={[
+                  {
+                    required: true,
+                    message: '请输入您的国家或地区!',
+                  },
+                ]}
+                options={[
+                  {
+                    label: '中国',
+                    value: 'China',
+                  },
+                ]}
+              />
+
+              <ProForm.Group title="所在省市" size={8}>
+                <ProFormSelect
+                  rules={[
+                    {
+                      required: true,
+                      message: '请输入您的所在省!',
+                    },
+                  ]}
+                  width="sm"
+                  fieldProps={{
+                    labelInValue: true,
+                  }}
+                  name="province"
+                  className={styles.item}
+                  request={async () => {
+                    return queryProvince().then(({ data }) => {
+                      return data.map((item) => {
+                        return {
+                          label: item.name,
+                          value: item.id,
+                        };
+                      });
+                    });
+                  }}
+                />
+                <ProFormDependency name={['province']}>
+                  {({ province }) => {
+                    return (
+                      <ProFormSelect
+                        params={{
+                          key: province?.value,
+                        }}
+                        name="city"
+                        width="sm"
+                        rules={[
+                          {
+                            required: true,
+                            message: '请输入您的所在城市!',
+                          },
+                        ]}
+                        disabled={!province}
+                        className={styles.item}
+                        request={async () => {
+                          if (!province?.key) {
+                            return [];
+                          }
+                          return queryCity(province.key || '').then(({ data }) => {
+                            return data.map((item) => {
+                              return {
+                                label: item.name,
+                                value: item.id,
+                              };
+                            });
+                          });
+                        }}
+                      />
+                    );
+                  }}
+                </ProFormDependency>
+              </ProForm.Group>
+              <ProFormText
+                width="md"
+                name="address"
+                label="街道地址"
+                rules={[
+                  {
+                    required: true,
+                    message: '请输入您的街道地址!',
+                  },
+                ]}
+              />
+              <ProFormFieldSet
+                name="phone"
+                label="联系电话"
+                rules={[
+                  {
+                    required: true,
+                    message: '请输入您的联系电话!',
+                  },
+                  { validator: validatorPhone },
+                ]}
+              >
+                <Input className={styles.area_code} />
+                <Input className={styles.phone_number} />
+              </ProFormFieldSet>
+            </ProForm>
+          </div>
+          <div className={styles.right}>
+            <AvatarView avatar={getAvatarURL()} />
+          </div>
+        </>
+      )}
+    </div>
+  );
+};
+
+export default BaseView;

+ 46 - 0
src/pages/personalCenter/components/binding.tsx

@@ -0,0 +1,46 @@
+import { AlipayOutlined, DingdingOutlined, TaobaoOutlined } from '@ant-design/icons';
+import { List } from 'antd';
+import React, { Fragment } from 'react';
+
+const BindingView: React.FC = () => {
+  const getData = () => [
+    {
+      title: '绑定淘宝',
+      description: '当前未绑定淘宝账号',
+      actions: [<a key="Bind">绑定</a>],
+      avatar: <TaobaoOutlined className="taobao" />,
+    },
+    {
+      title: '绑定支付宝',
+      description: '当前未绑定支付宝账号',
+      actions: [<a key="Bind">绑定</a>],
+      avatar: <AlipayOutlined className="alipay" />,
+    },
+    {
+      title: '绑定钉钉',
+      description: '当前未绑定钉钉账号',
+      actions: [<a key="Bind">绑定</a>],
+      avatar: <DingdingOutlined className="dingding" />,
+    },
+  ];
+
+  return (
+    <Fragment>
+      <List
+        itemLayout="horizontal"
+        dataSource={getData()}
+        renderItem={(item) => (
+          <List.Item actions={item.actions}>
+            <List.Item.Meta
+              avatar={item.avatar}
+              title={item.title}
+              description={item.description}
+            />
+          </List.Item>
+        )}
+      />
+    </Fragment>
+  );
+};
+
+export default BindingView;

+ 44 - 0
src/pages/personalCenter/components/notification.tsx

@@ -0,0 +1,44 @@
+import { List, Switch } from 'antd';
+import React, { Fragment } from 'react';
+
+type Unpacked<T> = T extends (infer U)[] ? U : T;
+
+const NotificationView: React.FC = () => {
+  const getData = () => {
+    const Action = <Switch checkedChildren="开" unCheckedChildren="关" defaultChecked />;
+    return [
+      {
+        title: '账户密码',
+        description: '其他用户的消息将以站内信的形式通知',
+        actions: [Action],
+      },
+      {
+        title: '系统消息',
+        description: '系统消息将以站内信的形式通知',
+        actions: [Action],
+      },
+      {
+        title: '待办任务',
+        description: '待办任务将以站内信的形式通知',
+        actions: [Action],
+      },
+    ];
+  };
+
+  const data = getData();
+  return (
+    <Fragment>
+      <List<Unpacked<typeof data>>
+        itemLayout="horizontal"
+        dataSource={data}
+        renderItem={(item) => (
+          <List.Item actions={item.actions}>
+            <List.Item.Meta title={item.title} description={item.description} />
+          </List.Item>
+        )}
+      />
+    </Fragment>
+  );
+};
+
+export default NotificationView;

+ 190 - 0
src/pages/personalCenter/components/security.tsx

@@ -0,0 +1,190 @@
+/*
+ * @Author: your name
+ * @Date: 2022-03-03 17:42:10
+ * @LastEditTime: 2022-03-09 16:45:48
+ * @LastEditors: Please set LastEditors
+ * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ * @FilePath: /KC-MiddlePlatform/src/pages/personalCenter/components/security.tsx
+ */
+import React, { useState } from 'react';
+import { List } from 'antd';
+import KCModal from '@/components/KCModal';
+import { ProFormText } from '@ant-design/pro-form';
+import { Form, Alert, Progress, notification, Modal } from 'antd';
+import PasswordQualityCalculator from 'password-quality-calculator';
+import { editUsers } from '@/service/user';
+import { useModel } from 'umi';
+
+type Unpacked<T> = T extends (infer U)[] ? U : T;
+
+const passwordStrength = {
+  strong: <span className="strong">强</span>,
+  medium: <span className="medium">中</span>,
+  weak: <span className="weak">弱 Weak</span>,
+};
+
+const SecurityView: React.FC = () => {
+  const getData = () => [
+    {
+      title: '账户密码',
+      description: (
+        <>
+          当前密码强度:
+          {passwordStrength}
+        </>
+      ),
+      actions: [
+        <a key="Modify" onClick={() => resetPasswordHandle()}>
+          修改
+        </a>,
+      ],
+    },
+    // {
+    //   title: '密保手机',
+    //   description: `已绑定手机:138****8293`,
+    //   actions: [<a key="Modify">修改</a>],
+    // },
+    // {
+    //   title: '密保问题',
+    //   description: '未设置密保问题,密保问题可有效保护账户安全',
+    //   actions: [<a key="Set">设置</a>],
+    // },
+    // {
+    //   title: '备用邮箱',
+    //   description: `已绑定邮箱:ant***sign.com`,
+    //   actions: [<a key="Modify">修改</a>],
+    // },
+    // {
+    //   title: 'MFA 设备',
+    //   description: '未绑定 MFA 设备,绑定后,可以进行二次确认',
+    //   actions: [<a key="bind">绑定</a>],
+    // },
+  ];
+
+  const { initialState, setInitialState } = useModel('@@initialState');
+
+  const [modalVisible, setmodalVisible] = useState(false);
+  const [passwordStrength, setpasswordStrength] = useState(0);
+  const [showPasswordCompareTip, setshowPasswordCompareTip] = useState(false);
+
+  const data = getData();
+
+  const resetPasswordHandle = () => {
+    setmodalVisible(true);
+  };
+
+  const onVisibleChangeHandle = (bool: boolean) => {
+    setmodalVisible(bool);
+  };
+
+  const passwordChangeHandle = (e: React.ChangeEvent<HTMLInputElement>) => {
+    // console.log(PasswordQualityCalculator(e.target.value));
+    setpasswordStrength(PasswordQualityCalculator(e.target.value));
+  };
+
+  const onFinishhandle = async (values: any) => {
+    const { newPassword, reNewPassword } = values;
+
+    if (reNewPassword != newPassword) {
+      setshowPasswordCompareTip(true);
+      setTimeout(() => {
+        setshowPasswordCompareTip(false);
+      }, 2000);
+      return false;
+    }
+    const userData = localStorage.getItem('userData');
+
+    if (userData) {
+      const resp = await editUsers({
+        id: JSON.parse(userData).userId,
+        password: newPassword,
+      });
+
+      if (resp) {
+        Modal.confirm({
+          title: '密码修改成功,前往重新登录?',
+          closable: false,
+          onOk: () => {
+            if (initialState?.logout) {
+              initialState.logout();
+            }
+          },
+          cancelText: '',
+        });
+        return true;
+      }
+    } else {
+      notification['error']({
+        message: '用户信息获取错误!',
+      });
+    }
+  };
+
+  return (
+    <div>
+      <KCModal
+        title="设置密码"
+        width={600}
+        visible={modalVisible}
+        onVisibleChange={onVisibleChangeHandle}
+        layout="horizontal"
+        labelCol={{ span: 6 }}
+        wrapperCol={{ span: 16 }}
+        onFinish={(val) => onFinishhandle(val)}
+      >
+        <div style={{ position: 'relative', paddingTop: '24px' }}>
+          <Alert
+            message="两次输入密码不一致!"
+            type="error"
+            showIcon
+            style={{
+              position: 'absolute',
+              marginBottom: '16px',
+              top: showPasswordCompareTip ? -27 : -70,
+              transition: 'all 0.3s ease-in',
+              width: '100%',
+            }}
+          />
+
+          <ProFormText.Password
+            label="原密码"
+            name="oldPassword"
+            rules={[{ required: true, message: '这是必填项' }]}
+          />
+          <ProFormText.Password
+            label="新密码"
+            name="newPassword"
+            rules={[{ required: true, message: '这是必填项' }]}
+            fieldProps={{
+              onChange: (e) => passwordChangeHandle(e),
+            }}
+          />
+          <ProFormText.Password
+            label="再次输入新密码"
+            name="reNewPassword"
+            rules={[{ required: true, message: '这是必填项' }]}
+          />
+          <Form.Item label="密码强度">
+            <Progress
+              percent={passwordStrength}
+              steps={10}
+              strokeColor={{ '0%': '#108ee9', '100%': '#87d068' }}
+            />
+          </Form.Item>
+        </div>
+      </KCModal>
+
+      <List<Unpacked<typeof data>>
+        itemLayout="horizontal"
+        dataSource={data}
+        renderItem={(item) => (
+          <List.Item actions={item.actions} className="rightListItem">
+            <List.Item.Meta title={item.title} description={item.description} />
+          </List.Item>
+        )}
+      />
+    </div>
+  );
+};
+
+export default SecurityView;

+ 43 - 0
src/pages/personalCenter/data.d.ts

@@ -0,0 +1,43 @@
+export type TagType = {
+  key: string;
+  label: string;
+};
+
+export type GeographicItemType = {
+  name: string;
+  id: string;
+};
+
+export type GeographicType = {
+  province: GeographicItemType;
+  city: GeographicItemType;
+};
+
+export type NoticeType = {
+  id: string;
+  title: string;
+  logo: string;
+  description: string;
+  updatedAt: string;
+  member: string;
+  href: string;
+  memberLink: string;
+};
+
+export type CurrentUser = {
+  name: string;
+  avatar: string;
+  userid: string;
+  notice: NoticeType[];
+  email: string;
+  signature: string;
+  title: string;
+  group: string;
+  tags: TagType[];
+  notifyCount: number;
+  unreadCount: number;
+  country: string;
+  geographic: GeographicType;
+  address: string;
+  phone: string;
+};

+ 1784 - 0
src/pages/personalCenter/geographic/city.json

@@ -0,0 +1,1784 @@
+{
+  "110000": [
+    {
+      "province": "北京市",
+      "name": "市辖区",
+      "id": "110100"
+    }
+  ],
+  "120000": [
+    {
+      "province": "天津市",
+      "name": "市辖区",
+      "id": "120100"
+    }
+  ],
+  "130000": [
+    {
+      "province": "河北省",
+      "name": "石家庄市",
+      "id": "130100"
+    },
+    {
+      "province": "河北省",
+      "name": "唐山市",
+      "id": "130200"
+    },
+    {
+      "province": "河北省",
+      "name": "秦皇岛市",
+      "id": "130300"
+    },
+    {
+      "province": "河北省",
+      "name": "邯郸市",
+      "id": "130400"
+    },
+    {
+      "province": "河北省",
+      "name": "邢台市",
+      "id": "130500"
+    },
+    {
+      "province": "河北省",
+      "name": "保定市",
+      "id": "130600"
+    },
+    {
+      "province": "河北省",
+      "name": "张家口市",
+      "id": "130700"
+    },
+    {
+      "province": "河北省",
+      "name": "承德市",
+      "id": "130800"
+    },
+    {
+      "province": "河北省",
+      "name": "沧州市",
+      "id": "130900"
+    },
+    {
+      "province": "河北省",
+      "name": "廊坊市",
+      "id": "131000"
+    },
+    {
+      "province": "河北省",
+      "name": "衡水市",
+      "id": "131100"
+    },
+    {
+      "province": "河北省",
+      "name": "省直辖县级行政区划",
+      "id": "139000"
+    }
+  ],
+  "140000": [
+    {
+      "province": "山西省",
+      "name": "太原市",
+      "id": "140100"
+    },
+    {
+      "province": "山西省",
+      "name": "大同市",
+      "id": "140200"
+    },
+    {
+      "province": "山西省",
+      "name": "阳泉市",
+      "id": "140300"
+    },
+    {
+      "province": "山西省",
+      "name": "长治市",
+      "id": "140400"
+    },
+    {
+      "province": "山西省",
+      "name": "晋城市",
+      "id": "140500"
+    },
+    {
+      "province": "山西省",
+      "name": "朔州市",
+      "id": "140600"
+    },
+    {
+      "province": "山西省",
+      "name": "晋中市",
+      "id": "140700"
+    },
+    {
+      "province": "山西省",
+      "name": "运城市",
+      "id": "140800"
+    },
+    {
+      "province": "山西省",
+      "name": "忻州市",
+      "id": "140900"
+    },
+    {
+      "province": "山西省",
+      "name": "临汾市",
+      "id": "141000"
+    },
+    {
+      "province": "山西省",
+      "name": "吕梁市",
+      "id": "141100"
+    }
+  ],
+  "150000": [
+    {
+      "province": "内蒙古自治区",
+      "name": "呼和浩特市",
+      "id": "150100"
+    },
+    {
+      "province": "内蒙古自治区",
+      "name": "包头市",
+      "id": "150200"
+    },
+    {
+      "province": "内蒙古自治区",
+      "name": "乌海市",
+      "id": "150300"
+    },
+    {
+      "province": "内蒙古自治区",
+      "name": "赤峰市",
+      "id": "150400"
+    },
+    {
+      "province": "内蒙古自治区",
+      "name": "通辽市",
+      "id": "150500"
+    },
+    {
+      "province": "内蒙古自治区",
+      "name": "鄂尔多斯市",
+      "id": "150600"
+    },
+    {
+      "province": "内蒙古自治区",
+      "name": "呼伦贝尔市",
+      "id": "150700"
+    },
+    {
+      "province": "内蒙古自治区",
+      "name": "巴彦淖尔市",
+      "id": "150800"
+    },
+    {
+      "province": "内蒙古自治区",
+      "name": "乌兰察布市",
+      "id": "150900"
+    },
+    {
+      "province": "内蒙古自治区",
+      "name": "兴安盟",
+      "id": "152200"
+    },
+    {
+      "province": "内蒙古自治区",
+      "name": "锡林郭勒盟",
+      "id": "152500"
+    },
+    {
+      "province": "内蒙古自治区",
+      "name": "阿拉善盟",
+      "id": "152900"
+    }
+  ],
+  "210000": [
+    {
+      "province": "辽宁省",
+      "name": "沈阳市",
+      "id": "210100"
+    },
+    {
+      "province": "辽宁省",
+      "name": "大连市",
+      "id": "210200"
+    },
+    {
+      "province": "辽宁省",
+      "name": "鞍山市",
+      "id": "210300"
+    },
+    {
+      "province": "辽宁省",
+      "name": "抚顺市",
+      "id": "210400"
+    },
+    {
+      "province": "辽宁省",
+      "name": "本溪市",
+      "id": "210500"
+    },
+    {
+      "province": "辽宁省",
+      "name": "丹东市",
+      "id": "210600"
+    },
+    {
+      "province": "辽宁省",
+      "name": "锦州市",
+      "id": "210700"
+    },
+    {
+      "province": "辽宁省",
+      "name": "营口市",
+      "id": "210800"
+    },
+    {
+      "province": "辽宁省",
+      "name": "阜新市",
+      "id": "210900"
+    },
+    {
+      "province": "辽宁省",
+      "name": "辽阳市",
+      "id": "211000"
+    },
+    {
+      "province": "辽宁省",
+      "name": "盘锦市",
+      "id": "211100"
+    },
+    {
+      "province": "辽宁省",
+      "name": "铁岭市",
+      "id": "211200"
+    },
+    {
+      "province": "辽宁省",
+      "name": "朝阳市",
+      "id": "211300"
+    },
+    {
+      "province": "辽宁省",
+      "name": "葫芦岛市",
+      "id": "211400"
+    }
+  ],
+  "220000": [
+    {
+      "province": "吉林省",
+      "name": "长春市",
+      "id": "220100"
+    },
+    {
+      "province": "吉林省",
+      "name": "吉林市",
+      "id": "220200"
+    },
+    {
+      "province": "吉林省",
+      "name": "四平市",
+      "id": "220300"
+    },
+    {
+      "province": "吉林省",
+      "name": "辽源市",
+      "id": "220400"
+    },
+    {
+      "province": "吉林省",
+      "name": "通化市",
+      "id": "220500"
+    },
+    {
+      "province": "吉林省",
+      "name": "白山市",
+      "id": "220600"
+    },
+    {
+      "province": "吉林省",
+      "name": "松原市",
+      "id": "220700"
+    },
+    {
+      "province": "吉林省",
+      "name": "白城市",
+      "id": "220800"
+    },
+    {
+      "province": "吉林省",
+      "name": "延边朝鲜族自治州",
+      "id": "222400"
+    }
+  ],
+  "230000": [
+    {
+      "province": "黑龙江省",
+      "name": "哈尔滨市",
+      "id": "230100"
+    },
+    {
+      "province": "黑龙江省",
+      "name": "齐齐哈尔市",
+      "id": "230200"
+    },
+    {
+      "province": "黑龙江省",
+      "name": "鸡西市",
+      "id": "230300"
+    },
+    {
+      "province": "黑龙江省",
+      "name": "鹤岗市",
+      "id": "230400"
+    },
+    {
+      "province": "黑龙江省",
+      "name": "双鸭山市",
+      "id": "230500"
+    },
+    {
+      "province": "黑龙江省",
+      "name": "大庆市",
+      "id": "230600"
+    },
+    {
+      "province": "黑龙江省",
+      "name": "伊春市",
+      "id": "230700"
+    },
+    {
+      "province": "黑龙江省",
+      "name": "佳木斯市",
+      "id": "230800"
+    },
+    {
+      "province": "黑龙江省",
+      "name": "七台河市",
+      "id": "230900"
+    },
+    {
+      "province": "黑龙江省",
+      "name": "牡丹江市",
+      "id": "231000"
+    },
+    {
+      "province": "黑龙江省",
+      "name": "黑河市",
+      "id": "231100"
+    },
+    {
+      "province": "黑龙江省",
+      "name": "绥化市",
+      "id": "231200"
+    },
+    {
+      "province": "黑龙江省",
+      "name": "大兴安岭地区",
+      "id": "232700"
+    }
+  ],
+  "310000": [
+    {
+      "province": "上海市",
+      "name": "市辖区",
+      "id": "310100"
+    }
+  ],
+  "320000": [
+    {
+      "province": "江苏省",
+      "name": "南京市",
+      "id": "320100"
+    },
+    {
+      "province": "江苏省",
+      "name": "无锡市",
+      "id": "320200"
+    },
+    {
+      "province": "江苏省",
+      "name": "徐州市",
+      "id": "320300"
+    },
+    {
+      "province": "江苏省",
+      "name": "常州市",
+      "id": "320400"
+    },
+    {
+      "province": "江苏省",
+      "name": "苏州市",
+      "id": "320500"
+    },
+    {
+      "province": "江苏省",
+      "name": "南通市",
+      "id": "320600"
+    },
+    {
+      "province": "江苏省",
+      "name": "连云港市",
+      "id": "320700"
+    },
+    {
+      "province": "江苏省",
+      "name": "淮安市",
+      "id": "320800"
+    },
+    {
+      "province": "江苏省",
+      "name": "盐城市",
+      "id": "320900"
+    },
+    {
+      "province": "江苏省",
+      "name": "扬州市",
+      "id": "321000"
+    },
+    {
+      "province": "江苏省",
+      "name": "镇江市",
+      "id": "321100"
+    },
+    {
+      "province": "江苏省",
+      "name": "泰州市",
+      "id": "321200"
+    },
+    {
+      "province": "江苏省",
+      "name": "宿迁市",
+      "id": "321300"
+    }
+  ],
+  "330000": [
+    {
+      "province": "浙江省",
+      "name": "杭州市",
+      "id": "330100"
+    },
+    {
+      "province": "浙江省",
+      "name": "宁波市",
+      "id": "330200"
+    },
+    {
+      "province": "浙江省",
+      "name": "温州市",
+      "id": "330300"
+    },
+    {
+      "province": "浙江省",
+      "name": "嘉兴市",
+      "id": "330400"
+    },
+    {
+      "province": "浙江省",
+      "name": "湖州市",
+      "id": "330500"
+    },
+    {
+      "province": "浙江省",
+      "name": "绍兴市",
+      "id": "330600"
+    },
+    {
+      "province": "浙江省",
+      "name": "金华市",
+      "id": "330700"
+    },
+    {
+      "province": "浙江省",
+      "name": "衢州市",
+      "id": "330800"
+    },
+    {
+      "province": "浙江省",
+      "name": "舟山市",
+      "id": "330900"
+    },
+    {
+      "province": "浙江省",
+      "name": "台州市",
+      "id": "331000"
+    },
+    {
+      "province": "浙江省",
+      "name": "丽水市",
+      "id": "331100"
+    }
+  ],
+  "340000": [
+    {
+      "province": "安徽省",
+      "name": "合肥市",
+      "id": "340100"
+    },
+    {
+      "province": "安徽省",
+      "name": "芜湖市",
+      "id": "340200"
+    },
+    {
+      "province": "安徽省",
+      "name": "蚌埠市",
+      "id": "340300"
+    },
+    {
+      "province": "安徽省",
+      "name": "淮南市",
+      "id": "340400"
+    },
+    {
+      "province": "安徽省",
+      "name": "马鞍山市",
+      "id": "340500"
+    },
+    {
+      "province": "安徽省",
+      "name": "淮北市",
+      "id": "340600"
+    },
+    {
+      "province": "安徽省",
+      "name": "铜陵市",
+      "id": "340700"
+    },
+    {
+      "province": "安徽省",
+      "name": "安庆市",
+      "id": "340800"
+    },
+    {
+      "province": "安徽省",
+      "name": "黄山市",
+      "id": "341000"
+    },
+    {
+      "province": "安徽省",
+      "name": "滁州市",
+      "id": "341100"
+    },
+    {
+      "province": "安徽省",
+      "name": "阜阳市",
+      "id": "341200"
+    },
+    {
+      "province": "安徽省",
+      "name": "宿州市",
+      "id": "341300"
+    },
+    {
+      "province": "安徽省",
+      "name": "六安市",
+      "id": "341500"
+    },
+    {
+      "province": "安徽省",
+      "name": "亳州市",
+      "id": "341600"
+    },
+    {
+      "province": "安徽省",
+      "name": "池州市",
+      "id": "341700"
+    },
+    {
+      "province": "安徽省",
+      "name": "宣城市",
+      "id": "341800"
+    }
+  ],
+  "350000": [
+    {
+      "province": "福建省",
+      "name": "福州市",
+      "id": "350100"
+    },
+    {
+      "province": "福建省",
+      "name": "厦门市",
+      "id": "350200"
+    },
+    {
+      "province": "福建省",
+      "name": "莆田市",
+      "id": "350300"
+    },
+    {
+      "province": "福建省",
+      "name": "三明市",
+      "id": "350400"
+    },
+    {
+      "province": "福建省",
+      "name": "泉州市",
+      "id": "350500"
+    },
+    {
+      "province": "福建省",
+      "name": "漳州市",
+      "id": "350600"
+    },
+    {
+      "province": "福建省",
+      "name": "南平市",
+      "id": "350700"
+    },
+    {
+      "province": "福建省",
+      "name": "龙岩市",
+      "id": "350800"
+    },
+    {
+      "province": "福建省",
+      "name": "宁德市",
+      "id": "350900"
+    }
+  ],
+  "360000": [
+    {
+      "province": "江西省",
+      "name": "南昌市",
+      "id": "360100"
+    },
+    {
+      "province": "江西省",
+      "name": "景德镇市",
+      "id": "360200"
+    },
+    {
+      "province": "江西省",
+      "name": "萍乡市",
+      "id": "360300"
+    },
+    {
+      "province": "江西省",
+      "name": "九江市",
+      "id": "360400"
+    },
+    {
+      "province": "江西省",
+      "name": "新余市",
+      "id": "360500"
+    },
+    {
+      "province": "江西省",
+      "name": "鹰潭市",
+      "id": "360600"
+    },
+    {
+      "province": "江西省",
+      "name": "赣州市",
+      "id": "360700"
+    },
+    {
+      "province": "江西省",
+      "name": "吉安市",
+      "id": "360800"
+    },
+    {
+      "province": "江西省",
+      "name": "宜春市",
+      "id": "360900"
+    },
+    {
+      "province": "江西省",
+      "name": "抚州市",
+      "id": "361000"
+    },
+    {
+      "province": "江西省",
+      "name": "上饶市",
+      "id": "361100"
+    }
+  ],
+  "370000": [
+    {
+      "province": "山东省",
+      "name": "济南市",
+      "id": "370100"
+    },
+    {
+      "province": "山东省",
+      "name": "青岛市",
+      "id": "370200"
+    },
+    {
+      "province": "山东省",
+      "name": "淄博市",
+      "id": "370300"
+    },
+    {
+      "province": "山东省",
+      "name": "枣庄市",
+      "id": "370400"
+    },
+    {
+      "province": "山东省",
+      "name": "东营市",
+      "id": "370500"
+    },
+    {
+      "province": "山东省",
+      "name": "烟台市",
+      "id": "370600"
+    },
+    {
+      "province": "山东省",
+      "name": "潍坊市",
+      "id": "370700"
+    },
+    {
+      "province": "山东省",
+      "name": "济宁市",
+      "id": "370800"
+    },
+    {
+      "province": "山东省",
+      "name": "泰安市",
+      "id": "370900"
+    },
+    {
+      "province": "山东省",
+      "name": "威海市",
+      "id": "371000"
+    },
+    {
+      "province": "山东省",
+      "name": "日照市",
+      "id": "371100"
+    },
+    {
+      "province": "山东省",
+      "name": "莱芜市",
+      "id": "371200"
+    },
+    {
+      "province": "山东省",
+      "name": "临沂市",
+      "id": "371300"
+    },
+    {
+      "province": "山东省",
+      "name": "德州市",
+      "id": "371400"
+    },
+    {
+      "province": "山东省",
+      "name": "聊城市",
+      "id": "371500"
+    },
+    {
+      "province": "山东省",
+      "name": "滨州市",
+      "id": "371600"
+    },
+    {
+      "province": "山东省",
+      "name": "菏泽市",
+      "id": "371700"
+    }
+  ],
+  "410000": [
+    {
+      "province": "河南省",
+      "name": "郑州市",
+      "id": "410100"
+    },
+    {
+      "province": "河南省",
+      "name": "开封市",
+      "id": "410200"
+    },
+    {
+      "province": "河南省",
+      "name": "洛阳市",
+      "id": "410300"
+    },
+    {
+      "province": "河南省",
+      "name": "平顶山市",
+      "id": "410400"
+    },
+    {
+      "province": "河南省",
+      "name": "安阳市",
+      "id": "410500"
+    },
+    {
+      "province": "河南省",
+      "name": "鹤壁市",
+      "id": "410600"
+    },
+    {
+      "province": "河南省",
+      "name": "新乡市",
+      "id": "410700"
+    },
+    {
+      "province": "河南省",
+      "name": "焦作市",
+      "id": "410800"
+    },
+    {
+      "province": "河南省",
+      "name": "濮阳市",
+      "id": "410900"
+    },
+    {
+      "province": "河南省",
+      "name": "许昌市",
+      "id": "411000"
+    },
+    {
+      "province": "河南省",
+      "name": "漯河市",
+      "id": "411100"
+    },
+    {
+      "province": "河南省",
+      "name": "三门峡市",
+      "id": "411200"
+    },
+    {
+      "province": "河南省",
+      "name": "南阳市",
+      "id": "411300"
+    },
+    {
+      "province": "河南省",
+      "name": "商丘市",
+      "id": "411400"
+    },
+    {
+      "province": "河南省",
+      "name": "信阳市",
+      "id": "411500"
+    },
+    {
+      "province": "河南省",
+      "name": "周口市",
+      "id": "411600"
+    },
+    {
+      "province": "河南省",
+      "name": "驻马店市",
+      "id": "411700"
+    },
+    {
+      "province": "河南省",
+      "name": "省直辖县级行政区划",
+      "id": "419000"
+    }
+  ],
+  "420000": [
+    {
+      "province": "湖北省",
+      "name": "武汉市",
+      "id": "420100"
+    },
+    {
+      "province": "湖北省",
+      "name": "黄石市",
+      "id": "420200"
+    },
+    {
+      "province": "湖北省",
+      "name": "十堰市",
+      "id": "420300"
+    },
+    {
+      "province": "湖北省",
+      "name": "宜昌市",
+      "id": "420500"
+    },
+    {
+      "province": "湖北省",
+      "name": "襄阳市",
+      "id": "420600"
+    },
+    {
+      "province": "湖北省",
+      "name": "鄂州市",
+      "id": "420700"
+    },
+    {
+      "province": "湖北省",
+      "name": "荆门市",
+      "id": "420800"
+    },
+    {
+      "province": "湖北省",
+      "name": "孝感市",
+      "id": "420900"
+    },
+    {
+      "province": "湖北省",
+      "name": "荆州市",
+      "id": "421000"
+    },
+    {
+      "province": "湖北省",
+      "name": "黄冈市",
+      "id": "421100"
+    },
+    {
+      "province": "湖北省",
+      "name": "咸宁市",
+      "id": "421200"
+    },
+    {
+      "province": "湖北省",
+      "name": "随州市",
+      "id": "421300"
+    },
+    {
+      "province": "湖北省",
+      "name": "恩施土家族苗族自治州",
+      "id": "422800"
+    },
+    {
+      "province": "湖北省",
+      "name": "省直辖县级行政区划",
+      "id": "429000"
+    }
+  ],
+  "430000": [
+    {
+      "province": "湖南省",
+      "name": "长沙市",
+      "id": "430100"
+    },
+    {
+      "province": "湖南省",
+      "name": "株洲市",
+      "id": "430200"
+    },
+    {
+      "province": "湖南省",
+      "name": "湘潭市",
+      "id": "430300"
+    },
+    {
+      "province": "湖南省",
+      "name": "衡阳市",
+      "id": "430400"
+    },
+    {
+      "province": "湖南省",
+      "name": "邵阳市",
+      "id": "430500"
+    },
+    {
+      "province": "湖南省",
+      "name": "岳阳市",
+      "id": "430600"
+    },
+    {
+      "province": "湖南省",
+      "name": "常德市",
+      "id": "430700"
+    },
+    {
+      "province": "湖南省",
+      "name": "张家界市",
+      "id": "430800"
+    },
+    {
+      "province": "湖南省",
+      "name": "益阳市",
+      "id": "430900"
+    },
+    {
+      "province": "湖南省",
+      "name": "郴州市",
+      "id": "431000"
+    },
+    {
+      "province": "湖南省",
+      "name": "永州市",
+      "id": "431100"
+    },
+    {
+      "province": "湖南省",
+      "name": "怀化市",
+      "id": "431200"
+    },
+    {
+      "province": "湖南省",
+      "name": "娄底市",
+      "id": "431300"
+    },
+    {
+      "province": "湖南省",
+      "name": "湘西土家族苗族自治州",
+      "id": "433100"
+    }
+  ],
+  "440000": [
+    {
+      "province": "广东省",
+      "name": "广州市",
+      "id": "440100"
+    },
+    {
+      "province": "广东省",
+      "name": "韶关市",
+      "id": "440200"
+    },
+    {
+      "province": "广东省",
+      "name": "深圳市",
+      "id": "440300"
+    },
+    {
+      "province": "广东省",
+      "name": "珠海市",
+      "id": "440400"
+    },
+    {
+      "province": "广东省",
+      "name": "汕头市",
+      "id": "440500"
+    },
+    {
+      "province": "广东省",
+      "name": "佛山市",
+      "id": "440600"
+    },
+    {
+      "province": "广东省",
+      "name": "江门市",
+      "id": "440700"
+    },
+    {
+      "province": "广东省",
+      "name": "湛江市",
+      "id": "440800"
+    },
+    {
+      "province": "广东省",
+      "name": "茂名市",
+      "id": "440900"
+    },
+    {
+      "province": "广东省",
+      "name": "肇庆市",
+      "id": "441200"
+    },
+    {
+      "province": "广东省",
+      "name": "惠州市",
+      "id": "441300"
+    },
+    {
+      "province": "广东省",
+      "name": "梅州市",
+      "id": "441400"
+    },
+    {
+      "province": "广东省",
+      "name": "汕尾市",
+      "id": "441500"
+    },
+    {
+      "province": "广东省",
+      "name": "河源市",
+      "id": "441600"
+    },
+    {
+      "province": "广东省",
+      "name": "阳江市",
+      "id": "441700"
+    },
+    {
+      "province": "广东省",
+      "name": "清远市",
+      "id": "441800"
+    },
+    {
+      "province": "广东省",
+      "name": "东莞市",
+      "id": "441900"
+    },
+    {
+      "province": "广东省",
+      "name": "中山市",
+      "id": "442000"
+    },
+    {
+      "province": "广东省",
+      "name": "潮州市",
+      "id": "445100"
+    },
+    {
+      "province": "广东省",
+      "name": "揭阳市",
+      "id": "445200"
+    },
+    {
+      "province": "广东省",
+      "name": "云浮市",
+      "id": "445300"
+    }
+  ],
+  "450000": [
+    {
+      "province": "广西壮族自治区",
+      "name": "南宁市",
+      "id": "450100"
+    },
+    {
+      "province": "广西壮族自治区",
+      "name": "柳州市",
+      "id": "450200"
+    },
+    {
+      "province": "广西壮族自治区",
+      "name": "桂林市",
+      "id": "450300"
+    },
+    {
+      "province": "广西壮族自治区",
+      "name": "梧州市",
+      "id": "450400"
+    },
+    {
+      "province": "广西壮族自治区",
+      "name": "北海市",
+      "id": "450500"
+    },
+    {
+      "province": "广西壮族自治区",
+      "name": "防城港市",
+      "id": "450600"
+    },
+    {
+      "province": "广西壮族自治区",
+      "name": "钦州市",
+      "id": "450700"
+    },
+    {
+      "province": "广西壮族自治区",
+      "name": "贵港市",
+      "id": "450800"
+    },
+    {
+      "province": "广西壮族自治区",
+      "name": "玉林市",
+      "id": "450900"
+    },
+    {
+      "province": "广西壮族自治区",
+      "name": "百色市",
+      "id": "451000"
+    },
+    {
+      "province": "广西壮族自治区",
+      "name": "贺州市",
+      "id": "451100"
+    },
+    {
+      "province": "广西壮族自治区",
+      "name": "河池市",
+      "id": "451200"
+    },
+    {
+      "province": "广西壮族自治区",
+      "name": "来宾市",
+      "id": "451300"
+    },
+    {
+      "province": "广西壮族自治区",
+      "name": "崇左市",
+      "id": "451400"
+    }
+  ],
+  "460000": [
+    {
+      "province": "海南省",
+      "name": "海口市",
+      "id": "460100"
+    },
+    {
+      "province": "海南省",
+      "name": "三亚市",
+      "id": "460200"
+    },
+    {
+      "province": "海南省",
+      "name": "三沙市",
+      "id": "460300"
+    },
+    {
+      "province": "海南省",
+      "name": "儋州市",
+      "id": "460400"
+    },
+    {
+      "province": "海南省",
+      "name": "省直辖县级行政区划",
+      "id": "469000"
+    }
+  ],
+  "500000": [
+    {
+      "province": "重庆市",
+      "name": "市辖区",
+      "id": "500100"
+    },
+    {
+      "province": "重庆市",
+      "name": "县",
+      "id": "500200"
+    }
+  ],
+  "510000": [
+    {
+      "province": "四川省",
+      "name": "成都市",
+      "id": "510100"
+    },
+    {
+      "province": "四川省",
+      "name": "自贡市",
+      "id": "510300"
+    },
+    {
+      "province": "四川省",
+      "name": "攀枝花市",
+      "id": "510400"
+    },
+    {
+      "province": "四川省",
+      "name": "泸州市",
+      "id": "510500"
+    },
+    {
+      "province": "四川省",
+      "name": "德阳市",
+      "id": "510600"
+    },
+    {
+      "province": "四川省",
+      "name": "绵阳市",
+      "id": "510700"
+    },
+    {
+      "province": "四川省",
+      "name": "广元市",
+      "id": "510800"
+    },
+    {
+      "province": "四川省",
+      "name": "遂宁市",
+      "id": "510900"
+    },
+    {
+      "province": "四川省",
+      "name": "内江市",
+      "id": "511000"
+    },
+    {
+      "province": "四川省",
+      "name": "乐山市",
+      "id": "511100"
+    },
+    {
+      "province": "四川省",
+      "name": "南充市",
+      "id": "511300"
+    },
+    {
+      "province": "四川省",
+      "name": "眉山市",
+      "id": "511400"
+    },
+    {
+      "province": "四川省",
+      "name": "宜宾市",
+      "id": "511500"
+    },
+    {
+      "province": "四川省",
+      "name": "广安市",
+      "id": "511600"
+    },
+    {
+      "province": "四川省",
+      "name": "达州市",
+      "id": "511700"
+    },
+    {
+      "province": "四川省",
+      "name": "雅安市",
+      "id": "511800"
+    },
+    {
+      "province": "四川省",
+      "name": "巴中市",
+      "id": "511900"
+    },
+    {
+      "province": "四川省",
+      "name": "资阳市",
+      "id": "512000"
+    },
+    {
+      "province": "四川省",
+      "name": "阿坝藏族羌族自治州",
+      "id": "513200"
+    },
+    {
+      "province": "四川省",
+      "name": "甘孜藏族自治州",
+      "id": "513300"
+    },
+    {
+      "province": "四川省",
+      "name": "凉山彝族自治州",
+      "id": "513400"
+    }
+  ],
+  "520000": [
+    {
+      "province": "贵州省",
+      "name": "贵阳市",
+      "id": "520100"
+    },
+    {
+      "province": "贵州省",
+      "name": "六盘水市",
+      "id": "520200"
+    },
+    {
+      "province": "贵州省",
+      "name": "遵义市",
+      "id": "520300"
+    },
+    {
+      "province": "贵州省",
+      "name": "安顺市",
+      "id": "520400"
+    },
+    {
+      "province": "贵州省",
+      "name": "毕节市",
+      "id": "520500"
+    },
+    {
+      "province": "贵州省",
+      "name": "铜仁市",
+      "id": "520600"
+    },
+    {
+      "province": "贵州省",
+      "name": "黔西南布依族苗族自治州",
+      "id": "522300"
+    },
+    {
+      "province": "贵州省",
+      "name": "黔东南苗族侗族自治州",
+      "id": "522600"
+    },
+    {
+      "province": "贵州省",
+      "name": "黔南布依族苗族自治州",
+      "id": "522700"
+    }
+  ],
+  "530000": [
+    {
+      "province": "云南省",
+      "name": "昆明市",
+      "id": "530100"
+    },
+    {
+      "province": "云南省",
+      "name": "曲靖市",
+      "id": "530300"
+    },
+    {
+      "province": "云南省",
+      "name": "玉溪市",
+      "id": "530400"
+    },
+    {
+      "province": "云南省",
+      "name": "保山市",
+      "id": "530500"
+    },
+    {
+      "province": "云南省",
+      "name": "昭通市",
+      "id": "530600"
+    },
+    {
+      "province": "云南省",
+      "name": "丽江市",
+      "id": "530700"
+    },
+    {
+      "province": "云南省",
+      "name": "普洱市",
+      "id": "530800"
+    },
+    {
+      "province": "云南省",
+      "name": "临沧市",
+      "id": "530900"
+    },
+    {
+      "province": "云南省",
+      "name": "楚雄彝族自治州",
+      "id": "532300"
+    },
+    {
+      "province": "云南省",
+      "name": "红河哈尼族彝族自治州",
+      "id": "532500"
+    },
+    {
+      "province": "云南省",
+      "name": "文山壮族苗族自治州",
+      "id": "532600"
+    },
+    {
+      "province": "云南省",
+      "name": "西双版纳傣族自治州",
+      "id": "532800"
+    },
+    {
+      "province": "云南省",
+      "name": "大理白族自治州",
+      "id": "532900"
+    },
+    {
+      "province": "云南省",
+      "name": "德宏傣族景颇族自治州",
+      "id": "533100"
+    },
+    {
+      "province": "云南省",
+      "name": "怒江傈僳族自治州",
+      "id": "533300"
+    },
+    {
+      "province": "云南省",
+      "name": "迪庆藏族自治州",
+      "id": "533400"
+    }
+  ],
+  "540000": [
+    {
+      "province": "西藏自治区",
+      "name": "拉萨市",
+      "id": "540100"
+    },
+    {
+      "province": "西藏自治区",
+      "name": "日喀则市",
+      "id": "540200"
+    },
+    {
+      "province": "西藏自治区",
+      "name": "昌都市",
+      "id": "540300"
+    },
+    {
+      "province": "西藏自治区",
+      "name": "林芝市",
+      "id": "540400"
+    },
+    {
+      "province": "西藏自治区",
+      "name": "山南市",
+      "id": "540500"
+    },
+    {
+      "province": "西藏自治区",
+      "name": "那曲地区",
+      "id": "542400"
+    },
+    {
+      "province": "西藏自治区",
+      "name": "阿里地区",
+      "id": "542500"
+    }
+  ],
+  "610000": [
+    {
+      "province": "陕西省",
+      "name": "西安市",
+      "id": "610100"
+    },
+    {
+      "province": "陕西省",
+      "name": "铜川市",
+      "id": "610200"
+    },
+    {
+      "province": "陕西省",
+      "name": "宝鸡市",
+      "id": "610300"
+    },
+    {
+      "province": "陕西省",
+      "name": "咸阳市",
+      "id": "610400"
+    },
+    {
+      "province": "陕西省",
+      "name": "渭南市",
+      "id": "610500"
+    },
+    {
+      "province": "陕西省",
+      "name": "延安市",
+      "id": "610600"
+    },
+    {
+      "province": "陕西省",
+      "name": "汉中市",
+      "id": "610700"
+    },
+    {
+      "province": "陕西省",
+      "name": "榆林市",
+      "id": "610800"
+    },
+    {
+      "province": "陕西省",
+      "name": "安康市",
+      "id": "610900"
+    },
+    {
+      "province": "陕西省",
+      "name": "商洛市",
+      "id": "611000"
+    }
+  ],
+  "620000": [
+    {
+      "province": "甘肃省",
+      "name": "兰州市",
+      "id": "620100"
+    },
+    {
+      "province": "甘肃省",
+      "name": "嘉峪关市",
+      "id": "620200"
+    },
+    {
+      "province": "甘肃省",
+      "name": "金昌市",
+      "id": "620300"
+    },
+    {
+      "province": "甘肃省",
+      "name": "白银市",
+      "id": "620400"
+    },
+    {
+      "province": "甘肃省",
+      "name": "天水市",
+      "id": "620500"
+    },
+    {
+      "province": "甘肃省",
+      "name": "武威市",
+      "id": "620600"
+    },
+    {
+      "province": "甘肃省",
+      "name": "张掖市",
+      "id": "620700"
+    },
+    {
+      "province": "甘肃省",
+      "name": "平凉市",
+      "id": "620800"
+    },
+    {
+      "province": "甘肃省",
+      "name": "酒泉市",
+      "id": "620900"
+    },
+    {
+      "province": "甘肃省",
+      "name": "庆阳市",
+      "id": "621000"
+    },
+    {
+      "province": "甘肃省",
+      "name": "定西市",
+      "id": "621100"
+    },
+    {
+      "province": "甘肃省",
+      "name": "陇南市",
+      "id": "621200"
+    },
+    {
+      "province": "甘肃省",
+      "name": "临夏回族自治州",
+      "id": "622900"
+    },
+    {
+      "province": "甘肃省",
+      "name": "甘南藏族自治州",
+      "id": "623000"
+    }
+  ],
+  "630000": [
+    {
+      "province": "青海省",
+      "name": "西宁市",
+      "id": "630100"
+    },
+    {
+      "province": "青海省",
+      "name": "海东市",
+      "id": "630200"
+    },
+    {
+      "province": "青海省",
+      "name": "海北藏族自治州",
+      "id": "632200"
+    },
+    {
+      "province": "青海省",
+      "name": "黄南藏族自治州",
+      "id": "632300"
+    },
+    {
+      "province": "青海省",
+      "name": "海南藏族自治州",
+      "id": "632500"
+    },
+    {
+      "province": "青海省",
+      "name": "果洛藏族自治州",
+      "id": "632600"
+    },
+    {
+      "province": "青海省",
+      "name": "玉树藏族自治州",
+      "id": "632700"
+    },
+    {
+      "province": "青海省",
+      "name": "海西蒙古族藏族自治州",
+      "id": "632800"
+    }
+  ],
+  "640000": [
+    {
+      "province": "宁夏回族自治区",
+      "name": "银川市",
+      "id": "640100"
+    },
+    {
+      "province": "宁夏回族自治区",
+      "name": "石嘴山市",
+      "id": "640200"
+    },
+    {
+      "province": "宁夏回族自治区",
+      "name": "吴忠市",
+      "id": "640300"
+    },
+    {
+      "province": "宁夏回族自治区",
+      "name": "固原市",
+      "id": "640400"
+    },
+    {
+      "province": "宁夏回族自治区",
+      "name": "中卫市",
+      "id": "640500"
+    }
+  ],
+  "650000": [
+    {
+      "province": "新疆维吾尔自治区",
+      "name": "乌鲁木齐市",
+      "id": "650100"
+    },
+    {
+      "province": "新疆维吾尔自治区",
+      "name": "克拉玛依市",
+      "id": "650200"
+    },
+    {
+      "province": "新疆维吾尔自治区",
+      "name": "吐鲁番市",
+      "id": "650400"
+    },
+    {
+      "province": "新疆维吾尔自治区",
+      "name": "哈密市",
+      "id": "650500"
+    },
+    {
+      "province": "新疆维吾尔自治区",
+      "name": "昌吉回族自治州",
+      "id": "652300"
+    },
+    {
+      "province": "新疆维吾尔自治区",
+      "name": "博尔塔拉蒙古自治州",
+      "id": "652700"
+    },
+    {
+      "province": "新疆维吾尔自治区",
+      "name": "巴音郭楞蒙古自治州",
+      "id": "652800"
+    },
+    {
+      "province": "新疆维吾尔自治区",
+      "name": "阿克苏地区",
+      "id": "652900"
+    },
+    {
+      "province": "新疆维吾尔自治区",
+      "name": "克孜勒苏柯尔克孜自治州",
+      "id": "653000"
+    },
+    {
+      "province": "新疆维吾尔自治区",
+      "name": "喀什地区",
+      "id": "653100"
+    },
+    {
+      "province": "新疆维吾尔自治区",
+      "name": "和田地区",
+      "id": "653200"
+    },
+    {
+      "province": "新疆维吾尔自治区",
+      "name": "伊犁哈萨克自治州",
+      "id": "654000"
+    },
+    {
+      "province": "新疆维吾尔自治区",
+      "name": "塔城地区",
+      "id": "654200"
+    },
+    {
+      "province": "新疆维吾尔自治区",
+      "name": "阿勒泰地区",
+      "id": "654300"
+    },
+    {
+      "province": "新疆维吾尔自治区",
+      "name": "自治区直辖县级行政区划",
+      "id": "659000"
+    }
+  ]
+}

+ 138 - 0
src/pages/personalCenter/geographic/province.json

@@ -0,0 +1,138 @@
+[
+  {
+    "name": "北京市",
+    "id": "110000"
+  },
+  {
+    "name": "天津市",
+    "id": "120000"
+  },
+  {
+    "name": "河北省",
+    "id": "130000"
+  },
+  {
+    "name": "山西省",
+    "id": "140000"
+  },
+  {
+    "name": "内蒙古自治区",
+    "id": "150000"
+  },
+  {
+    "name": "辽宁省",
+    "id": "210000"
+  },
+  {
+    "name": "吉林省",
+    "id": "220000"
+  },
+  {
+    "name": "黑龙江省",
+    "id": "230000"
+  },
+  {
+    "name": "上海市",
+    "id": "310000"
+  },
+  {
+    "name": "江苏省",
+    "id": "320000"
+  },
+  {
+    "name": "浙江省",
+    "id": "330000"
+  },
+  {
+    "name": "安徽省",
+    "id": "340000"
+  },
+  {
+    "name": "福建省",
+    "id": "350000"
+  },
+  {
+    "name": "江西省",
+    "id": "360000"
+  },
+  {
+    "name": "山东省",
+    "id": "370000"
+  },
+  {
+    "name": "河南省",
+    "id": "410000"
+  },
+  {
+    "name": "湖北省",
+    "id": "420000"
+  },
+  {
+    "name": "湖南省",
+    "id": "430000"
+  },
+  {
+    "name": "广东省",
+    "id": "440000"
+  },
+  {
+    "name": "广西壮族自治区",
+    "id": "450000"
+  },
+  {
+    "name": "海南省",
+    "id": "460000"
+  },
+  {
+    "name": "重庆市",
+    "id": "500000"
+  },
+  {
+    "name": "四川省",
+    "id": "510000"
+  },
+  {
+    "name": "贵州省",
+    "id": "520000"
+  },
+  {
+    "name": "云南省",
+    "id": "530000"
+  },
+  {
+    "name": "西藏自治区",
+    "id": "540000"
+  },
+  {
+    "name": "陕西省",
+    "id": "610000"
+  },
+  {
+    "name": "甘肃省",
+    "id": "620000"
+  },
+  {
+    "name": "青海省",
+    "id": "630000"
+  },
+  {
+    "name": "宁夏回族自治区",
+    "id": "640000"
+  },
+  {
+    "name": "新疆维吾尔自治区",
+    "id": "650000"
+  },
+  {
+    "name": "台湾省",
+    "id": "710000"
+  },
+  {
+    "name": "香港特别行政区",
+    "id": "810000"
+  },
+  {
+    "name": "澳门特别行政区",
+    "id": "820000"
+  }
+]

+ 111 - 0
src/pages/personalCenter/index.tsx

@@ -0,0 +1,111 @@
+import React, { useState, useRef, useLayoutEffect } from 'react';
+import { GridContent } from '@ant-design/pro-layout';
+import { Menu } from 'antd';
+import BaseView from './components/base';
+import BindingView from './components/binding';
+import NotificationView from './components/notification';
+import SecurityView from './components/security';
+import styles from './style.less';
+
+const { Item } = Menu;
+
+type PAGE_NAME_UPPER_CAMEL_CASEStateKeys = 'base' | 'security' | 'binding' | 'notification';
+type PAGE_NAME_UPPER_CAMEL_CASEState = {
+  mode: 'inline' | 'horizontal';
+  selectKey: PAGE_NAME_UPPER_CAMEL_CASEStateKeys;
+};
+
+const PAGE_NAME_UPPER_CAMEL_CASE: React.FC = () => {
+  const menuMap: Record<string, React.ReactNode> = {
+    // base: '基本设置',
+    security: '安全设置',
+    // binding: '账号绑定',
+    notification: '消息',
+  };
+
+  const [initConfig, setInitConfig] = useState<PAGE_NAME_UPPER_CAMEL_CASEState>({
+    mode: 'inline',
+    selectKey: 'security',
+  });
+  const dom = useRef<HTMLDivElement>();
+
+  const resize = () => {
+    requestAnimationFrame(() => {
+      if (!dom.current) {
+        return;
+      }
+      let mode: 'inline' | 'horizontal' = 'inline';
+      const { offsetWidth } = dom.current;
+      if (dom.current.offsetWidth < 641 && offsetWidth > 400) {
+        mode = 'horizontal';
+      }
+      if (window.innerWidth < 768 && offsetWidth > 400) {
+        mode = 'horizontal';
+      }
+      setInitConfig({ ...initConfig, mode: mode as PAGE_NAME_UPPER_CAMEL_CASEState['mode'] });
+    });
+  };
+
+  useLayoutEffect(() => {
+    if (dom.current) {
+      window.addEventListener('resize', resize);
+      resize();
+    }
+    return () => {
+      window.removeEventListener('resize', resize);
+    };
+  }, [dom.current]);
+
+  const getMenu = () => {
+    return Object.keys(menuMap).map((item) => <Item key={item}>{menuMap[item]}</Item>);
+  };
+
+  const renderChildren = () => {
+    const { selectKey } = initConfig;
+    switch (selectKey) {
+      case 'base':
+        return <BaseView />;
+      case 'security':
+        return <SecurityView />;
+      case 'binding':
+        return <BindingView />;
+      case 'notification':
+        return <NotificationView />;
+      default:
+        return null;
+    }
+  };
+
+  return (
+    <GridContent>
+      <div
+        className={styles.main}
+        ref={(ref) => {
+          if (ref) {
+            dom.current = ref;
+          }
+        }}
+      >
+        <div className={styles.leftMenu}>
+          <Menu
+            mode={initConfig.mode}
+            selectedKeys={[initConfig.selectKey]}
+            onClick={({ key }) => {
+              setInitConfig({
+                ...initConfig,
+                selectKey: key as PAGE_NAME_UPPER_CAMEL_CASEStateKeys,
+              });
+            }}
+          >
+            {getMenu()}
+          </Menu>
+        </div>
+        <div className={styles.right}>
+          <div className={styles.title}>{menuMap[initConfig.selectKey]}</div>
+          {renderChildren()}
+        </div>
+      </div>
+    </GridContent>
+  );
+};
+export default PAGE_NAME_UPPER_CAMEL_CASE;

+ 18 - 0
src/pages/personalCenter/service.ts

@@ -0,0 +1,18 @@
+import { request } from 'umi';
+import type { CurrentUser, GeographicItemType } from './data';
+
+export async function queryCurrent(): Promise<{ data: CurrentUser }> {
+  return request('/api/accountSettingCurrentUser');
+}
+
+export async function queryProvince(): Promise<{ data: GeographicItemType[] }> {
+  return request('/api/geographic/province');
+}
+
+export async function queryCity(province: string): Promise<{ data: GeographicItemType[] }> {
+  return request(`/api/geographic/city/${province}`);
+}
+
+export async function query() {
+  return request('/api/users');
+}

+ 98 - 0
src/pages/personalCenter/style.less

@@ -0,0 +1,98 @@
+@import '~antd/es/style/themes/default.less';
+
+.main {
+  display: flex;
+  flex: 1;
+  height: calc(100vh - 200px);
+  padding-top: 16px;
+  padding-bottom: 16px;
+  margin: 16px 16px;
+  background-color: @menu-bg;
+  .leftMenu {
+    width: 224px;
+    border-right: @border-width-base @border-style-base @border-color-split;
+    :global {
+      .ant-menu-inline {
+        border: none;
+      }
+      .ant-menu:not(.ant-menu-horizontal) .ant-menu-item-selected {
+        font-weight: bold;
+      }
+    }
+  }
+  .right {
+    flex: 1;
+    padding: 8px 40px;
+    .title {
+      margin-bottom: 12px;
+      color: @heading-color;
+      font-weight: 500;
+      font-size: 20px;
+      line-height: 28px;
+    }
+
+    .rightListItem {
+      background-color: #eee;
+    }
+  }
+  :global {
+    .ant-list-split .ant-list-item:last-child {
+      border-bottom: 1px solid @border-color-split;
+    }
+    .ant-list-item {
+      padding-top: 14px;
+      padding-bottom: 14px;
+    }
+  }
+}
+:global {
+  .kcmp-ant-list-item-meta {
+    // 账号绑定图标
+    .taobao {
+      display: block;
+      color: #ff4000;
+      font-size: 48px;
+      line-height: 48px;
+      border-radius: @border-radius-base;
+    }
+    .dingding {
+      margin: 2px;
+      padding: 6px;
+      color: #fff;
+      font-size: 32px;
+      line-height: 32px;
+      background-color: #2eabff;
+      border-radius: @border-radius-base;
+    }
+    .alipay {
+      color: #2eabff;
+      font-size: 48px;
+      line-height: 48px;
+      border-radius: @border-radius-base;
+    }
+  }
+
+  // 密码强度
+  font.strong {
+    color: @success-color;
+  }
+  font.medium {
+    color: @warning-color;
+  }
+  font.weak {
+    color: @error-color;
+  }
+}
+
+@media screen and (max-width: @screen-md) {
+  .main {
+    flex-direction: column;
+    .leftMenu {
+      width: 100%;
+      border: none;
+    }
+    .right {
+      padding: 40px;
+    }
+  }
+}

+ 50 - 5
src/pages/platform/_layout.tsx

@@ -1,7 +1,7 @@
 /*
  * @Author: your name
  * @Date: 2022-01-06 15:25:39
- * @LastEditTime: 2022-02-14 16:42:22
+ * @LastEditTime: 2022-03-09 17:16:38
  * @LastEditors: Please set LastEditors
  * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/_layout.tsx
@@ -10,9 +10,10 @@
 import { IRouteComponentProps, useModel } from 'umi';
 // import { CrownOutlined, UserOutlined, SmileOutlined } from '@ant-design/icons';
 import ProLayout, { PageContainer } from '@ant-design/pro-layout';
-
 import { getPlatformMenu } from '@/service/menu';
 import './index.less';
+import { TreeItemType } from '@/utils';
+import { SpacicalPageParamsType } from '@/typings';
 
 export default function Layout({
   children,
@@ -20,11 +21,10 @@ export default function Layout({
   route,
   history,
   match,
+  ...rest
 }: IRouteComponentProps) {
   const { initialState, setInitialState } = useModel('@@initialState');
 
-  // console.log({children, location, route, history, match});
-
   return (
     <ProLayout
       style={{
@@ -33,7 +33,9 @@ export default function Layout({
       logoStyle={{
         display: 'none',
       }}
-      contentStyle={{}}
+      // location={{
+      //   pathname: '/platform/setting',
+      // }}
       disableContentMargin
       menuItemRender={(item, dom) => (
         <a
@@ -45,13 +47,56 @@ export default function Layout({
         </a>
       )}
       menu={{
+        autoClose: false,
+        params: {},
         request: async () => {
           if (initialState) {
             const systemId = initialState.currentSelectedSys?.id;
             if (systemId) {
               const menuData = await getPlatformMenu(systemId);
 
+              const getVFromTree = (data: TreeItemType[], key: string) => {
+                let result: SpacicalPageParamsType[] = [];
+                function looper(data: TreeItemType[], key: string) {
+                  data.forEach((t) => {
+                    if (t[key] && t[key] != 0) {
+                      //非一般页面
+                      result.push({
+                        contentType: t[key],
+                        path: t['path'],
+                        reportId: t['reportId'],
+                        url: t['youshuUrl'],
+                      });
+                    }
+                    if (t.children && t.children.length > 0) {
+                      looper(t.children, key);
+                    }
+                  });
+                }
+                looper(data, key);
+                return result;
+              };
+
+              const _menu = getVFromTree(menuData, 'contentType');
+
+              setInitialState((t) => ({ ...t, spacicalPageParamsType: _menu }));
+
               return menuData;
+
+              // return [
+              //   {
+              //     "path":"/platform/setting",
+              //     "name":"系统设置",
+              //     "softUrl":"/","icon":"",
+              //     "children":[
+              //       {"path":"/platform/setting/hospManage","name":"院区管理","softUrl":"/","icon":"","children":[]},
+              //       {"path":"/platform/setting/roleManage","name":"角色管理","softUrl":"/","icon":"","children":[]},
+              //       {"path":"/platform/setting/menuManage","name":"菜单管理","softUrl":"/","icon":"","children":[]},
+              //       {"path":"/platform/setting/userManage","name":"用户管理","softUrl":"/","icon":"","children":[]},
+              //       {"path":"/platform/setting/reports","name":"报表展示","softUrl":"/","icon":"","children":[]}
+              //     ]
+              //   }
+              // ]
             }
             return [];
           }

+ 33 - 40
src/pages/platform/components/menuEditer/menu.tsx

@@ -1,7 +1,7 @@
 /*
  * @Author: your name
  * @Date: 2022-01-14 14:03:42
- * @LastEditTime: 2022-02-08 10:28:11
+ * @LastEditTime: 2022-03-09 17:03:14
  * @LastEditors: Please set LastEditors
  * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/hospManage/modals/menu.tsx
@@ -28,11 +28,7 @@ export interface MenuEditerType {
   noAction?: boolean;
 }
 
-const MenuEditer: React.FC<MenuEditerType> = ({
-  value = [],
-  onChange,
-  noAction = false,
-}) => {
+const MenuEditer: React.FC<MenuEditerType> = ({ value = [], onChange, noAction = false }) => {
   const columns: ProColumns<MenuItemDataType>[] = [
     {
       title: 'ID',
@@ -73,27 +69,27 @@ const MenuEditer: React.FC<MenuEditerType> = ({
         return findType[0].label;
       },
     },
-    {
-      title: '操作',
-      width: 100,
-      key: 'option',
-      valueType: 'option',
-      render: (text, record) =>
-        record.parentId == '0'
-          ? [
-              <Popconfirm
-                title="是否初始化?"
-                onConfirm={() => {}}
-                // onCancel={cancel}
-                okText="确定"
-                cancelText="取消"
-                key="link2"
-              >
-                <a>初始化</a>
-              </Popconfirm>,
-            ]
-          : [],
-    },
+    // {
+    //   title: '操作',
+    //   width: 100,
+    //   key: 'option',
+    //   valueType: 'option',
+    //   render: (text, record) =>
+    //     record.parentId == '0'
+    //       ? [
+    //           <Popconfirm
+    //             title="是否初始化?"
+    //             onConfirm={() => {}}
+    //             // onCancel={cancel}
+    //             okText="确定"
+    //             cancelText="取消"
+    //             key="link2"
+    //           >
+    //             <a>初始化</a>
+    //           </Popconfirm>,
+    //         ]
+    //       : [],
+    // },
   ];
 
   const getData = async () => {
@@ -103,12 +99,15 @@ const MenuEditer: React.FC<MenuEditerType> = ({
     setDataSource(data);
   };
 
-  const onChangeHandle = (
-    selectedRowKeys: React.Key[],
-    selectedRows: any[],
-  ) => {
+  const onChangeHandle = (selectedRowKeys: React.Key[], selectedRows: any[]) => {
+    const menus = selectedRows.filter((t) => t.type == 1); //筛选出所有菜单
+
+    const menuIds = menus.map((t) => t.menuId);
+
+    console.log({ selectedRowKeys, selectedRows });
+
     setSelectedKeys(selectedRowKeys);
-    onChange && onChange(selectedRowKeys, selectedRows);
+    onChange && onChange(menuIds, selectedRows);
   };
 
   const [selectedKeys, setSelectedKeys] = useState<React.Key[]>([]);
@@ -182,16 +181,10 @@ const MenuEditer: React.FC<MenuEditerType> = ({
             // console.log({expanded, onExpand, record});
             return expanded
               ? record.children.length > 0 && (
-                  <DownOutlined
-                    onClick={(e) => onExpand(record, e)}
-                    style={{ marginRight: 10 }}
-                  />
+                  <DownOutlined onClick={(e) => onExpand(record, e)} style={{ marginRight: 10 }} />
                 )
               : record.children.length > 0 && (
-                  <RightOutlined
-                    onClick={(e) => onExpand(record, e)}
-                    style={{ marginRight: 10 }}
-                  />
+                  <RightOutlined onClick={(e) => onExpand(record, e)} style={{ marginRight: 10 }} />
                 );
           },
           onExpandedRowsChange: onExpandedRowsChangeHandle,

+ 1 - 0
src/pages/platform/components/menuEditer/style.less

@@ -1,4 +1,5 @@
 .MenuEditer {
+  width: 100%;
   .kcmp-ant-card-body {
     padding: 0;
   }

+ 28 - 13
src/pages/platform/setting/hospManage/index.tsx

@@ -1,7 +1,7 @@
 /*
  * @Author: your name
  * @Date: 2022-01-13 15:22:48
- * @LastEditTime: 2022-02-08 14:29:30
+ * @LastEditTime: 2022-03-02 15:47:20
  * @LastEditors: Please set LastEditors
  * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/hospManage/index.tsx
@@ -12,7 +12,7 @@ import { hospManageModelState, ConnectProps, Loading, connect } from 'umi';
 import { Button, Divider, Popconfirm } from 'antd';
 import KCTable from '@/components/kcTable';
 import type { ProColumns } from '@ant-design/pro-table';
-import { getAllHosp } from '@/service/hospList';
+import { getAllHosp, getHospYoushuAccounts } from '@/service/hospList';
 import { TableRequestParamsType } from '@/typings';
 import ActModal from './modals/modal';
 import './style.less';
@@ -25,6 +25,7 @@ export enum TableActType {
   DEL,
   EDIT,
   EDITMENU,
+  BINDACCOUNT, //绑定有数账号
 }
 
 interface PageProps extends ConnectProps {
@@ -79,14 +80,14 @@ const HospManage: FC<PageProps> = ({ hospManageModel: state, dispatch }) => {
     },
     {
       title: '操作',
-      width: 220,
+      width: 250,
       key: 'option',
       valueType: 'option',
       render: (text, record) => [
         <a key="link" onClick={() => editHandle(record)}>
           编辑
         </a>,
-        <Divider key="1" type="vertical" style={{ margin: '0 3px' }} />,
+        <Divider key="1" type="vertical" style={{ margin: '0 1px' }} />,
         <Popconfirm
           title="是否确定删除?"
           onConfirm={() => delHandle(record)}
@@ -97,10 +98,14 @@ const HospManage: FC<PageProps> = ({ hospManageModel: state, dispatch }) => {
         >
           <a>删除</a>
         </Popconfirm>,
-        <Divider key="2" type="vertical" style={{ margin: '0 3px' }} />,
+        <Divider key="2" type="vertical" style={{ margin: '0 1px' }} />,
         <a key="link3" onClick={() => editMenuBind(record)}>
           菜单
         </a>,
+        <Divider key="2" type="vertical" style={{ margin: '0 1px' }} />,
+        <a key="link3" onClick={() => youshuAccountBind(record)}>
+          报告
+        </a>,
       ],
     },
   ];
@@ -181,7 +186,23 @@ const HospManage: FC<PageProps> = ({ hospManageModel: state, dispatch }) => {
       });
   };
 
-  //  console.log({state});
+  const youshuAccountBind = async (record: TableListItem) => {
+    const { id } = record;
+    const resp = await getHospYoushuAccounts({ hospId: id });
+
+    if (resp) {
+      const { reportId, reportUrl, youshuUsers } = resp;
+      dispatch &&
+        dispatch({
+          type: 'hospManageModel/edit',
+          payload: {
+            data: { ...record, reportId, reportUrl, youshuUsers },
+            act: TableActType.BINDACCOUNT,
+            isShowModal: true,
+          },
+        });
+    }
+  };
 
   return (
     <div className="HospManage">
@@ -203,13 +224,7 @@ const HospManage: FC<PageProps> = ({ hospManageModel: state, dispatch }) => {
 };
 
 export default connect(
-  ({
-    hospManageModel,
-    loading,
-  }: {
-    hospManageModel: hospManageModelState;
-    loading: Loading;
-  }) => {
+  ({ hospManageModel, loading }: { hospManageModel: hospManageModelState; loading: Loading }) => {
     //  console.log({userManageModel});
     return {
       hospManageModel,

+ 150 - 33
src/pages/platform/setting/hospManage/modals/modal.tsx

@@ -1,23 +1,21 @@
 /*
  * @Author: your name
  * @Date: 2022-01-12 17:11:11
- * @LastEditTime: 2022-01-21 09:31:14
+ * @LastEditTime: 2022-03-04 09:06:04
  * @LastEditors: Please set LastEditors
  * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/userManage/modal.tsx
  */
 
-import React from 'react';
+import React, { useEffect, useRef, useState } from 'react';
 import KCModal from '@/components/KCModal';
 import KCProSelect from '@/components/KCProSelect';
 import { hospManageModelState, Dispatch } from 'umi';
 
-import {
-  ProFormText,
-  ProFormRadio,
-  ProFormDependency,
-} from '@ant-design/pro-form';
-import { getHospList } from '@/service/hospList';
+import { ProFormText, ProFormRadio, ProFormDependency, ProFormDigit } from '@ant-design/pro-form';
+import type { ProColumns } from '@ant-design/pro-table';
+import { EditableProTable } from '@ant-design/pro-table';
+import { getHospList, getHospYoushuAccounts, YoushuAccountsType } from '@/service/hospList';
 import type { AddUsersDataType } from '@/service/user';
 import { randomString } from '@/utils';
 import { TableActType } from '..';
@@ -28,14 +26,63 @@ interface ActModalProps extends hospManageModelState {
   dispatch: Dispatch | undefined;
 }
 
-const ActModal: React.FC<ActModalProps> = ({
-  dispatch,
-  isShowModal,
-  tableAct,
-  currentEdit,
-}) => {
+type DataSourceType = YoushuAccountsType & { key: number };
+
+const ActModal: React.FC<ActModalProps> = ({ dispatch, isShowModal, tableAct, currentEdit }) => {
+  const [editableKeys, setEditableRowKeys] = useState<React.Key[]>([]);
+  const [dataSource, setDataSource] = useState<DataSourceType[]>([]);
+
+  const columns: ProColumns<DataSourceType>[] = [
+    {
+      title: 'id',
+      dataIndex: 'id',
+      key: 'id',
+      hideInTable: true,
+    },
+    {
+      title: '账号',
+      dataIndex: 'account',
+      key: 'account',
+    },
+    {
+      title: '密码',
+      key: 'password',
+      dataIndex: 'password',
+    },
+    {
+      title: '是否默认',
+      dataIndex: 'isDefault',
+      valueType: 'select',
+      request: async () => [
+        {
+          value: 1,
+          label: '是',
+        },
+        {
+          value: 0,
+          label: '否',
+        },
+      ],
+    },
+    {
+      title: '操作',
+      valueType: 'option',
+      key: 'option',
+      width: 120,
+      render: (text, record, _, action) => [
+        <a
+          key="delete"
+          onClick={() => {
+            setDataSource(dataSource.filter((item) => item.key !== record.key));
+          }}
+        >
+          删除
+        </a>,
+      ],
+    },
+  ];
+
   const onVisibleChangeHandle = (bool: boolean) => {
-    // console.log({bool});
     if (!bool) {
       dispatch &&
         dispatch({
@@ -45,6 +92,7 @@ const ActModal: React.FC<ActModalProps> = ({
   };
 
   const onFinishHandle = (data: any & AddUsersDataType) => {
+    console.log({ data });
     if (tableAct == TableActType.ADD) {
       dispatch &&
         dispatch({
@@ -53,14 +101,17 @@ const ActModal: React.FC<ActModalProps> = ({
         });
     }
 
-    if (tableAct == TableActType.EDIT || tableAct == TableActType.EDITMENU) {
+    if (
+      tableAct == TableActType.EDIT ||
+      tableAct == TableActType.EDITMENU ||
+      tableAct == TableActType.BINDACCOUNT
+    ) {
       dispatch &&
         dispatch({
           type: 'hospManageModel/postEditData',
           payload: data,
         });
     }
-
     return true;
   };
 
@@ -74,6 +125,9 @@ const ActModal: React.FC<ActModalProps> = ({
     if (tableAct == TableActType.EDITMENU) {
       return '绑定菜单';
     }
+    if (tableAct == TableActType.BINDACCOUNT) {
+      return '院区报告设置';
+    }
   };
 
   const setInitialValues = () => {
@@ -89,8 +143,25 @@ const ActModal: React.FC<ActModalProps> = ({
     if (tableAct == TableActType.EDITMENU) {
       return { ...currentEdit };
     }
+
+    if (tableAct == TableActType.BINDACCOUNT) {
+      if (currentEdit?.reportId) {
+        return { ...currentEdit, reportId: parseInt(currentEdit.reportId) };
+      }
+    }
   };
 
+  useEffect(() => {
+    //加装key字段
+    const fixedDataSource = currentEdit?.youshuUsers
+      ? currentEdit.youshuUsers.map((t) => ({
+          ...t,
+          key: Number((Math.random() * 1000000).toFixed(0)),
+        }))
+      : [];
+    setDataSource(fixedDataSource);
+  }, [currentEdit]);
+
   return (
     <KCModal
       visible={isShowModal}
@@ -100,15 +171,20 @@ const ActModal: React.FC<ActModalProps> = ({
       initialValues={setInitialValues()}
       title={setModalTitle()}
       labelCol={{
-        span: 4,
+        span: 6,
       }}
-      onFinish={async (data) => onFinishHandle(data)}
+      wrapperCol={{ span: 12 }}
+      onFinish={async (data) =>
+        onFinishHandle(tableAct == TableActType.BINDACCOUNT ? { ...data, dataSource } : data)
+      }
     >
-      {tableAct == TableActType.EDITMENU ? (
+      {tableAct == TableActType.EDITMENU && (
         <Form.Item name="bindMenuIds">
           <MenuEditer />
         </Form.Item>
-      ) : (
+      )}
+
+      {tableAct != TableActType.EDITMENU && tableAct != TableActType.BINDACCOUNT && (
         <>
           <ProFormText
             width="md"
@@ -173,18 +249,8 @@ const ActModal: React.FC<ActModalProps> = ({
             }}
           </ProFormDependency>
           <ProFormText width="md" name="hospSign" label="医院标识" disabled />
-          <ProFormText
-            width="md"
-            name="hospAbbreviation"
-            label="简称"
-            placeholder="请输入"
-          />
-          <ProFormText
-            width="md"
-            name="systemName"
-            label="系统名称"
-            placeholder="请输入"
-          />
+          <ProFormText width="md" name="hospAbbreviation" label="简称" placeholder="请输入" />
+          <ProFormText width="md" name="systemName" label="系统名称" placeholder="请输入" />
           <ProFormRadio.Group
             name="isDataShare"
             label="是否数据分享"
@@ -201,6 +267,57 @@ const ActModal: React.FC<ActModalProps> = ({
           />
         </>
       )}
+      {tableAct == TableActType.BINDACCOUNT && (
+        <>
+          <ProFormText
+            width="md"
+            name="reportUrl"
+            label="报告请求地址"
+            placeholder="请输入"
+            rules={[
+              {
+                required: true,
+                message: '请输入!',
+              },
+            ]}
+          />
+          <ProFormDigit
+            label="报告项目Id"
+            name="reportId"
+            min={0}
+            fieldProps={{ precision: 0 }}
+            rules={[
+              {
+                required: true,
+                message: '请输入!',
+              },
+            ]}
+          />
+          <EditableProTable<DataSourceType>
+            rowKey="key"
+            headerTitle="院区[有数]账号绑定"
+            columns={columns}
+            value={dataSource}
+            recordCreatorProps={{
+              record: {
+                key: Number((Math.random() * 1000000).toFixed(0)),
+                id: -1,
+                userName: '',
+                account: '',
+                password: '',
+                isDefault: 0,
+              },
+            }}
+            onChange={setDataSource}
+            editable={{
+              // type: 'multiple',
+              deletePopconfirmMessage: '确定删除此行?',
+              editableKeys,
+              onChange: setEditableRowKeys,
+            }}
+          />
+        </>
+      )}
     </KCModal>
   );
 };

+ 38 - 9
src/pages/platform/setting/hospManage/model.ts

@@ -1,14 +1,23 @@
 /*
  * @Author: your name
  * @Date: 2022-01-12 10:12:55
- * @LastEditTime: 2022-01-21 09:30:46
+ * @LastEditTime: 2022-03-03 09:05:55
  * @LastEditors: Please set LastEditors
  * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/userManage/model.ts
  */
 
 import { Effect, ImmerReducer, Reducer, Subscription } from 'umi';
-import { addHosp, delHosp, editHosp, hospBindMenu } from '@/service/hospList';
+import {
+  addHosp,
+  delHosp,
+  editHosp,
+  GetHospYoushuAccountsType,
+  hospBindMenu,
+  hospBindYoushuAccount,
+  YoushuAccountsType,
+  YoushuUserSaveDTOs,
+} from '@/service/hospList';
 import type { getUsersParams } from '@/service/user';
 import { HospTableItem as TableListItem } from '@/service/hospList';
 // import { TableActType } from '.';
@@ -19,14 +28,16 @@ enum TableActType {
   DEL,
   EDIT,
   EDITMENU,
+  BINDACCOUNT, //绑定有数账号
 }
 
+type CurrentSelectedData = TableListItem & GetHospYoushuAccountsType;
 export interface hospManageModelState {
   name: string;
   tableAct: TableActType;
   isShowModal: boolean;
   reloadTable: boolean;
-  currentEdit: TableListItem | undefined;
+  currentEdit: CurrentSelectedData | undefined;
 }
 
 export interface hospManageModelType {
@@ -71,15 +82,12 @@ const hospManageModel: hospManageModelType = {
       });
     },
     *postEditData({ payload }, { call, put, select }) {
+      // console.log({payload});
       const {
         tableAct,
         currentEdit: currentEditOld,
       }: { tableAct: TableActType; currentEdit: TableListItem } = yield select(
-        ({
-          hospManageModel: state,
-        }: {
-          hospManageModel: hospManageModelState;
-        }) => {
+        ({ hospManageModel: state }: { hospManageModel: hospManageModelState }) => {
           return {
             tableAct: state.tableAct,
             currentEdit: state.currentEdit,
@@ -87,6 +95,25 @@ const hospManageModel: hospManageModelType = {
         },
       );
 
+      if (tableAct == TableActType.BINDACCOUNT) {
+        const defaultAccount = payload.dataSource.filter((t: YoushuAccountsType) => t.isDefault);
+        //  return;
+        yield hospBindYoushuAccount({
+          hospId: currentEditOld.id,
+          reportId: payload.reportId,
+          reportUrl: payload.reportUrl,
+          userId: defaultAccount.length > 0 ? defaultAccount[0].id : 0,
+          youshuUserSaveDTOs: payload.dataSource.map((t: YoushuUserSaveDTOs) => ({
+            account: t.account,
+            password: t.password,
+          })),
+        });
+        yield put({
+          type: 'reloadTable',
+          payload: true,
+        });
+      }
+
       if (tableAct == TableActType.EDITMENU) {
         //绑定菜单
         yield hospBindMenu({
@@ -97,7 +124,9 @@ const hospManageModel: hospManageModelType = {
           type: 'reloadTable',
           payload: true,
         });
-      } else {
+      }
+
+      if (tableAct == TableActType.EDIT) {
         //编辑院区信息
         yield editHosp({ ...currentEditOld, ...payload });
 

+ 9 - 23
src/pages/platform/setting/menuManage/index.tsx

@@ -1,7 +1,7 @@
 /*
  * @Author: your name
  * @Date: 2022-01-13 15:22:48
- * @LastEditTime: 2022-02-09 10:51:13
+ * @LastEditTime: 2022-03-03 16:10:32
  * @LastEditors: Please set LastEditors
  * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/hospManage/index.tsx
@@ -75,10 +75,10 @@ const MenuManage: FC<PageProps> = ({ menuManageModel: state, dispatch }) => {
         return findType[0].label;
       },
     },
-    {
-      title: 'URL',
-      dataIndex: 'url',
-    },
+    // {
+    //   title: 'URL',
+    //   dataIndex: 'url',
+    // },
     {
       title: 'Path',
       dataIndex: 'path',
@@ -119,9 +119,7 @@ const MenuManage: FC<PageProps> = ({ menuManageModel: state, dispatch }) => {
     },
   ];
 
-  const getData = async (
-    params: { name?: string } & TableRequestParamsType,
-  ) => {
+  const getData = async (params: { name?: string } & TableRequestParamsType) => {
     const { current = 1, pageSize = 1000, name } = params;
     const resp = await getAllMenus();
 
@@ -216,16 +214,10 @@ const MenuManage: FC<PageProps> = ({ menuManageModel: state, dispatch }) => {
             // console.log({expanded, onExpand, record});
             return expanded
               ? record.children.length > 0 && (
-                  <DownOutlined
-                    onClick={(e) => onExpand(record, e)}
-                    style={{ marginRight: 10 }}
-                  />
+                  <DownOutlined onClick={(e) => onExpand(record, e)} style={{ marginRight: 10 }} />
                 )
               : record.children.length > 0 && (
-                  <RightOutlined
-                    onClick={(e) => onExpand(record, e)}
-                    style={{ marginRight: 10 }}
-                  />
+                  <RightOutlined onClick={(e) => onExpand(record, e)} style={{ marginRight: 10 }} />
                 );
           },
         }}
@@ -235,13 +227,7 @@ const MenuManage: FC<PageProps> = ({ menuManageModel: state, dispatch }) => {
 };
 
 export default connect(
-  ({
-    menuManageModel,
-    loading,
-  }: {
-    menuManageModel: menuManageModelState;
-    loading: Loading;
-  }) => {
+  ({ menuManageModel, loading }: { menuManageModel: menuManageModelState; loading: Loading }) => {
     //  console.log({userManageModel});
     return {
       menuManageModel,

+ 73 - 15
src/pages/platform/setting/menuManage/modals/modal.tsx

@@ -1,7 +1,7 @@
 /*
  * @Author: your name
  * @Date: 2022-01-12 17:11:11
- * @LastEditTime: 2022-02-09 10:56:58
+ * @LastEditTime: 2022-03-09 16:53:54
  * @LastEditors: Please set LastEditors
  * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/userManage/modal.tsx
@@ -12,12 +12,7 @@ import KCModal from '@/components/KCModal';
 import KCProSelect from '@/components/KCProSelect';
 import { menuManageModelState, Dispatch } from 'umi';
 
-import {
-  ProFormText,
-  ProFormRadio,
-  ProFormDependency,
-} from '@ant-design/pro-form';
-import { getHospList } from '@/service/hospList';
+import { ProFormText, ProFormDependency, ProFormDigit } from '@ant-design/pro-form';
 import type { AddUsersDataType } from '@/service/user';
 import { randomString } from '@/utils';
 import { MenuTypes } from '@/constant';
@@ -85,6 +80,10 @@ const ActModal: React.FC<ActModalProps> = ({
       //子系统菜单目录
       return MenuTypes.filter((t) => t.label == '菜单');
     }
+    if (record?.type == 0) {
+      //子系统菜单目录
+      return MenuTypes.filter((t) => t.label == '菜单' || t.label == '目录');
+    }
     return MenuTypes;
   };
 
@@ -101,8 +100,9 @@ const ActModal: React.FC<ActModalProps> = ({
       }
       title={tableAct == TableActType.EDIT ? '编辑菜单' : '新增菜单'}
       labelCol={{
-        span: 4,
+        span: 6,
       }}
+      wrapperCol={{ span: 12 }}
       onFinish={async (data) => onFinishHandle(data)}
     >
       <ProFormText
@@ -136,7 +136,7 @@ const ActModal: React.FC<ActModalProps> = ({
         placeholder="请输入"
         rules={[
           {
-            required: true,
+            required: false,
             message: '请输入!',
           },
         ]}
@@ -153,12 +153,70 @@ const ActModal: React.FC<ActModalProps> = ({
           },
         ]}
       />
-      <ProFormText
-        width="md"
-        name="icon"
-        label="菜单icon"
-        placeholder="请输入"
-      />
+      <ProFormText width="md" name="icon" label="菜单icon" placeholder="请输入" />
+      <ProFormDependency name={['type']}>
+        {({ type }) => {
+          return (
+            type == 1 && (
+              //类型时菜单时
+              <>
+                <KCProSelect
+                  label="内容类型"
+                  width="md"
+                  name="contentType"
+                  initialValue={0}
+                  options={[
+                    {
+                      label: '一般',
+                      value: 0, //普通页面,默认值
+                    },
+                    {
+                      label: '报告',
+                      value: 1,
+                    },
+                    {
+                      label: '大屏',
+                      value: 2,
+                    },
+                    {
+                      label: '填报',
+                      value: 3,
+                    },
+                  ]}
+                  rules={[
+                    {
+                      required: true,
+                      message: '请选择!',
+                    },
+                  ]}
+                />
+                <ProFormDependency name={['contentType']}>
+                  {({ contentType }) => {
+                    return (
+                      contentType &&
+                      contentType != 0 && (
+                        //页面内容为非一般时,填写对应有数Id
+                        <ProFormDigit
+                          label="报告Id"
+                          name="reportId"
+                          min={1}
+                          fieldProps={{ precision: 0 }}
+                          rules={[
+                            {
+                              required: true,
+                              message: '请填写id!',
+                            },
+                          ]}
+                        />
+                      )
+                    );
+                  }}
+                </ProFormDependency>
+              </>
+            )
+          );
+        }}
+      </ProFormDependency>
     </KCModal>
   );
 };

+ 55 - 0
src/pages/platform/setting/reports/index.tsx

@@ -0,0 +1,55 @@
+/*
+ * @Author: your name
+ * @Date: 2022-03-03 18:04:40
+ * @LastEditTime: 2022-03-04 11:18:43
+ * @LastEditors: Please set LastEditors
+ * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/reports/index.tsx
+ */
+
+import { useEffect, useState } from 'react';
+import { useModel } from 'umi';
+import { Skeleton } from 'antd';
+
+export default () => {
+  const { initialState, setInitialState } = useModel('@@initialState');
+  const [specialPageUrl, setspecialPageUrl] = useState<string | undefined>(undefined);
+  const [loading, setloading] = useState(false);
+
+  const onLoadhandle = () => {
+    setloading(false);
+  };
+
+  useEffect(() => {
+    setloading(true);
+    if (initialState && initialState.spacicalPageParamsType && initialState.userData) {
+      const {
+        spacicalPageParamsType,
+        userData: { youshuToken },
+      } = initialState;
+      const { pathname } = location;
+      const spacialPage = spacicalPageParamsType.filter((t) => t.path == pathname);
+
+      // console.log({pathname,spacialPage,spacicalPageParamsType,initialState});
+
+      if (spacialPage.length > 0) {
+        //当前页面属于有数数据展示页面
+        console.log(`${spacialPage[0].url}&token=${youshuToken}`);
+
+        const url = `${spacialPage[0].url}&token=${youshuToken}`;
+        setspecialPageUrl(url);
+      }
+    }
+  }, [initialState]);
+
+  return (
+    <>
+      <Skeleton loading={loading} paragraph={{ rows: 50 }} active />
+      <iframe
+        onLoad={() => onLoadhandle()}
+        style={{ width: '100%', height: '100%', border: 'none' }}
+        src={specialPageUrl}
+      ></iframe>
+    </>
+  );
+};

+ 7 - 13
src/pages/platform/setting/roleManage/index.tsx

@@ -1,7 +1,7 @@
 /*
  * @Author: your name
  * @Date: 2022-01-13 15:22:48
- * @LastEditTime: 2022-01-20 10:46:26
+ * @LastEditTime: 2022-03-03 14:27:58
  * @LastEditors: Please set LastEditors
  * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/hospManage/index.tsx
@@ -12,11 +12,7 @@ import { roleManageModelState, ConnectProps, Loading, connect } from 'umi';
 import { Button, Divider, Popconfirm } from 'antd';
 import KCTable from '@/components/kcTable';
 import type { ProColumns } from '@ant-design/pro-table';
-import {
-  getAllRoles,
-  getRoleHasBindMenus,
-  getRoleHasBindUsers,
-} from '@/service/role';
+import { getAllRoles, getRoleHasBindMenus, getRoleHasBindUsers } from '@/service/role';
 import { TableRequestParamsType } from '@/typings';
 import ActModal from './modals/modal';
 import './style.less';
@@ -62,6 +58,10 @@ const RoleManage: FC<PageProps> = ({ roleManageModel: state, dispatch }) => {
       title: '变更人',
       dataIndex: 'hospAbbreviation',
     },
+    {
+      title: '有数账号',
+      dataIndex: 'account',
+    },
     {
       title: '变更日期',
       dataIndex: 'modifyTime',
@@ -204,13 +204,7 @@ const RoleManage: FC<PageProps> = ({ roleManageModel: state, dispatch }) => {
 };
 
 export default connect(
-  ({
-    roleManageModel,
-    loading,
-  }: {
-    roleManageModel: roleManageModelState;
-    loading: Loading;
-  }) => {
+  ({ roleManageModel, loading }: { roleManageModel: roleManageModelState; loading: Loading }) => {
     //  console.log({userManageModel});
     return {
       roleManageModel,

+ 24 - 7
src/pages/platform/setting/roleManage/modals/modal.tsx

@@ -1,7 +1,7 @@
 /*
  * @Author: your name
  * @Date: 2022-01-12 17:11:11
- * @LastEditTime: 2022-02-09 10:09:22
+ * @LastEditTime: 2022-03-09 17:11:50
  * @LastEditors: Please set LastEditors
  * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/userManage/modal.tsx
@@ -14,7 +14,7 @@ import { roleManageModelState, Dispatch } from 'umi';
 
 import { ProFormText, ProFormTextArea } from '@ant-design/pro-form';
 import { getHospList } from '@/service/hospList';
-import type { AddUsersDataType } from '@/service/user';
+import { AddUsersDataType, getYoushuUsers } from '@/service/user';
 
 import { TableActType } from '..';
 import { Form } from 'antd';
@@ -88,10 +88,7 @@ const ActModal: React.FC<ActModalProps> = ({
     if (tableAct == TableActType.ADD) {
       return { hospId: hospId };
     }
-    if (
-      tableAct == TableActType.EDITMENU ||
-      tableAct == TableActType.EDITRELAUSER
-    ) {
+    if (tableAct == TableActType.EDITMENU || tableAct == TableActType.EDITRELAUSER) {
       return { ...currentEdit };
     }
   };
@@ -105,7 +102,7 @@ const ActModal: React.FC<ActModalProps> = ({
       initialValues={setInitialValues()}
       title={setModalTitle()}
       labelCol={{
-        span: 4,
+        span: 5,
       }}
       onFinish={async (data) => onFinishHandle(data)}
     >
@@ -151,6 +148,26 @@ const ActModal: React.FC<ActModalProps> = ({
               },
             ]}
           />
+
+          <KCProSelect
+            label="关联有数账号"
+            width="md"
+            name="youshuUserId"
+            request={async () => {
+              if (currentEdit) {
+                const { roleId } = currentEdit;
+                const resp = await getYoushuUsers(roleId);
+                if (resp) {
+                  return resp.map((t) => ({
+                    label: t.account,
+                    value: t.id,
+                  }));
+                }
+              }
+              return [];
+            }}
+          />
+
           <ProFormTextArea
             name="remark"
             label="备注"

+ 3 - 14
src/pages/platform/setting/userManage/index.tsx

@@ -1,7 +1,7 @@
 /*
  * @Author: your name
  * @Date: 2022-01-11 09:43:18
- * @LastEditTime: 2022-02-10 09:03:49
+ * @LastEditTime: 2022-03-07 14:44:22
  * @LastEditors: Please set LastEditors
  * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/userManage/index.tsx
@@ -96,12 +96,7 @@ const UserManage: FC<PageProps> = ({ userManageModel: state, dispatch }) => {
   ];
 
   const getUserData = async (params: TableRequestParamsType) => {
-    const {
-      current = 1,
-      pageSize = 10,
-      name = undefined,
-      account = undefined,
-    } = params;
+    const { current = 1, pageSize = 10, name = undefined, account = undefined } = params;
 
     const resp = await getUsers({
       current,
@@ -217,13 +212,7 @@ const UserManage: FC<PageProps> = ({ userManageModel: state, dispatch }) => {
 };
 
 export default connect(
-  ({
-    userManageModel,
-    loading,
-  }: {
-    userManageModel: userManageModelState;
-    loading: Loading;
-  }) => {
+  ({ userManageModel, loading }: { userManageModel: userManageModelState; loading: Loading }) => {
     //  console.log({userManageModel});
     return {
       userManageModel,

+ 2 - 6
src/pages/platform/setting/userManage/model.ts

@@ -1,7 +1,7 @@
 /*
  * @Author: your name
  * @Date: 2022-01-12 10:12:55
- * @LastEditTime: 2022-02-10 09:02:58
+ * @LastEditTime: 2022-03-07 14:44:53
  * @LastEditors: Please set LastEditors
  * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/userManage/model.ts
@@ -85,11 +85,7 @@ const userManageModel: userManageModelType = {
     },
     *postEditUserData({ payload }, { call, put, select }) {
       const currentEditUserOld = yield select(
-        ({
-          userManageModel: state,
-        }: {
-          userManageModel: userManageModelState;
-        }) => {
+        ({ userManageModel: state }: { userManageModel: userManageModelState }) => {
           return state.currentEditUser;
         },
       );

+ 19 - 0
src/password-quality-calculator.d.ts

@@ -0,0 +1,19 @@
+/*
+ * @Author: your name
+ * @Date: 2022-03-09 15:43:36
+ * @LastEditTime: 2022-03-09 15:43:37
+ * @LastEditors: Please set LastEditors
+ * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ * @FilePath: /KC-MiddlePlatform/src/password-quality-calculator.d.ts
+ */
+
+declare module 'password-quality-calculator' {
+  const content: any;
+  /// 这里的 content 可以根据自己的需要,添加需要的类型,这的话可以让 ts 更好的提示
+  /**
+    type content = {
+      test: string
+    }
+   */
+  export = content;
+}

+ 2 - 1
src/service/api.d.ts

@@ -1,7 +1,7 @@
 /*
  * @Author: your name
  * @Date: 2021-11-11 11:23:56
- * @LastEditTime: 2022-01-12 10:05:06
+ * @LastEditTime: 2022-03-04 11:41:56
  * @LastEditors: Please set LastEditors
  * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  * @FilePath: /KC-MiddlePlatform/src/service/api.d.ts
@@ -47,5 +47,6 @@ declare namespace userRelationInfo {
     name: string;
     icon: string;
     url: string;
+    path: string;
   };
 }

+ 44 - 5
src/service/hospList.ts

@@ -1,7 +1,7 @@
 /*
  * @Author: your name
  * @Date: 2022-01-13 09:15:59
- * @LastEditTime: 2022-02-08 14:25:50
+ * @LastEditTime: 2022-03-02 17:16:06
  * @LastEditors: Please set LastEditors
  * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  * @FilePath: /KC-MiddlePlatform/src/service/hospList.ts
@@ -105,12 +105,51 @@ export const editHosp = async (data: EditHospType) => {
 
 //院区绑定菜单
 
-export const hospBindMenu = async (data: {
-  hospId: number;
-  menuIds: string[];
-}) => {
+export const hospBindMenu = async (data: { hospId: number; menuIds: string[] }) => {
   return request('/master/centerSys/hospital/addHospMenu', {
     method: 'POST',
     data: data,
   });
 };
+
+export type YoushuAccountsType = {
+  id: number;
+  userName: string;
+  account: string;
+  password: string;
+  isDefault: number; //是否默认0,非默认,1.默认
+};
+
+export type GetHospYoushuAccountsType = {
+  reportUrl: string;
+  reportId: string;
+  youshuUsers: YoushuAccountsType[];
+};
+
+export const getHospYoushuAccounts = async (data: { hospId: number }) => {
+  return request<GetHospYoushuAccountsType>('/master/centerSys/hospital/getHospReport', {
+    method: 'GET',
+    params: data,
+  });
+};
+
+export type YoushuUserSaveDTOs = {
+  userName: string;
+  account: string;
+  password: string;
+};
+
+export type HospBindYoushuAccountReqBodyType = {
+  hospId: number;
+  reportId: number;
+  reportUrl: string;
+  userId: number;
+  youshuUserSaveDTOs: YoushuUserSaveDTOs[];
+};
+
+export const hospBindYoushuAccount = async (data: HospBindYoushuAccountReqBodyType) => {
+  return request('/master/centerSys/hospital/saveHospReport', {
+    method: 'POST',
+    data: data,
+  });
+};

+ 8 - 6
src/service/login.ts

@@ -1,7 +1,7 @@
 /*
  * @Author: your name
  * @Date: 2021-11-11 10:35:56
- * @LastEditTime: 2022-02-14 15:46:24
+ * @LastEditTime: 2022-03-03 15:50:52
  * @LastEditors: Please set LastEditors
  * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  * @FilePath: /KC-MiddlePlatform/service/login.ts
@@ -29,12 +29,14 @@ export const getHospSubSystemList = async () => {
   });
 };
 
+export type UserDataType = {
+  name: string;
+  token: string;
+  userId: number;
+  youshuToken: string; //用于有数链接展示
+};
 export const login = async (data: LoginApi.LoginParams) => {
-  return request<{
-    name: string;
-    token: string;
-    userId: number;
-  }>('/master/centerSys/login', {
+  return request<UserDataType>('/master/centerSys/login', {
     method: 'POST',
     data: data,
   });

+ 4 - 9
src/service/role.ts

@@ -1,7 +1,7 @@
 /*
  * @Author: your name
  * @Date: 2022-01-18 14:56:29
- * @LastEditTime: 2022-01-19 17:27:32
+ * @LastEditTime: 2022-03-03 11:46:03
  * @LastEditors: Please set LastEditors
  * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  * @FilePath: /KC-MiddlePlatform/src/service/role.ts
@@ -22,9 +22,7 @@ export type RoleItemType = {
 };
 
 type GetAllRolesType = { list: RoleItemType[] } & TableResponseDataType;
-export const getAllRoles = async (
-  params: { roleName?: string } & TableRequestParamsType,
-) => {
+export const getAllRoles = async (params: { roleName?: string } & TableRequestParamsType) => {
   return request<GetAllRolesType>('/master/centerSys/role/list', {
     method: 'GET',
     params: { ...params },
@@ -32,11 +30,7 @@ export const getAllRoles = async (
 };
 
 //新增角色
-export const addRoles = async (data: {
-  roleName: string;
-  remark?: string;
-  hospId: number;
-}) => {
+export const addRoles = async (data: { roleName: string; remark?: string; hospId: number }) => {
   return request('/master/centerSys/role/addRole', {
     method: 'POST',
     data: { ...data },
@@ -56,6 +50,7 @@ export const editRoles = async (data: {
   remark: string;
   roleId: number;
   roleName: string;
+  youshuUserId: number;
 }) => {
   return request('/master/centerSys/role/editRole', {
     method: 'POST',

+ 19 - 7
src/service/user.ts

@@ -1,7 +1,7 @@
 /*
  * @Author: your name
  * @Date: 2022-01-12 09:55:49
- * @LastEditTime: 2022-02-10 08:59:51
+ * @LastEditTime: 2022-03-03 11:24:07
  * @LastEditors: Please set LastEditors
  * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  * @FilePath: /KC-MiddlePlatform/src/service/user.ts
@@ -75,12 +75,9 @@ export const delUsers = async (data: number[]) => {
 };
 
 export const getUsertemplate = async () => {
-  return request<string>(
-    '/master/centerSys/pfmfiledata/getUserTemplateFileUrl',
-    {
-      method: 'GET',
-    },
-  );
+  return request<string>('/master/centerSys/pfmfiledata/getUserTemplateFileUrl', {
+    method: 'GET',
+  });
 };
 
 //导入用户
@@ -98,3 +95,18 @@ export const resetUserPwd = async (data: { userId: number }) => {
     data: data,
   });
 };
+
+//获取有数用户列表
+export type GetYoushuUsersRepType = {
+  id: number;
+  account: string;
+  password: string;
+  isDefault: number;
+};
+
+export const getYoushuUsers = async (roleId: number) => {
+  return request<GetYoushuUsersRepType[]>('/master/centerSys/role/getYoushuUsersByRole', {
+    method: 'GET',
+    params: { roleId },
+  });
+};

+ 9 - 1
src/typings.d.ts

@@ -1,7 +1,7 @@
 /*
  * @Author: your name
  * @Date: 2021-11-19 16:31:19
- * @LastEditTime: 2022-01-14 15:25:24
+ * @LastEditTime: 2022-03-09 15:43:55
  * @LastEditors: Please set LastEditors
  * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  * @FilePath: /KC-MiddlePlatform/src/typings.d.ts
@@ -24,6 +24,14 @@ export type TableRequestParamsType = {
   [key: string]: any;
 };
 
+export type SpacicalPageParamsType = {
+  //特殊页面参数项集合,用于有数
+  contentType: number; //内容类型,0:一般,1.报告,2.大屏,2.填报
+  path: string;
+  reportId: number;
+  url: string;
+};
+
 export type TableResponseDataType = {
   //KCtable组件response data
   totalCount?: number | undefined;

+ 2 - 3
src/utils.ts

@@ -1,15 +1,14 @@
 /*
  * @Author: your name
  * @Date: 2022-01-13 17:09:05
- * @LastEditTime: 2022-01-21 10:41:05
+ * @LastEditTime: 2022-03-03 15:02:41
  * @LastEditors: Please set LastEditors
  * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  * @FilePath: /KC-MiddlePlatform/src/utils.js
  */
 
 export const randomString = (length: number) => {
-  const chars =
-    '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_=-';
+  const chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_=-';
   let result = '';
   for (let i = length; i > 0; --i) {
     result += chars[Math.floor(Math.random() * chars.length)];