Commit 4680276fc25bfcbe83005213caccf590ae51221c

Authored by 王强
1 parent 5694d3f4

fix(ehr): 优化 角色管理组 添加 查看管理组组织架构 并对接接口

package.json
... ... @@ -76,6 +76,7 @@
76 76 "react-beautiful-dnd": "^13.1.1",
77 77 "react-bmap": "^1.0.131",
78 78 "react-copy-to-clipboard": "^5.1.0",
  79 + "react-d3-tree": "3.6.2",
79 80 "react-document-title": "^2.0.3",
80 81 "react-dom": "^16.14.0",
81 82 "react-image-crop": "^8.6.12",
... ...
pnpm-lock.yaml
... ... @@ -128,6 +128,9 @@ dependencies:
128 128 react-copy-to-clipboard:
129 129 specifier: ^5.1.0
130 130 version: 5.1.0(react@16.14.0)
  131 + react-d3-tree:
  132 + specifier: 3.6.2
  133 + version: 3.6.2(react-dom@16.14.0)(react@16.14.0)
131 134 react-document-title:
132 135 specifier: ^2.0.3
133 136 version: 2.0.3(react@16.14.0)
... ... @@ -2386,6 +2389,22 @@ packages:
2386 2389 resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
2387 2390 dev: true
2388 2391  
  2392 + /@bkrem/react-transition-group@1.3.3(react-dom@16.14.0)(react@16.14.0):
  2393 + resolution: {integrity: sha512-nUZaumHu/MMolELv+MhEEQzQtKsnfpbKBHtam/NK53tGICwU19tuffEXW8BLhm9HhQfN1H3+C0bsJv8Z7vzwEA==}
  2394 + peerDependencies:
  2395 + react: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0
  2396 + react-dom: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0
  2397 + dependencies:
  2398 + chain-function: 1.0.1
  2399 + dom-helpers: 3.4.0
  2400 + loose-envify: 1.4.0
  2401 + prop-types: 15.8.1
  2402 + react: 16.14.0
  2403 + react-dom: 16.14.0(react@16.14.0)
  2404 + react-lifecycles-compat: 3.0.4
  2405 + warning: 3.0.0
  2406 + dev: false
  2407 +
2389 2408 /@bloomberg/record-tuple-polyfill@0.0.3:
2390 2409 resolution: {integrity: sha512-sBnCqW0nqofE47mxFnw+lvx6kzsQstwaQMVkh66qm/A6IlsnH7WsyGuVXTou8RF2wL4W7ybOoHPvP2WgIo6rhQ==}
2391 2410  
... ... @@ -3114,6 +3133,10 @@ packages:
3114 3133 '@types/node': 20.8.7
3115 3134 dev: true
3116 3135  
  3136 + /@types/d3-hierarchy@1.1.11:
  3137 + resolution: {integrity: sha512-lnQiU7jV+Gyk9oQYk0GGYccuexmQPTp08E0+4BidgFdiJivjEvf+esPSdZqCZ2C7UwTWejWpqetVaU8A+eX3FA==}
  3138 + dev: false
  3139 +
3117 3140 /@types/eslint-scope@3.7.7:
3118 3141 resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==}
3119 3142 dependencies:
... ... @@ -5936,6 +5959,10 @@ packages:
5936 5959 lazy-cache: 1.0.4
5937 5960 dev: false
5938 5961  
  5962 + /chain-function@1.0.1:
  5963 + resolution: {integrity: sha512-SxltgMwL9uCko5/ZCLiyG2B7R9fY4pDZUw7hJ4MhirdjBLosoDqkWABi3XMucddHdLiFJMb7PD2MZifZriuMTg==}
  5964 + dev: false
  5965 +
5939 5966 /chalk@1.1.3:
5940 5967 resolution: {integrity: sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==}
5941 5968 engines: {node: '>=0.10.0'}
... ... @@ -6187,7 +6214,6 @@ packages:
6187 6214 /clone@2.1.2:
6188 6215 resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==}
6189 6216 engines: {node: '>=0.8'}
6190   - dev: true
6191 6217  
6192 6218 /cloneable-readable@1.1.3:
6193 6219 resolution: {integrity: sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==}
... ... @@ -6697,6 +6723,14 @@ packages:
6697 6723 resolution: {integrity: sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA==}
6698 6724 dev: false
6699 6725  
  6726 + /d3-drag@3.0.0:
  6727 + resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==}
  6728 + engines: {node: '>=12'}
  6729 + dependencies:
  6730 + d3-dispatch: 1.0.6
  6731 + d3-selection: 3.0.0
  6732 + dev: false
  6733 +
6700 6734 /d3-dsv@1.0.10:
6701 6735 resolution: {integrity: sha512-vqklfpxmtO2ZER3fq/B33R/BIz3A1PV0FaZRuFM8w6jLo7sUX1BZDh73fPlr0s327rzq4H6EN1q9U+eCBCSN8g==}
6702 6736 hasBin: true
... ... @@ -6769,6 +6803,11 @@ packages:
6769 6803 resolution: {integrity: sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg==}
6770 6804 dev: false
6771 6805  
  6806 + /d3-selection@3.0.0:
  6807 + resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==}
  6808 + engines: {node: '>=12'}
  6809 + dev: false
  6810 +
