index.tsx 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  1. /*
  2. * @Author: code4eat awesomedema@gmail.com
  3. * @Date: 2022-12-16 09:42:52
  4. * @LastEditors: code4eat awesomedema@gmail.com
  5. * @LastEditTime: 2023-06-12 16:46:28
  6. * @FilePath: /BudgetManaSystem/src/pages/budgetMana/monthlySet/index.tsx
  7. * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  8. */
  9. import BMSPagecontainer from '@/components/BMSPageContainer';
  10. import { useEffect, useImperativeHandle, useRef, useState } from 'react';
  11. import './style.less';
  12. import { TreeProps, Input, Modal, Transfer, Popconfirm, Table, message } from 'antd';
  13. import { DataNode } from 'antd/es/tree';
  14. import expandedIcon from '../../../../../static/treenode_open.png';
  15. import closeIcon from '../../../../../static/treenode_collapse.png';
  16. import { BMSTable } from '@/components/BMSTable';
  17. import { ActionType, ProColumns} from '@ant-design/pro-components';
  18. import { createFromIconfontCN } from '@ant-design/icons';
  19. import { CheckUnitEmpMapTableDataType, delTableData,addMapEmp,getCheckUnitEmpMapTableDataByUnitClass,getMapEmpList, getTreeData, getTreeDataRespType } from './service';
  20. import { TransferItem, TransferProps } from 'antd/es/transfer';
  21. import difference from 'lodash/difference';
  22. import 'dayjs/locale/zh-cn';
  23. import React from 'react';
  24. import DirectoryTree from 'antd/es/tree/DirectoryTree';
  25. import { getDeepestTreeData } from '@/utils/tooljs';
  26. import { ColumnsType, TableRowSelection } from 'antd/es/table/interface';
  27. import '../../../../utils/zhongtaiB';
  28. import '../../../../utils/zhongtaiC';
  29. const IconFont = createFromIconfontCN({
  30. scriptUrl: '',
  31. });
  32. const SearchIcon = createFromIconfontCN({
  33. scriptUrl: '',
  34. });
  35. export type TableListItem = {
  36. key: number;
  37. name: string;
  38. };
  39. const CheckUnitDepMap: React.FC = () => {
  40. const [treeData, set_treeData] = useState<getTreeDataRespType[]>([]);
  41. const [tableColumn, set_tableColumn] = useState<ProColumns[]>([]);
  42. const [currentSelectedTreeNode, set_currentSelectedTreeNode] = useState<any | undefined>();
  43. const [tableDataFilterParams, set_tableDataFilterParams] = useState<any | undefined>(undefined);
  44. const [tableDataSearchKeywords,set_tableDataSearchKeywords] = useState('');
  45. const [tableData,set_tableData] = useState<CheckUnitEmpMapTableDataType[]>([]);
  46. const [expandedKeys, setExpandedKeys] = useState<React.Key[]>([]);
  47. const [searchValue, setSearchValue] = useState('');
  48. const [autoExpandParent, setAutoExpandParent] = useState(true);
  49. const tableRef = useRef<ActionType>();
  50. const column = [
  51. {
  52. title: '工号',
  53. dataIndex: 'account'
  54. },
  55. {
  56. title: '姓名',
  57. dataIndex: 'name',
  58. },
  59. {
  60. title: '人员类别',
  61. dataIndex: 'userCateName',
  62. },
  63. {
  64. title: '职务',
  65. dataIndex: 'jobTitleName',
  66. },
  67. {
  68. title: '职称',
  69. dataIndex: 'titleName',
  70. },
  71. {
  72. title: '岗位',
  73. dataIndex: 'positionName',
  74. },
  75. {
  76. title: '学历',
  77. dataIndex: 'degreeName',
  78. },
  79. // {
  80. // title: '入职时间',
  81. // dataIndex: 'entryTime',
  82. // },
  83. // {
  84. // title: '在职',
  85. // dataIndex: 'isOnServiceName',
  86. // },
  87. {
  88. title: '操作',
  89. key: 'option',
  90. valueType: 'option',
  91. render: (_: any, record: any) => {
  92. return [
  93. <Popconfirm
  94. title="是否确认删除?"
  95. key="del"
  96. onConfirm={() => delTableDataHandle(record)}
  97. >
  98. <a>删除</a>
  99. </Popconfirm>
  100. ]
  101. },
  102. },
  103. ];
  104. const delTableDataHandle = async (record: any) => {
  105. const resp: any = await delTableData(record.id);
  106. if (resp) {
  107. getTreeReqFunc();
  108. tableRef.current?.reload()
  109. }
  110. }
  111. const onSelect: TreeProps['onSelect'] = (selectedKeys, info) => {
  112. // console.log('selected', selectedKeys, info);
  113. const { node } = info;
  114. set_currentSelectedTreeNode(node);
  115. };
  116. const getTableData = async (type: 'PERSON' | 'DEP' | 'CHARGE', params: any, sort: any, filter: any) => {
  117. // console.log({ currentSelectedTreeNode });
  118. // console.log({ params, sort, filter });
  119. if (currentSelectedTreeNode) {
  120. const resp = await getCheckUnitEmpMapTableDataByUnitClass({
  121. ...params,
  122. unitCode: currentSelectedTreeNode.code,
  123. });
  124. if (resp) {
  125. set_tableData(resp.list);
  126. return {
  127. data: resp.list,
  128. success: true,
  129. total: resp.totalCount,
  130. pageSize: resp.pageSize,
  131. totalPage: resp.totalPage,
  132. }
  133. }
  134. return {
  135. data: [],
  136. success: true
  137. }
  138. }
  139. return []
  140. }
  141. const transferTableColumn: any[] = [
  142. {
  143. title: '工号',
  144. dataIndex: 'account',
  145. with: 100,
  146. ellipsis: true,
  147. },
  148. {
  149. title: '姓名',
  150. width: 120,
  151. dataIndex: 'name',
  152. ellipsis: true
  153. },
  154. ];
  155. const addHandle = () => {
  156. const ref = React.createRef<{ save: any; }>();
  157. Modal.confirm({
  158. title: `添加单元对照科室(${currentSelectedTreeNode.name})`,
  159. icon: <></>,
  160. width: 750,
  161. okText: '确定',
  162. cancelText: '取消',
  163. centered: true,
  164. content: <TableTransfer
  165. ref={ref}
  166. record={currentSelectedTreeNode}
  167. leftColumns={transferTableColumn}
  168. rightColumns={transferTableColumn} dataSource={[]}
  169. ></TableTransfer>,
  170. onOk: () => {
  171. return ref.current && ref.current.save();
  172. }
  173. })
  174. }
  175. const TableTransfer = React.forwardRef(({ leftColumns, rightColumns, record }:any, ref) => {
  176. const [targetKeys, setTargetKeys] = useState<string[]>([]);
  177. const [datasource, set_datasource] = useState<any[]>([]);
  178. const [selectedKeys, setSelectedKeys] = useState<string[]>([]);
  179. //获取对照科室
  180. const getFuncList = async () => {
  181. const resp = await getMapEmpList();
  182. if (resp) {
  183. const defaultSelctedkeys = tableData.map((item: any) => item.userId);
  184. set_datasource([...resp,...tableData]);
  185. setTargetKeys(defaultSelctedkeys);
  186. }
  187. }
  188. const onChange = (nextTargetKeys: string[]) => {
  189. setTargetKeys(nextTargetKeys);
  190. };
  191. const onSelectChange = (sourceSelectedKeys: string[], targetSelectedKeys: string[]) => {
  192. //console.log('sourceSelectedKeys:', sourceSelectedKeys,'targetSelectedKeys:',targetSelectedKeys);
  193. setSelectedKeys([...sourceSelectedKeys, ...targetSelectedKeys]);
  194. };
  195. useImperativeHandle(ref, () => ({
  196. save: async () => {
  197. const needData = datasource.filter(item => targetKeys.includes(item.userId));
  198. const result = {
  199. unitCode:record.code,
  200. unitType:record.unitType,
  201. employee:needData
  202. };
  203. const resp = await addMapEmp(result);
  204. if (resp) {
  205. message.success('添加成功!');
  206. getTreeReqFunc();
  207. tableRef.current?.reload();
  208. }
  209. }
  210. }));
  211. useEffect(() => {
  212. getFuncList();
  213. }, [])
  214. return (
  215. <Transfer className='TableTransfer' showSearch
  216. titles={['待选项', '已选项']}
  217. locale={{
  218. itemUnit: '项',
  219. itemsUnit: '项',
  220. searchPlaceholder: '请输入'
  221. }}
  222. onChange={onChange}
  223. onSelectChange={onSelectChange}
  224. dataSource={datasource}
  225. rowKey={record => record.userId}
  226. targetKeys={targetKeys}
  227. selectedKeys={selectedKeys}
  228. filterOption={(inputValue, item) => {
  229. return item.deptName!.indexOf(inputValue) !== -1
  230. }}
  231. >
  232. {({
  233. direction,
  234. filteredItems,
  235. onItemSelectAll,
  236. onItemSelect,
  237. selectedKeys: listSelectedKeys,
  238. disabled: listDisabled,
  239. }) => {
  240. // console.log({ filteredItems, listSelectedKeys,direction });
  241. const columns = direction === 'left' ? leftColumns : rightColumns;
  242. const rowSelection: TableRowSelection<TransferItem> = {
  243. getCheckboxProps: (item) => ({ disabled: listDisabled || item.disabled }),
  244. onSelectAll(selected, selectedRows) {
  245. const treeSelectedKeys = selectedRows.map(({ userId }) => userId);
  246. const diffKeys = selected
  247. ? difference(treeSelectedKeys, listSelectedKeys)
  248. : difference(listSelectedKeys, treeSelectedKeys);
  249. onItemSelectAll(diffKeys as string[], selected);
  250. },
  251. onSelect({ userId }, selected) {
  252. onItemSelect(userId as string, selected);
  253. },
  254. selectedRowKeys: listSelectedKeys,
  255. };
  256. return (
  257. <BMSTable
  258. rowSelection={rowSelection}
  259. columns={columns as TransferItem[]}
  260. dataSource={filteredItems}
  261. size="small"
  262. rowKey={'userId'}
  263. tableAlertRender={false}
  264. pagination={{simple:true,pageSize:10}}
  265. style={{ pointerEvents: listDisabled ? 'none' : undefined }}
  266. onRow={({ userId, disabled: itemDisabled }) => ({
  267. onClick: () => {
  268. if (itemDisabled || listDisabled) return;
  269. onItemSelect(userId as string, !listSelectedKeys.includes(userId as string));
  270. },
  271. })}
  272. />
  273. );
  274. }}
  275. </Transfer>
  276. )
  277. })
  278. const dataList: any[] = [];
  279. const getParentKey = (key: React.Key, tree: any[]): React.Key => {
  280. let parentKey: React.Key;
  281. for (let i = 0; i < tree.length; i++) {
  282. const node = tree[i];
  283. if (node.child) {
  284. if (node.child.some((item: { code: React.Key; }) => item.code === key)) {
  285. parentKey = node.code;
  286. } else if (getParentKey(key, node.child)) {
  287. parentKey = getParentKey(key, node.child);
  288. }
  289. }
  290. }
  291. return parentKey!;
  292. };
  293. const onTreeSearchKeyChange = (e: React.ChangeEvent<HTMLInputElement>) => {
  294. const { value } = e.target;
  295. const newExpandedKeys = dataList
  296. .map((item) => {
  297. if (item.name.indexOf(value) > -1) {
  298. return getParentKey(item.code, treeData);
  299. }
  300. return null;
  301. });
  302. const b = newExpandedKeys.filter((item, i, self) => item && self.indexOf(item) === i);
  303. setExpandedKeys(newExpandedKeys as React.Key[]);
  304. setSearchValue(value);
  305. setAutoExpandParent(true);
  306. }
  307. const onExpand = (newExpandedKeys: React.Key[]) => {
  308. setExpandedKeys(newExpandedKeys);
  309. setAutoExpandParent(false);
  310. };
  311. const generateList = (data: any[]) => {
  312. for (let i = 0; i < data.length; i++) {
  313. const node = data[i];
  314. const { code, name } = node;
  315. dataList.push({ code, name });
  316. if (node.child) {
  317. generateList(node.child);
  318. }
  319. }
  320. };
  321. generateList(treeData as any);
  322. const getTreeReqFunc = async () => {
  323. const resp = await getTreeData();
  324. set_treeData(resp);
  325. }
  326. const tableDataSearchHandle = (paramName: string) => {
  327. set_tableDataFilterParams({
  328. ...tableDataFilterParams,
  329. [`${paramName}`]: tableDataSearchKeywords
  330. })
  331. }
  332. useEffect(() => {
  333. if(currentSelectedTreeNode&&currentSelectedTreeNode.unitType){
  334. tableRef.current?.reload();
  335. }
  336. }, [currentSelectedTreeNode]);
  337. useEffect(() => {
  338. //初始化左侧树结构数据后
  339. if(currentSelectedTreeNode) return;
  340. if (treeData?.length > 0) {
  341. if (treeData[0].child && treeData[0].child.length > 0) {
  342. const [node, nodeParent] = getDeepestTreeData(treeData[0], 'child');
  343. set_currentSelectedTreeNode(node);
  344. setExpandedKeys([nodeParent.code]);
  345. }
  346. }
  347. }, [treeData]);
  348. useEffect(() => {
  349. set_tableColumn(column as ProColumns[]);
  350. getTreeReqFunc();
  351. }, []);
  352. return (
  353. <div className='CheckUnitDepMap'>
  354. <div className='leftTree'>
  355. <div className='search'>
  356. <Input
  357. className='searchInput'
  358. placeholder="请输入类目名称"
  359. size='small'
  360. allowClear
  361. style={{ marginBottom: 16 }}
  362. onChange={onTreeSearchKeyChange}
  363. suffix={
  364. <SearchIcon type='iconsousuo' />
  365. }
  366. />
  367. </div>
  368. {
  369. treeData && treeData.length > 0 && currentSelectedTreeNode && (
  370. <DirectoryTree
  371. fieldNames={{ title: 'name', key: 'code',children:'child' }}
  372. rootStyle={{ height: '100%', paddingBottom: 50, overflowY: 'scroll', overflowX: 'hidden' }}
  373. onSelect={onSelect}
  374. onExpand={onExpand}
  375. expandedKeys={expandedKeys}
  376. autoExpandParent={autoExpandParent}
  377. selectedKeys={[currentSelectedTreeNode.code]}
  378. blockNode={true}
  379. icon={() => null}
  380. titleRender={
  381. (nodeData: any) => {
  382. const strTitle = nodeData.name as string;
  383. const index = strTitle.indexOf(searchValue);
  384. const beforeStr = strTitle.substring(0, index);
  385. const afterStr = strTitle.slice(index + searchValue.length);
  386. const title =
  387. index > -1 ? (
  388. <span style={{display:'flex',flexDirection:'row',justifyContent:'center',alignItems:'center'}}>
  389. {beforeStr}
  390. <span className={'site-tree-search-value'} style={{ color: 'red', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{searchValue}</span>
  391. {afterStr}
  392. </span>
  393. ) : (
  394. <span className={'strTitle'}>{strTitle}</span>
  395. );
  396. return <div style={{
  397. display: 'flex', flexDirection: 'row',
  398. width: '100%',
  399. justifyContent:'space-between', alignItems: 'center', height: 32,
  400. borderRadius: '4px',
  401. overflow: 'hidden',
  402. color: '#17181A',
  403. textOverflow: 'ellipsis',
  404. whiteSpace: 'nowrap'
  405. }}>
  406. {title}
  407. {!nodeData.map&&<span className={nodeData.unitType?'point lastChild':'point'}></span>}
  408. </div>
  409. }
  410. }
  411. defaultSelectedKeys={[treeData[0].child[0].code]}
  412. treeData={treeData as unknown as DataNode[]}
  413. // treeData={treeDataNew}
  414. switcherIcon={(props: any) => {
  415. const { expanded } = props;
  416. return !expanded ? <img style={{ width: 20, height: 20, position: 'relative', top: 5 }} src={expandedIcon} /> : <img style={{ width: 20, height: 20, position: 'relative', top: 5 }} src={closeIcon} />
  417. }}
  418. />
  419. )
  420. }
  421. </div>
  422. {/* <div style={{width:16,height:'92vh',background:'#F5F7FA'}}></div> */}
  423. <div className='rightContent'>
  424. <BMSPagecontainer title={false} ghost>
  425. <div className='content'>
  426. <div className='tableToolbar'>
  427. <div className='search'>
  428. <span>检索:</span><Input className='searchInput' allowClear placeholder="请输入工号/姓名" onChange={(e) => {
  429. set_tableDataSearchKeywords(e.target.value);
  430. if (e.target.value.length == 0) {
  431. set_tableDataFilterParams({...tableDataFilterParams,empName:''});
  432. }
  433. }} suffix={
  434. <IconFont type="iconsousuo" onClick={() => tableDataSearchHandle('empName')} />
  435. }
  436. onPressEnter={(e) => {
  437. set_tableDataFilterParams({
  438. ...tableDataFilterParams,
  439. empName: (e.target as HTMLInputElement).value
  440. });
  441. }}
  442. />
  443. </div>
  444. <div className='btnGroup'>
  445. <span className='add' onClick={()=>addHandle()}>添加</span>
  446. </div>
  447. </div>
  448. {currentSelectedTreeNode && <BMSTable actionRef={tableRef} params={tableDataFilterParams} rowKey='id' columns={tableColumn} request={(params, sort, filter) => getTableData('CHARGE', params, sort, filter)} />}
  449. </div>
  450. </BMSPagecontainer>
  451. </div>
  452. </div>
  453. );
  454. };
  455. export default CheckUnitDepMap;