index.tsx 17 KB

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