6772 6811 /d3-shape@1.3.7:
6773 6812 resolution: {integrity: sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==}
6774 6813 dependencies:
... ... @@ -6790,10 +6829,35 @@ packages:
6790 6829 d3-timer: 1.0.10
6791 6830 dev: false
6792 6831  
  6832 + /d3-transition@3.0.1(d3-selection@3.0.0):
  6833 + resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==}
  6834 + engines: {node: '>=12'}
  6835 + peerDependencies:
  6836 + d3-selection: 2 - 3
  6837 + dependencies:
  6838 + d3-color: 1.4.1
  6839 + d3-dispatch: 1.0.6
  6840 + d3-ease: 1.0.7
  6841 + d3-interpolate: 1.4.0
  6842 + d3-selection: 3.0.0
  6843 + d3-timer: 1.0.10
  6844 + dev: false
  6845 +
6793 6846 /d3-voronoi@1.1.4:
6794 6847 resolution: {integrity: sha512-dArJ32hchFsrQ8uMiTBLq256MpnZjeuBtdHpaDlYuQyjU0CVzCJl/BVW+SkszaAeH95D/8gxqAhgx0ouAWAfRg==}
6795 6848 dev: false
6796 6849  
  6850 + /d3-zoom@3.0.0:
  6851 + resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==}
  6852 + engines: {node: '>=12'}
  6853 + dependencies:
  6854 + d3-dispatch: 1.0.6
  6855 + d3-drag: 3.0.0
  6856 + d3-interpolate: 1.4.0
  6857 + d3-selection: 3.0.0
  6858 + d3-transition: 3.0.1(d3-selection@3.0.0)
  6859 + dev: false
  6860 +
6797 6861 /dagre@0.8.5:
6798 6862 resolution: {integrity: sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==}
6799 6863 dependencies:
... ... @@ -6821,7 +6885,7 @@ packages:
6821 6885 resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==}
6822 6886 engines: {node: '>=0.11'}
6823 6887 dependencies:
6824   - '@babel/runtime': 7.23.2
  6888 + '@babel/runtime': 7.23.8
6825 6889  
6826 6890 /date-format@0.0.0:
6827 6891 resolution: {integrity: sha512-kAmAdtsjW5nQ02FERwI1bP4xe6HQBPwy5kpAF4CRSLOMUs/vgMIEEwpy6JqUs7NitTyhZiImxwAjgPpnteycHg==}
... ... @@ -6991,6 +7055,11 @@ packages:
6991 7055 engines: {node: '>= 0.8'}
6992 7056 dev: true
6993 7057  
  7058 + /dequal@2.0.3:
  7059 + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
  7060 + engines: {node: '>=6'}
  7061 + dev: false
  7062 +
6994 7063 /des.js@1.1.0:
6995 7064 resolution: {integrity: sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==}
6996 7065 dependencies:
... ... @@ -7087,6 +7156,12 @@ packages:
7087 7156 /dom-align@1.12.4:
7088 7157 resolution: {integrity: sha512-R8LUSEay/68zE5c8/3BDxiTEvgb4xZTF0RKmAHfiEVN3klfIpXfi2/QCoiWPccVQ0J/ZGdz9OjzL4uJEP/MRAw==}
7089 7158  
  7159 + /dom-helpers@3.4.0:
  7160 + resolution: {integrity: sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==}
  7161 + dependencies:
  7162 + '@babel/runtime': 7.23.8
  7163 + dev: false
  7164 +
7090 7165 /dom-scroll-into-view@1.2.1:
7091 7166 resolution: {integrity: sha512-LwNVg3GJOprWDO+QhLL1Z9MMgWe/KAFLxVWKzjRTxNSPn8/LLDIfmuG71YHznXCqaqTjvHJDYO1MEAgX6XCNbQ==}
7092 7167 dev: false
... ... @@ -7224,7 +7299,7 @@ packages:
7224 7299 peerDependencies:
7225 7300 redux: 4.x
7226 7301 dependencies:
7227   - '@babel/runtime': 7.23.2
  7302 + '@babel/runtime': 7.23.8
7228 7303 flatten: 1.0.3
7229 7304 global: 4.4.0
7230 7305 invariant: 2.2.4
... ... @@ -9144,7 +9219,7 @@ packages:
9144 9219 /history-with-query@4.10.4:
9145 9220 resolution: {integrity: sha512-JnskQK8X+PbRFHSdDAExhoJyhLnlLZL+UuHQuQhys+Se9/ukRDRBWU4JVTjsiIfbv1fcEmR3oqKW56OYmk5M5w==}
9146 9221 dependencies:
9147   - '@babel/runtime': 7.23.2
  9222 + '@babel/runtime': 7.23.8
9148 9223 loose-envify: 1.4.0
9149 9224 query-string: 6.14.1
9150 9225 resolve-pathname: 3.0.0
... ... @@ -9155,7 +9230,7 @@ packages:
9155 9230 /history@4.10.1:
9156 9231 resolution: {integrity: sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==}
9157 9232 dependencies:
9158   - '@babel/runtime': 7.23.2
  9233 + '@babel/runtime': 7.23.8
