index.tsx 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. /*
  2. * @Author: code4eat awesomedema@gmail.com
  3. * @Date: 2023-03-03 11:30:33
  4. * @LastEditors: code4eat awesomedema@gmail.com
  5. * @LastEditTime: 2024-12-02 14:09:41
  6. * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
  7. * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  8. */
  9. import { KCInput } from '@/components/KCInput';
  10. import KCTable from '@/components/kcTable';
  11. import { getAllHosp } from '@/service/hospList';
  12. import { ModalForm, ProFormDigit, ProFormRadio, ProFormSelect, ProFormText, ProFormTextArea } from '@ant-design/pro-form';
  13. import { ProColumns } from '@ant-design/pro-table';
  14. import { Input, message, Modal, Popconfirm, TreeProps } from 'antd';
  15. import { useEffect, useState } from 'react';
  16. import { getData, PubDicTypeData } from '../pubDicTypeMana/service';
  17. import { addPubDicRelaTbaleData, delData, editPubDicRelaTbaleData, getLeftData, getPubDicRelaTbaleData, initReq } from './service';
  18. import { useLocation } from 'umi';
  19. import './style.less';
  20. import { getDeepestTreeData } from '@/utils';
  21. import expandedIcon from '../../../../../public/images/treenode_open.png';
  22. import closeIcon from '../../../../../public/images/treenode_collapse.png';
  23. import { createFromIconfontCN } from '@ant-design/icons';
  24. import { DataNode } from 'antd/lib/tree';
  25. import DirectoryTree from 'antd/es/tree/DirectoryTree';
  26. const SearchIcon = createFromIconfontCN({
  27. scriptUrl: '//at.alicdn.com/t/c/font_1927152_g1njmm1kh7b.js',
  28. });
  29. let systemId = '';
  30. const currentSelectedTab = localStorage.getItem('currentSelectedTab');
  31. if (currentSelectedTab) {
  32. const { systemId: id } = JSON.parse(currentSelectedTab as string);
  33. systemId = id;
  34. }
  35. const PubDicMana = () => {
  36. const [tableDataFilterParams, set_tableDataFilterParams] = useState<any | undefined>();
  37. const [tableDataSearchKeywords, set_tableDataSearchKeywords] = useState<string>('');
  38. const [reload, set_reload] = useState(false);
  39. const [treeData, set_treeData] = useState<any[]>([]);
  40. const [currentSelectedTreeNode, set_currentSelectedTreeNode] = useState<any | undefined>();
  41. const [expandedKeys, setExpandedKeys] = useState<React.Key[]>([]);
  42. const [searchValue, setSearchValue] = useState('');
  43. const [autoExpandParent, setAutoExpandParent] = useState(true);
  44. const [pageType, set_pageType] = useState<undefined | number>(undefined); // 1 公用字典 2 院区公用字典
  45. const location = useLocation();
  46. const defaultColumns = [
  47. {
  48. title: '项目名称',
  49. dataIndex: 'name',
  50. },
  51. {
  52. title: '项目代码',
  53. dataIndex: 'code',
  54. },
  55. {
  56. title: '项目值',
  57. dataIndex: 'value',
  58. },
  59. {
  60. title: '默认',
  61. dataIndex: 'data.0.dictDefault',
  62. render: (_: any, record: any) => {
  63. return record.dictDefault == 1 ? '是' : '否';
  64. },
  65. },
  66. {
  67. title: '序号',
  68. dataIndex: pageType == 1 ? 'dictSort' : 'sort',
  69. },
  70. {
  71. title: '扩展1',
  72. dataIndex: 'expandOne',
  73. },
  74. {
  75. title: '扩展2',
  76. dataIndex: 'expandTwo',
  77. },
  78. ];
  79. const options = [
  80. {
  81. title: '操作',
  82. key: 'option',
  83. width: 120,
  84. valueType: 'option',
  85. render: (_: any, record: any) => {
  86. return [
  87. <UpDataActBtn key={'act'} record={record} type="EDIT" />,
  88. <Popconfirm title="是否确认删除?" key="del" onConfirm={() => delTableData(record)}>
  89. <a>删除</a>
  90. </Popconfirm>,
  91. ];
  92. },
  93. },
  94. ];
  95. const [columns, set_columns] = useState<any[]>([]);
  96. const getTableData = async (params: any) => {
  97. const { dictType, systemId } = currentSelectedTreeNode;
  98. if (dictType && pageType) {
  99. const resp = await getPubDicRelaTbaleData({ ...params, dictType: params.dictType ? params.dictType : currentSelectedTreeNode.dictType, systemId }, pageType);
  100. set_reload(false);
  101. if (resp) {
  102. return {
  103. data: resp.list,
  104. success: true,
  105. total: resp.totalCount,
  106. };
  107. }
  108. }
  109. return [];
  110. };
  111. const delTableData = async (record: any) => {
  112. if (pageType) {
  113. const resp = await delData(pageType == 1 ? record.dictDataId : record.id, pageType);
  114. if (resp) {
  115. set_reload(true);
  116. }
  117. }
  118. };
  119. const updateTable = async (formVal: any, type: 'EDIT' | 'ADD') => {
  120. const currentSelectedHop = localStorage.getItem('currentSelectedSubHop');
  121. const { systemId: parentId } = currentSelectedTreeNode;
  122. let hospId = '0';
  123. if (currentSelectedHop&&pageType == 2) {
  124. const { id } = JSON.parse(currentSelectedHop);
  125. hospId = id
  126. }
  127. if (type == 'EDIT' && pageType) {
  128. const resp = await editPubDicRelaTbaleData(
  129. pageType == 1 ? { ...formVal, systemId: parentId, hospId, dictType: currentSelectedTreeNode?.dictType } : { ...formVal, systemId: parentId, hospId, type: currentSelectedTreeNode?.dictType },
  130. pageType,
  131. );
  132. if (resp) {
  133. set_reload(true);
  134. }
  135. }
  136. if (type == 'ADD' && pageType) {
  137. const resp = await addPubDicRelaTbaleData(
  138. pageType == 1 ? { ...formVal, systemId: parentId, hospId, dictType: currentSelectedTreeNode?.dictType } : { ...formVal, systemId: parentId, hospId, type: currentSelectedTreeNode?.dictType },
  139. pageType,
  140. );
  141. if (resp) {
  142. set_reload(true);
  143. }
  144. }
  145. return true
  146. };
  147. const UpDataActBtn = ({ record, type }: { record: any; type: 'EDIT' | 'ADD' }) => {
  148. let tableFileNames = [];
  149. if (currentSelectedTreeNode) {
  150. const { topic = '' } = currentSelectedTreeNode;
  151. const titles = topic.split('|')
  152. if (topic && titles.length == 7) {
  153. tableFileNames = titles
  154. }
  155. }
  156. return (
  157. <ModalForm
  158. title={`${type == 'EDIT' ? '编辑' : '新增'}公用字典(${currentSelectedTreeNode?.dictName})`}
  159. width={352}
  160. initialValues={type == 'EDIT' ? { ...record } : {}}
  161. trigger={type == 'EDIT' ? <a key="edit">编辑</a> : <span className="add">新增</span>}
  162. onFinish={(val) => {
  163. return updateTable(type == 'EDIT' ? (pageType == 1 ? { ...val, dictDataId: record.dictDataId } : { ...val, id: record.id }) : val, type);
  164. }}
  165. >
  166. <ProFormText name="name" label={tableFileNames.length == 7?`${tableFileNames[0]}:`:"名称:"} placeholder="请输入" rules={[{ required: true, message: '名称不能为空!' }]} />
  167. <ProFormText name="code" label={tableFileNames.length == 7?`${tableFileNames[1]}:`:"代码:"} placeholder="请输入" rules={[{ required: true, message: '代码不能为空!' }]} />
  168. <ProFormText name="value" label={tableFileNames.length == 7?`${tableFileNames[2]}:`:"对应值:"} placeholder="请输入" />
  169. <ProFormDigit label={tableFileNames.length == 7?`${tableFileNames[3]}:`:"顺序号:"} name={pageType == 1 ? 'dictSort' : 'sort'} rules={[{ required: true, message: '顺序号不能为空!' }]} />
  170. <ProFormRadio.Group
  171. name={pageType == 1 ? 'dictDefault' : 'defaultFlag'}
  172. label={tableFileNames.length == 7?`${tableFileNames[4]}:`:"默认:"}
  173. fieldProps={{
  174. buttonStyle: 'solid',
  175. }}
  176. options={[
  177. {
  178. label: '是',
  179. value: 1,
  180. },
  181. {
  182. label: '否',
  183. value: 0,
  184. },
  185. ]}
  186. rules={[{ required: true, message: '默认不能为空!' }]}
  187. />
  188. {true && (
  189. <>
  190. <ProFormText name="expandOne" label={tableFileNames.length == 7?`${tableFileNames[5]}:`:"扩展一:"} placeholder="请输入" />
  191. <ProFormText name="expandTwo" label={tableFileNames.length == 7?`${tableFileNames[6]}:`:"扩展二:"} placeholder="请输入" />
  192. </>
  193. )}
  194. </ModalForm>
  195. );
  196. };
  197. const tableDataSearchHandle = (paramName: string) => {
  198. set_tableDataFilterParams({
  199. ...tableDataFilterParams,
  200. current:1,
  201. [`${paramName}`]: tableDataSearchKeywords,
  202. });
  203. };
  204. const getTreeReqFunc = async (type: number) => {
  205. const resp = await getLeftData(type);
  206. const transformResp = resp.map((a: any, index: number) => {
  207. return {
  208. code: Math.random(),
  209. name: a.systemName,
  210. systemId: a.systemId,
  211. children: a.dictTypeList.map((b: any, num: number) => ({ ...b, name: b.dictName, code: Math.random() })),
  212. };
  213. });
  214. set_treeData(transformResp);
  215. };
  216. const dataList: any[] = [];
  217. const getParentKey = (key: React.Key, tree: any[]): React.Key => {
  218. let parentKey: React.Key;
  219. for (let i = 0; i < tree.length; i++) {
  220. const node = tree[i];
  221. if (node.children) {
  222. if (node.children.some((item: { code: React.Key }) => item.code === key)) {
  223. parentKey = node.code;
  224. } else if (getParentKey(key, node.children)) {
  225. parentKey = getParentKey(key, node.children);
  226. }
  227. }
  228. }
  229. return parentKey!;
  230. };
  231. const generateList = (data: any[]) => {
  232. if (!data) return;
  233. for (let i = 0; i < data.length; i++) {
  234. const node = data[i];
  235. const { code, name } = node;
  236. dataList.push({ code, name: name });
  237. if (node.children) {
  238. generateList(node.children);
  239. }
  240. }
  241. };
  242. generateList(treeData as any);
  243. const onTreeSearchKeyChange = (e: React.ChangeEvent<HTMLInputElement>) => {
  244. const { value } = e.target;
  245. const newExpandedKeys = dataList.map((item) => {
  246. if (item.name.indexOf(value) > -1) {
  247. return getParentKey(item.code, treeData);
  248. }
  249. return null;
  250. });
  251. const b = newExpandedKeys.filter((item, i, self) => item && self.indexOf(item) === i);
  252. setExpandedKeys(newExpandedKeys as React.Key[]);
  253. setSearchValue(value);
  254. setAutoExpandParent(true);
  255. };
  256. const onSelect: TreeProps['onSelect'] = (selectedKeys, info) => {
  257. //console.log('selected', selectedKeys, info);
  258. const { node } = info;
  259. if (!node.children) {
  260. set_currentSelectedTreeNode(node);
  261. }
  262. };
  263. const onExpand = (newExpandedKeys: React.Key[]) => {
  264. setExpandedKeys(newExpandedKeys);
  265. setAutoExpandParent(false);
  266. };
  267. const initFunction = () => {
  268. Modal.confirm({
  269. title: '注意',
  270. content: '初始化操作会覆盖已有的字典数据并根据默认数据生成字典数据,确定继续操作?',
  271. onOk: async (...args) => {
  272. if (currentSelectedTreeNode) {
  273. const { systemId, dictType } = currentSelectedTreeNode;
  274. const resp = await initReq(systemId, dictType);
  275. if (resp) {
  276. set_reload(true);
  277. message.success('初始化成功!');
  278. }
  279. }
  280. },
  281. });
  282. };
  283. useEffect(() => {
  284. if (currentSelectedTreeNode) {
  285. const { topic = '' } = currentSelectedTreeNode;
  286. const titles = topic.split('|');
  287. if (topic && titles.length == 7) {
  288. const newColumns = defaultColumns.map((a, index) => ({
  289. ...a,
  290. title: titles[index],
  291. }));
  292. set_columns([...newColumns, ...options]);
  293. } else {
  294. set_columns([...defaultColumns, ...options]);
  295. }
  296. set_reload(true);
  297. }
  298. }, [currentSelectedTreeNode]);
  299. useEffect(() => {
  300. //初始化左侧树结构数据后
  301. if (treeData?.length > 0) {
  302. if (treeData[0].children && treeData[0].children.length > 0) {
  303. const [node, nodeParent] = getDeepestTreeData(treeData[0], 'children');
  304. set_currentSelectedTreeNode(node);
  305. setExpandedKeys([nodeParent.code]);
  306. }
  307. }
  308. }, [treeData]);
  309. useEffect(() => {
  310. const { pathname } = location;
  311. if (pathname == '/platform/setting/pubDicMana/1') set_pageType(1);
  312. if (pathname == '/platform/setting/pubDicMana/2') set_pageType(2);
  313. }, [location]);
  314. useEffect(() => {
  315. if (pageType) getTreeReqFunc(pageType);
  316. }, [pageType]);
  317. return (
  318. <div className="PubDicMana">
  319. <div className="left">
  320. <div className="search">
  321. <Input className="searchInput" placeholder="请输入" size="small" allowClear style={{ marginBottom: 16 }} onChange={onTreeSearchKeyChange} suffix={<SearchIcon type="iconsousuo" />} />
  322. </div>
  323. <div className="wrap">
  324. {treeData && treeData.length > 0 && (
  325. <DirectoryTree
  326. fieldNames={{ title: 'name', key: 'code' }}
  327. rootStyle={{ height: '100%', paddingBottom: 50 }}
  328. onSelect={onSelect}
  329. onExpand={onExpand}
  330. expandedKeys={expandedKeys}
  331. autoExpandParent={autoExpandParent}
  332. selectedKeys={currentSelectedTreeNode ? [currentSelectedTreeNode.code] : []}
  333. blockNode={true}
  334. icon={() => null}
  335. titleRender={(nodeData: any) => {
  336. const strTitle = nodeData.name as string;
  337. const index = strTitle.indexOf(searchValue);
  338. const beforeStr = strTitle.substring(0, index);
  339. const afterStr = strTitle.slice(index + searchValue.length);
  340. const title =
  341. index > -1 ? (
  342. <span>
  343. {beforeStr}
  344. <span className="site-tree-search-value" style={{ color: 'red', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
  345. {searchValue}
  346. </span>
  347. {afterStr}
  348. </span>
  349. ) : (
  350. <span className="strTitle">{strTitle}</span>
  351. );
  352. return (
  353. <div
  354. style={{
  355. display: 'flex',
  356. flexDirection: 'row',
  357. width: '100%',
  358. justifyContent: 'flex-start',
  359. alignItems: 'center',
  360. height: 32,
  361. borderRadius: '4px',
  362. overflow: 'hidden',
  363. color: '#17181A',
  364. textOverflow: 'ellipsis',
  365. whiteSpace: 'nowrap',
  366. }}
  367. >
  368. {title}
  369. </div>
  370. );
  371. }}
  372. defaultSelectedKeys={[treeData[0].children[0].code]}
  373. treeData={treeData as unknown as DataNode[]}
  374. // treeData={treeDataNew}
  375. switcherIcon={(props: any) => {
  376. const { expanded } = props;
  377. //return <button className='site-table-row-expand-icon site-table-row-expand-icon-expanded'></button>
  378. return !expanded ? (
  379. <img style={{ width: 20, height: 20, position: 'relative', top: 5 }} src={expandedIcon} />
  380. ) : (
  381. <img style={{ width: 20, height: 20, position: 'relative', top: 5 }} src={closeIcon} />
  382. );
  383. }}
  384. />
  385. )}
  386. </div>
  387. </div>
  388. <div className="right">
  389. <div className="toolBar">
  390. <div className="filter">
  391. <div className="filterItem">
  392. <span className="label">检索:</span>
  393. <KCInput
  394. placeholder={'请输入项目名称'}
  395. style={{ width: 160 }}
  396. search
  397. allowClear
  398. onChange={(e) => {
  399. set_tableDataSearchKeywords(e.target.value);
  400. if (e.target.value.length == 0) {
  401. set_tableDataFilterParams(
  402. pageType == 1
  403. ? {
  404. ...tableDataFilterParams,
  405. current:1,
  406. typeName: '',
  407. }
  408. : { ...tableDataFilterParams,current:1, dictName: '' },
  409. );
  410. }
  411. }}
  412. onSearch={() => tableDataSearchHandle(pageType == 1 ? 'typeName' : 'dictName')}
  413. />
  414. </div>
  415. </div>
  416. <div className="btnGroup">
  417. {pageType == 2 && (
  418. <span className="initBtn" onClick={() => initFunction()}>
  419. 初始化
  420. </span>
  421. )}
  422. <UpDataActBtn record type="ADD" />
  423. </div>
  424. </div>
  425. <div style={{ marginTop: 16 }}>
  426. {currentSelectedTreeNode && (
  427. <KCTable
  428. scroll={{ y: `calc(100vh - 250px)` }}
  429. columns={columns as ProColumns[]}
  430. reload={reload}
  431. rowKey={pageType == 1 ? 'dictDataId' : 'id'}
  432. newVer
  433. params={tableDataFilterParams}
  434. request={(params) => getTableData(params)}
  435. />
  436. )}
  437. </div>
  438. </div>
  439. </div>
  440. );
  441. };
  442. export default PubDicMana;