9159 9234 loose-envify: 1.4.0
9160 9235 resolve-pathname: 3.0.0
9161 9236 tiny-invariant: 1.3.1
... ... @@ -11403,7 +11478,7 @@ packages:
11403 11478 prop-types: ^15.0.0
11404 11479 react: ^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
11405 11480 dependencies:
11406   - '@babel/runtime': 7.23.2
  11481 + '@babel/runtime': 7.23.8
11407 11482 prop-types: 15.8.1
11408 11483 react: 16.14.0
11409 11484 tiny-warning: 1.0.3
... ... @@ -13207,7 +13282,7 @@ packages:
13207 13282 react: '>=16.9.0'
13208 13283 react-dom: '>=16.9.0'
13209 13284 dependencies:
13210   - '@babel/runtime': 7.23.2
  13285 + '@babel/runtime': 7.23.8
13211 13286 classnames: 2.3.2
13212 13287 dom-align: 1.12.4
13213 13288 rc-util: 5.38.0(react-dom@16.14.0)(react@16.14.0)
... ... @@ -13515,7 +13590,7 @@ packages:
13515 13590 react: '>=16.9.0'
13516 13591 react-dom: '>=16.9.0'
13517 13592 dependencies:
13518   - '@babel/runtime': 7.23.2
  13593 + '@babel/runtime': 7.23.8
13519 13594 classnames: 2.3.2
13520 13595 rc-resize-observer: 1.4.0(react-dom@16.14.0)(react@16.14.0)
13521 13596 rc-util: 5.38.0(react-dom@16.14.0)(react@16.14.0)
... ... @@ -13860,7 +13935,7 @@ packages:
13860 13935 react: '*'
13861 13936 react-dom: '*'
13862 13937 dependencies:
13863   - '@babel/runtime': 7.23.2
  13938 + '@babel/runtime': 7.23.8
13864 13939 classnames: 2.3.2
13865 13940 rc-resize-observer: 1.4.0(react-dom@16.14.0)(react@16.14.0)
13866 13941 rc-util: 5.38.0(react-dom@16.14.0)(react@16.14.0)
... ... @@ -13908,6 +13983,25 @@ packages:
13908 13983 react: 16.14.0
13909 13984 dev: false
13910 13985  
  13986 + /react-d3-tree@3.6.2(react-dom@16.14.0)(react@16.14.0):
  13987 + resolution: {integrity: sha512-1ExQlmEnv5iOw9XfZ3EcESDjzGXVKPAmyDJTJbvVfiwkplZtP7CcNEY0tKZf4XSW0FzYJf4aFXprGJen+95yuw==}
  13988 + peerDependencies:
  13989 + react: 16.x || 17.x || 18.x
  13990 + react-dom: 16.x || 17.x || 18.x
  13991 + dependencies:
  13992 + '@bkrem/react-transition-group': 1.3.3(react-dom@16.14.0)(react@16.14.0)
  13993 + '@types/d3-hierarchy': 1.1.11
  13994 + clone: 2.1.2
  13995 + d3-hierarchy: 1.1.9
  13996 + d3-selection: 3.0.0
  13997 + d3-shape: 1.3.7
  13998 + d3-zoom: 3.0.0
  13999 + dequal: 2.0.3
  14000 + react: 16.14.0
  14001 + react-dom: 16.14.0(react@16.14.0)
  14002 + uuid: 8.3.2
  14003 + dev: false
  14004 +
13911 14005 /react-dev-utils@9.0.1(eslint@8.52.0)(typescript@5.3.3)(webpack@5.89.0):
13912 14006 resolution: {integrity: sha512-pnaeMo/Pxel8aZpxk1WwxT3uXxM3tEwYvsjCYn5R7gNxjhN1auowdcLDzFB8kr7rafAj2rxmvfic/fbac5CzwQ==}
13913 14007 engines: {node: '>=8.10'}
... ... @@ -14073,7 +14167,7 @@ packages:
14073 14167 react: '>=15'
14074 14168 react-router: '>=5'
14075 14169 dependencies:
14076   - '@babel/runtime': 7.23.2
  14170 + '@babel/runtime': 7.23.8
14077 14171 react: 16.14.0
14078 14172 react-router: 5.2.0(react@16.14.0)
14079 14173  
... ... @@ -14083,7 +14177,7 @@ packages:
14083 14177 react: '>=15'
14084 14178 react-router: '>=5'
14085 14179 dependencies:
14086   - '@babel/runtime': 7.23.2
  14180 + '@babel/runtime': 7.23.8
14087 14181 react: 16.14.0
14088 14182 react-router: 5.3.4(react@16.14.0)
14089 14183  
... ... @@ -14092,7 +14186,7 @@ packages:
14092 14186 peerDependencies:
14093 14187 react: '>=15'
14094 14188 dependencies:
14095   - '@babel/runtime': 7.23.2
  14189 + '@babel/runtime': 7.23.8
14096 14190 history: 4.10.1
14097 14191 loose-envify: 1.4.0
14098 14192 prop-types: 15.8.1
... ... @@ -14106,7 +14200,7 @@ packages:
14106 14200 peerDependencies:
14107 14201 react: '>=15'
14108 14202 dependencies:
14109   - '@babel/runtime': 7.23.2
  14203 + '@babel/runtime': 7.23.8
14110 14204 history: 4.10.1
14111 14205 loose-envify: 1.4.0
14112 14206 prop-types: 15.8.1
... ... @@ -14121,7 +14215,7 @@ packages:
14121 14215 peerDependencies:
14122 14216 react: '>=15'
14123 14217 dependencies:
14124   - '@babel/runtime': 7.23.2
  14218 + '@babel/runtime': 7.23.8
14125 14219 history: 4.10.1
14126 14220 hoist-non-react-statics: 3.3.2
14127 14221 loose-envify: 1.4.0
... ... @@ -14138,7 +14232,7 @@ packages:
14138 14232 peerDependencies:
14139 14233 react: '>=15'
14140 14234 dependencies:
14141   - '@babel/runtime': 7.23.2
  14235 + '@babel/runtime': 7.23.8
14142 14236 history: 4.10.1
14143 14237 hoist-non-react-statics: 3.3.2
14144 14238 loose-envify: 1.4.0
... ... @@ -14405,7 +14499,7 @@ packages:
14405 14499 /regenerator-transform@0.15.2:
14406 14500 resolution: {integrity: sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==}
14407 14501 dependencies:
14408   - '@babel/runtime': 7.23.2
  14502 + '@babel/runtime': 7.23.8
14409 14503 dev: true
14410 14504  
14411 14505 /regex-not@1.0.2:
... ... @@ -17085,8 +17179,6 @@ packages:
17085 17179 resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
17086 17180 hasBin: true
17087 17181 requiresBuild: true
17088   - dev: true
17089   - optional: true
17090 17182  
17091 17183 /v8-compile-cache@2.3.0:
17092 17184 resolution: {integrity: sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==}
... ...
src/pages/ehr/RoleManagementGroup/api.ts
... ... @@ -4,18 +4,16 @@
4 4 * @LastEditors: wangqiang@feewee.cn
5 5 * @LastEditTime: 2023-05-09 09:49:07
6 6 */
7   -import request from "@/utils/request";
8   -import { EHR_HOST } from "@/utils/host";
9   -import { http } from "@/typing/http";
  7 +import request from '@/utils/request';
  8 +import { EHR_HOST } from '@/utils/host';
  9 +import { http } from '@/typing/http';
10 10  
11 11 /**
12 12 * @description: 获取角色管理组列表
13 13 * @param {RoleManagementGrooup.QueryParams} params
14 14 * @return {http.PromisePageResp<RoleManagementGrooup.GroupItem>}
15 15 */
16   -export function getListApi(
17   - params: RoleManagementGrooup.QueryParams
18   -): http.PromisePageResp<RoleManagementGrooup.GroupItem> {
  16 +export function getListApi(params: RoleManagementGrooup.QueryParams): http.PromisePageResp<RoleManagementGrooup.GroupItem> {
19 17 return request.get(`${EHR_HOST}/roleStep/list`, { params });
20 18 }
21 19  
... ... @@ -24,9 +22,7 @@ export function getListApi(
24 22 * @param {RoleManagementGrooup.Detail} params
25 23 * @return {http.PromiseResp<string>}
26 24 */
27   -export function saveGroupApi(
28   - params: RoleManagementGrooup.Detail
29   -): http.PromiseResp<string> {
  25 +export function saveGroupApi(params: RoleManagementGrooup.Detail): http.PromiseResp<string> {
30 26 return request.post(`${EHR_HOST}/roleStep/save`, params);
31 27 }
32 28  
... ... @@ -35,9 +31,7 @@ export function saveGroupApi(
35 31 * @param {number} id
36 32 * @return {http.PromiseResp<RoleManagementGrooup.GroupRoleStepItem[]>}
37 33 */
38   -export function getGroupDetailApi(
39   - id: number
40   -): http.PromiseResp<RoleManagementGrooup.GroupRoleStepItem[]> {
  34 +export function getGroupDetailApi(id: number): http.PromiseResp<RoleManagementGrooup.GroupRoleStepItem[]> {
41 35 return request.get(`${EHR_HOST}/roleStep/step/info`, { params: { id } });
42 36 }
43 37  
... ... @@ -49,3 +43,12 @@ export function getGroupDetailApi(
49 43 export function deleteGroupApi(id: number): http.PromiseResp<string> {
50 44 return request.get(`${EHR_HOST}/roleStep/remove`, { params: { id } });
51 45 }
  46 +
  47 +/**
  48 + * @description: 获取角色组对应组织架构
  49 + * @param {number} stepId
  50 + * @return {http.PromiseResp<RoleManagementGrooup.RoleStaffTreeListVO>}
  51 + */
  52 +export function getRoleStaffTreeApi(stepId: number): http.PromiseResp<RoleManagementGrooup.RoleStaffTreeListVO> {
  53 + return request.get(`${EHR_HOST}/hr/common/role/step/manage/tree`, { params: { stepId } });
  54 +}
... ...
src/pages/ehr/RoleManagementGroup/components/List.tsx
... ... @@ -2,28 +2,28 @@
2 2 * @Author: wangqiang@feewee.cn
3 3 * @Date: 2022-06-29 10:35:41
4 4 * @LastEditors: wangqiang@feewee.cn
5   - * @LastEditTime: 2022-07-01 15:20:41
  5 + * @LastEditTime: 2024-04-19 17:15:41
6 6 */
7   -import { Divider, message, Popconfirm, Table } from "antd";
8   -import moment from "moment";
9   -import React from "react";
10   -import { useStore } from "../index";
11   -import { deleteGroupApi } from "../api";
  7 +import { Divider, message, Popconfirm, Table } from 'antd';
  8 +import moment from 'moment';
  9 +import React from 'react';
  10 +import { useStore } from '../index';
  11 +import { deleteGroupApi } from '../api';
12 12 // import SubmitModal from "@/pages/ehr/Insurance/components/SubmitModal";
13 13  
14 14 export default function RoleManagementGroupList() {
15   - const { pagination, getDetail, current, setCurrent } = useStore();
  15 + const { elements, pagination, getDetail, setType, setCurrent } = useStore();
16 16 // const [deleteVisible, setDeleteVisible] = useState(false);
17 17  
18 18 const deleteGroup = (id: number) => {
19   - const hide = message.loading("删除中...", 0);
  19 + const hide = message.loading('删除中...', 0);
20 20 deleteGroupApi(id)
21 21 .then((res) => {
22 22 message.success(res.result);
23 23 pagination.setLoading(true);
24 24 })
25 25 .catch((err) => {
26   - message.error(err.message || "删除失败");
  26 + message.error(err.message || '删除失败');
27 27 })
28 28 .finally(() => {
29 29 setCurrent(undefined);
... ... @@ -32,59 +32,40 @@ export default function RoleManagementGroupList() {
32 32 });
33 33 };
34 34  
  35 + function getRoleStaffTree(item: RoleManagementGrooup.GroupItem) {
  36 + setCurrent(item);
  37 + setType('tree');
  38 + }
  39 +
35 40 return (
36   - <>
37   - <Table
38   - dataSource={pagination.list}
39   - rowKey="id"
40   - loading={pagination.loading}
41   - pagination={pagination.paginationConfig}
42   - >
43   - <Table.Column title="角色管理组名" align="left" dataIndex="name" />
44   - <Table.Column
45   - title="创建时间"
46   - align="left"
47   - render={(record: RoleManagementGrooup.GroupItem) => (record.createTime
48   - ? moment(record.createTime).format("YYYY-MM-DD HH:mm")
49   - : "-")}
50   - />
51   - <Table.Column
52   - title="操作"
53   - align="left"
54   - render={(record: RoleManagementGrooup.GroupItem) => (
55   - <>
56   - <a onClick={() => getDetail(record, false)}>查看</a>
57   - <Divider type="vertical" />
58   - <a onClick={() => getDetail(record, true)}>编辑</a>
59   - <Divider type="vertical" />
60   - {/* <a
61   - style={{ color: "red" }}
62   - onClick={() => {
63   - setCurrent(record);
64   - setDeleteVisible(true);
65   - }}
66   - >
67   - 删除
68   - </a> */}
69   - <Popconfirm
70   - title={`确定删除【${record.name}】角色管理组?`}
71   - onConfirm={() => deleteGroup(record.id || -1)}
72   - >
73   - <a style={{ color: "red" }}>删除</a>
74   - </Popconfirm>
75   - </>
76   - )}
77   - />
78   - </Table>
79   - {/* <SubmitModal
80   - closable={false}
81   - limit
82   - style={{ minWidth: 400 }}
83   - title={`确定删除【${current?.name}】角色管理组?`}
84   - visible={deleteVisible}
85   - onCancel={() => setDeleteVisible(false)}
86   - onOk={deleteGroup}
87   - /> */}
88   - </>
  41 + <Table dataSource={pagination.list} rowKey="id" loading={pagination.loading} pagination={pagination.paginationConfig}>
  42 + <Table.Column title="角色管理组名" align="left" dataIndex="name" />
  43 + <Table.Column
  44 + title="创建时间"
  45 + align="left"
  46 + render={(record: RoleManagementGrooup.GroupItem) => (record.createTime ? moment(record.createTime).format('YYYY-MM-DD HH:mm') : '-')}
  47 + />
  48 + <Table.Column
  49 + title="操作"
  50 + align="left"
  51 + render={(record: RoleManagementGrooup.GroupItem) => (
  52 + <>
  53 + {elements.includes('role:manage:edit') ? (
  54 + <>
  55 + <a onClick={() => getDetail(record, false)}>查看</a>
  56 + <Divider type="vertical" />
  57 + <a onClick={() => getDetail(record, true)}>编辑</a>
  58 + <Divider type="vertical" />
  59 + <Popconfirm title={`确定删除【${record.name}】角色管理组?`} onConfirm={() => deleteGroup(record.id || -1)}>
  60 + <a style={{ color: 'red' }}>删除</a>
  61 + </Popconfirm>
  62 + <Divider type="vertical" />
  63 + </>
  64 + ) : null}
  65 + <a onClick={() => getRoleStaffTree(record)}>查看组织架构</a>
  66 + </>
  67 + )}
  68 + />
  69 + </Table>
89 70 );
90 71 }
... ...
src/pages/ehr/RoleManagementGroup/components/ListIndex.tsx 0 → 100644
  1 +import React from 'react';
  2 +import List from './List';
  3 +import Modal from './Modal';
  4 +import FeeweeFilterOption from '@/pages/notice/components/FeeweeFilterOption';
  5 +import { useStore } from '../index';
  6 +import { Button, Input, Row } from 'antd';
  7 +import { PlusOutlined } from '@ant-design/icons';
  8 +
  9 +export default function ListIndex() {
  10 + const { elements, pagination, setVisible } = useStore();
  11 +
  12 + return (
  13 + <>
  14 + <Row justify="space-between">
  15 + <FeeweeFilterOption title="角色管理组名">
  16 + <Input.Search
  17 + style={{ minWidth: 260, marginBottom: 10, marginRight: 10 }}
  18 + allowClear
  19 + placeholder="请输入角色管理组名查询"
  20 + value={pagination.innerParams.name}
  21 + onChange={(e) => pagination.setParams({ name: e.target.value })}
  22 + onSearch={() => pagination.setParams({ current: 1 }, true)}
  23 + />
  24 + </FeeweeFilterOption>
  25 +
  26 + {elements.includes('role:manage:edit') ? (
  27 + <Button
  28 + // @ts-ignore
  29 + icon={<PlusOutlined />}
  30 + type="primary"
  31 + onClick={() => {
  32 + setVisible(true);
  33 + }}
  34 + >
  35 + 新增
  36 + </Button>
  37 + ) : null}
  38 + </Row>
  39 + <List />
  40 + <Modal />
  41 + </>
  42 + );
  43 +}
... ...
src/pages/ehr/RoleManagementGroup/components/RoleStaffTree.tsx 0 → 100644
  1 +import React, { useEffect, useRef, useState } from 'react';
  2 +import { useStore } from '../index';
  3 +import Tree, { RawNodeDatum, Point } from 'react-d3-tree';
  4 +import { getRoleStaffTreeApi } from '../api';
  5 +import { Empty, Spin, Modal, Button, Row, Divider } from 'antd';
  6 +import useInitial from '@/hooks/useInitail';
  7 +import DetailItem from '@/pages/ehr/Authentication/Settings/components/DetailItem';
  8 +
  9 +export default function RoleStaffTree() {
  10 + const { current, setCurrent } = useStore();
  11 + const treeInitital = useInitial(getRoleStaffTreeApi, {}, current?.id ?? -1);
  12 + const treeContainer = useRef<HTMLDivElement | null>(null);
  13 + const [translate, setTranslate] = useState<Point>({ x: 200, y: 50 });
  14 + const [dimensions, setDataimensions] = useState<{ width: number; height: number }>();
  15 +
  16 + const [modalInfo, setModalInfo] = useState<{ open: boolean; data?: RoleManagementGrooup.RoleStaffTreeVO }>({ open: false });
  17 +
  18 + useEffect(() => {
  19 + if (treeContainer.current) {
  20 + const rect = treeContainer.current.getBoundingClientRect();
  21 + setTranslate({ x: rect.width / 2, y: 200 });
  22 + setDataimensions({ width: rect.width, height: rect.height });
  23 + }
  24 + }, [treeContainer.current]);
  25 +
  26 + return (
  27 + <div id="treeWrapper" style={{ height: 'calc(100vh - 288px)' }} ref={treeContainer}>
  28 + {treeInitital.loading ? (
  29 + <div style={{ width: '100%' }}>
  30 + <Spin spinning style={{ width: '100%', margin: '40px auto' }} />
  31 + </div>
  32 + ) : treeInitital.errMsg ? (
  33 + <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description={treeInitital.errMsg} />
  34 + ) : treeInitital.data.treeList?.length ? (
  35 + <Tree
  36 + data={treeInitital.data.treeList}
  37 + orientation="vertical"
  38 + separation={{ nonSiblings: 2, siblings: 2 }}
  39 + pathFunc="step"
  40 + onLinkClick={(...props) => console.log('onLinkClick', props)}
  41 + onNodeClick={(...props) => {
  42 + console.log('onNodeClick', props);
  43 + }}
  44 + scaleExtent={{ min: 0, max: 20 }}
  45 + enableLegacyTransitions
  46 + translate={translate}
  47 + initialDepth={treeInitital.data.levelCnt ?? 2}
  48 + dimensions={dimensions}
  49 + centeringTransitionDuration={500}
  50 + renderCustomNodeElement={({ nodeDatum, toggleNode }) => {
  51 + const data: RoleManagementGrooup.RoleStaffTreeVO = nodeDatum;
  52 + const level = data.level ?? '级别';
  53 + const width = 15 * level.length;
  54 + const x = -(width / 2);
  55 + const textX = width / 2 + 10;
  56 + return (
  57 + <g>
  58 + <rect
  59 + id="tree-item-toggle"
  60 + x={x}
  61 + width={width}
  62 + height="30"
  63 + fill={data.children?.length ? '#4189FD' : 'white'}
  64 + stroke={data.children?.length ? '#4189FD' : 'black'}
  65 + strokeWidth="0.5"
  66 + onClick={toggleNode}
  67 + />
  68 + <text
  69 + id="tree-item-toggle"
  70 + x="0"
  71 + y="15"
  72 + fontSize="12"
  73 + textAnchor="middle"
  74 + alignmentBaseline="middle"
  75 + strokeWidth="0.5"
  76 + fill={data.children?.length ? 'white' : 'black'}
  77 + stroke={data.children?.length ? 'white' : 'black'}
  78 + onClick={toggleNode}
  79 + >
  80 + {level}
  81 + </text>
  82 + <text fill="black" strokeWidth="1" fontSize={15} x={textX} y={15}>
  83 + {nodeDatum.name}&nbsp;&nbsp;
  84 + <tspan
  85 + textDecoration="underline"
  86 + fontSize={12}
  87 + strokeWidth={0.5}
  88 + fill="#FF921C"
  89 + stroke="#FF921C"
  90 + onClick={() => setModalInfo({ open: true, data })}
  91 + >
  92 + 查看详情
  93 + </tspan>
  94 + </text>
  95 + {Object.entries(nodeDatum.attributes ?? {}).map(([name, value], idx) => (
  96 + <text key={name} fill="#666" stroke="#666" strokeWidth="0.5" fontSize={12} x={textX} y={15 * (idx + 2)}>
  97 + {name}:{value}
  98 + </text>
  99 + ))}
  100 + </g>
  101 + );
  102 + }}
  103 + />
  104 + ) : null}
  105 + <Modal
  106 + title="人员详情"
  107 + open={modalInfo.open}
  108 + footer={<Button onClick={() => setModalInfo({ open: false })}>关闭</Button>}
  109 + onCancel={() => setModalInfo({ open: false })}
  110 + >
  111 + <Row style={{ gap: '0 30px' }}>
  112 + <DetailItem title="级别" desp={modalInfo.data?.level ?? '-'} />
  113 + <DetailItem title="员工" desp={modalInfo.data?.name ?? '-'} />
  114 + {Object.entries(modalInfo.data?.attributes ?? {}).map(([name, value]) => (
  115 + <DetailItem key={name} title={name} desp={value ?? '-'} />
  116 + ))}
  117 + </Row>
  118 + <Divider orientation="left">角色授权门店({modalInfo.data?.roleShopList?.length ?? '-'} 个门店 )</Divider>
  119 + <Row style={{ flexDirection: 'column', flexWrap: 'nowrap', alignItems: 'start', maxHeight: '50vh', overflowY: 'auto' }}>
  120 + {modalInfo.data?.roleShopList?.map((shop, idx) => (
  121 + <p key={shop} style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
  122 + <div style={{ width: 6, height: 6, borderRadius: '50%', backgroundColor: '#4189FD' }} />
  123 + <span style={{ flex: 1 }}>
  124 + {idx + 1}.&nbsp;{shop}
  125 + </span>
  126 + </p>
  127 + ))}
  128 + </Row>
  129 + </Modal>
  130 + </div>
  131 + );
  132 +}
... ...
src/pages/ehr/RoleManagementGroup/index.tsx
... ... @@ -2,51 +2,54 @@
2 2 * @Author: wangqiang@feewee.cn
3 3 * @Date: 2022-06-29 10:09:59
4 4 * @LastEditors: wangqiang@feewee.cn
5   - * @LastEditTime: 2023-09-02 16:12:33
  5 + * @LastEditTime: 2024-04-19 17:07:55
6 6 */
7   -import React from 'react';
  7 +import React, { useEffect, useMemo } from 'react';
8 8 import { createStore } from '@/hooks/moz';
9 9 import zhCN from 'antd/lib/locale-provider/zh_CN';
10 10 import { PageHeaderWrapper } from '@ant-design/pro-layout';
11   -import { Button, Card, ConfigProvider, Input, Row } from 'antd';
12   -import { PlusOutlined } from '@ant-design/icons';
  11 +import { Button, Card, ConfigProvider } from 'antd';
  12 +import { LeftCircleOutlined } from '@ant-design/icons';
13 13 import store from './store';
14   -import List from './components/List';
15   -import Modal from './components/Modal';
16   -import FeeweeFilterOption from '@/pages/notice/components/FeeweeFilterOption';
  14 +import List from './components/ListIndex';
  15 +import Tree from './components/RoleStaffTree';
17 16  
18 17 export const { Provider, useStore } = createStore(store);
19 18  
20 19 function RoleManagementGroup() {
21   - const { pagination, setVisible } = useStore();
  20 + const { type, current, setType, setCurrent } = useStore();
  21 +
  22 + const DOM = useMemo(() => {
  23 + if (type === 'list') {
  24 + return List;
  25 + } else {
  26 + return Tree;
  27 + }
  28 + }, [type]);
22 29  
23 30 return (
24   - <PageHeaderWrapper title="角色管理组">
  31 + <PageHeaderWrapper
  32 + title="角色管理组"
  33 + content={type === 'tree' ? current?.name ?? '-' : null}
  34 + extraContent={
  35 + type === 'tree' ? (
  36 + <Button
  37 + // @ts-ignore
  38 + icon={<LeftCircleOutlined />}
  39 + type="link"
  40 + onClick={() => {
  41 + setCurrent(undefined);
  42 + setType('list');
  43 + }}
  44 + >
  45 + 返回
  46 + </Button>
  47 + ) : null
  48 + }
  49 + >
25 50 <ConfigProvider locale={zhCN}>
26 51 <Card bordered={false}>
27   - <Row justify="space-between">
28   - <FeeweeFilterOption title="角色管理组名">
29   - <Input.Search
30   - style={{ minWidth: 260, marginBottom: 10, marginRight: 10 }}
31   - allowClear
32   - placeholder="请输入角色管理组名查询"
33   - value={pagination.innerParams.name}
34   - onChange={(e) => pagination.setParams({ name: e.target.value })}
35   - onSearch={() => pagination.setParams({ current: 1 }, true)}
36   - />
37   - </FeeweeFilterOption>
38   - <Button
39   - icon={<PlusOutlined />}
40   - type="primary"
41   - onClick={() => {
42   - setVisible(true);
43   - }}
44   - >
45   - 新增
46   - </Button>
47   - </Row>
48   - <List />
49   - <Modal />
  52 + <DOM />
50 53 </Card>
51 54 </ConfigProvider>
52 55 </PageHeaderWrapper>
... ...
src/pages/ehr/RoleManagementGroup/interface.d.ts
... ... @@ -27,4 +27,18 @@ declare namespace RoleManagementGrooup {
27 27 interface Role extends CommonApi.RoleCodeVO {
28 28 index?: number; // 所在级别,其他级别不能编辑
29 29 }
  30 +
  31 + interface RoleStaffTreeListVO {
  32 + treeList?: RoleStaffTreeVO[];
  33 + levelCnt?: number; //
  34 + }
  35 +
  36 + interface RoleStaffTreeVO {
  37 + staffId?: number; //
  38 + name: string; // 员工名
  39 + level?: string; // 级别
  40 + attributes?: Record<string, string | number | boolean>;
  41 + roleShopList?: string[]; // 授权门店
  42 + children?: RoleStaffTreeVO[];
  43 + }
30 44 }
... ...
src/pages/ehr/RoleManagementGroup/store.ts
... ... @@ -4,25 +4,25 @@
4 4 * @LastEditors: wangqiang@feewee.cn
5 5 * @LastEditTime: 2022-07-04 10:32:00
6 6 */
7   -import usePagination from "@/hooks/usePagination";
8   -import useInitial from "@/hooks/useInitail";
9   -import { getAllRoleCodeApi } from "@/common/api";
10   -import { useState } from "react";
11   -import { getListApi, getGroupDetailApi } from "./api";
12   -import { message } from "antd";
  7 +import usePagination from '@/hooks/usePagination';
  8 +import useInitial from '@/hooks/useInitail';
  9 +import { getAllRoleCodeApi } from '@/common/api';
  10 +import { useState } from 'react';
  11 +import { getListApi, getGroupDetailApi } from './api';
  12 +import { message } from 'antd';
  13 +import useMenuElement from '@/hooks/useMenuElement';
13 14  
14 15 export default function useStore() {
  16 + const { elements } = useMenuElement();
15 17 const pagination = usePagination(getListApi);
16   - const roleInitial = useInitial<
17   - RoleManagementGrooup.Role[],
18   - CommonApi.RoleParams
19   - >(getAllRoleCodeApi, [], { roleType: 2 }); // 默认查询所有管理角色
  18 + const roleInitial = useInitial<RoleManagementGrooup.Role[], CommonApi.RoleParams>(getAllRoleCodeApi, [], { roleType: 2 }); // 默认查询所有管理角色
20 19 const [visible, setVisible] = useState(false);
21 20 const [disabled, setDisabled] = useState(false);
22 21 const [current, setCurrent] = useState<RoleManagementGrooup.Detail>();
  22 + const [type, setType] = useState<'list' | 'tree'>('list');
23 23  
24 24 function getDetail(item: RoleManagementGrooup.GroupItem, edit: boolean) {
25   - const hide = message.loading("查询中...", 0);
  25 + const hide = message.loading('查询中...', 0);
26 26 getGroupDetailApi(item.id || -1)
27 27 .then((res) => {
28 28 setCurrent({
... ... @@ -33,7 +33,7 @@ export default function useStore() {
33 33 setVisible(true);
34 34 })
35 35 .catch((err) => {
36   - message.error(err.message || "查询失败");
  36 + message.error(err.message || '查询失败');
37 37 })
38 38 .finally(() => {
39 39 hide();
... ... @@ -45,6 +45,7 @@ export default function useStore() {
45 45 }
46 46  
47 47 return {
  48 + elements,
48 49 pagination,
49 50 roleInitial,
50 51 visible,
... ... @@ -53,21 +54,20 @@ export default function useStore() {
53 54 setDisabled,
54 55 current,
55 56 setCurrent,
  57 + type,
  58 + setType,
56 59 getDetail,
57 60 formatRoleList,
58 61 };
59 62 }
60 63  
61   -function handleRoleList(
62   - roleList: RoleManagementGrooup.Role[],
63   - codes?: (string | string[])[]
64   -): RoleManagementGrooup.Role[] {
  64 +function handleRoleList(roleList: RoleManagementGrooup.Role[], codes?: (string | string[])[]): RoleManagementGrooup.Role[] {
65 65 if (codes) {
66 66 roleList = roleList.map((role) => {
67   - let index = codes.findIndex((code) => {
  67 + const index = codes.findIndex((code) => {
68 68 if (Array.isArray(code) && code.includes(role.roleCode)) {
69 69 return true;
70   - } else if (typeof code === "string" && code === role.roleCode) {
  70 + } else if (typeof code === 'string' && code === role.roleCode) {
71 71 return true;
72 72 } else {
73 73 return false;
... ...