index.tsx 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  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-06 13:32:54
  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,useRef, useState } from 'react';
  11. import './style.less';
  12. import { TreeProps, Input,Popconfirm, 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, ModalForm, ProColumns, ProFormRadio, ProFormSelect, ProFormText, ProFormTextArea } from '@ant-design/pro-components';
  18. import { createFromIconfontCN } from '@ant-design/icons';
  19. import { addCheckUnit, delTableData, editCheckUnit, getCheckUnitTableDataByUnitClass, getTreeData } from './service';
  20. import 'dayjs/locale/zh-cn';
  21. import React from 'react';
  22. import DirectoryTree from 'antd/es/tree/DirectoryTree';
  23. import { getDeepestTreeData } from '@/utils/tooljs';
  24. import { CheckUnitClassTableDataType } from '../checkUnitClassMana/service';
  25. import { getDataByKeyFromDic, getPubDicData } from '@/services/getDic';
  26. import '../../../../utils/zhongtaiB';
  27. import '../../../../utils/zhongtaiC';
  28. const IconFont = createFromIconfontCN({
  29. scriptUrl: '',
  30. });
  31. const SearchIcon = createFromIconfontCN({
  32. scriptUrl: '',
  33. });
  34. export type TableListItem = {
  35. key: number;
  36. name: string;
  37. };
  38. const CheckUnitMana: React.FC = () => {
  39. const [treeData, set_treeData] = useState<CheckUnitClassTableDataType[]>([]);
  40. const [tableColumn, set_tableColumn] = useState<ProColumns[]>([]);
  41. const [currentSelectedTreeNode, set_currentSelectedTreeNode] = useState<any | undefined>();
  42. const [tableDataFilterParams, set_tableDataFilterParams] = useState<any | undefined>(undefined);
  43. const [tableDataSearchKeywords, set_tableDataSearchKeywords] = useState('');
  44. const [expandedKeys, setExpandedKeys] = useState<React.Key[]>([]);
  45. const [searchValue, setSearchValue] = useState('');
  46. const [autoExpandParent, setAutoExpandParent] = useState(true);
  47. const tableRef = useRef<ActionType>();
  48. const column = [
  49. {
  50. title: '核算单元名称',
  51. dataIndex: 'unitName'
  52. },
  53. {
  54. title: '核算单元代码',
  55. dataIndex: 'code',
  56. },
  57. {
  58. title: '职类',
  59. dataIndex: 'unitTypeName',
  60. },
  61. {
  62. title: '特殊单元',
  63. dataIndex: 'specialUnit',
  64. render: (_: any, record: any) => {
  65. return record.specialUnit == 1 ? '是' : '否'
  66. }
  67. },
  68. {
  69. title: '单元分级',
  70. dataIndex: 'unitLevelName',
  71. // render: (_: any, record: any) => {
  72. // return record.specialUnit == 1 ? '是' : '否'
  73. // }
  74. },
  75. {
  76. title: '系数',
  77. dataIndex: 'rate',
  78. },
  79. {
  80. title: '说明',
  81. dataIndex: 'description',
  82. },
  83. {
  84. title: '操作',
  85. key: 'option',
  86. valueType: 'option',
  87. render: (_: any, record: any) => {
  88. return [
  89. <UpDataActBtn key={'act'} record={record} type='EDIT' />,
  90. <Popconfirm
  91. title="是否确认删除?"
  92. key="del"
  93. onConfirm={() => delTableDataHanfle(record)}
  94. >
  95. <a>删除</a>
  96. </Popconfirm>
  97. ]
  98. },
  99. },
  100. ];
  101. const delTableDataHanfle = async (record: any) => {
  102. const resp: any = await delTableData(record.id);
  103. if (resp) {
  104. tableRef.current?.reload();
  105. }
  106. }
  107. const onSelect: TreeProps['onSelect'] = (selectedKeys, info) => {
  108. // console.log('selected', selectedKeys, info);
  109. const { node } = info;
  110. set_currentSelectedTreeNode(node);
  111. };
  112. const updateTable = async (formVal: any, type: 'EDIT' | "ADD") => {
  113. if (type == 'ADD') {
  114. const resp = await addCheckUnit({
  115. ...formVal,
  116. classCode: currentSelectedTreeNode.code,
  117. unitType: currentSelectedTreeNode.unitType
  118. });
  119. if (resp) {
  120. tableRef.current?.reload();
  121. message.success('操作成功!');
  122. }
  123. }
  124. if (type == 'EDIT') {
  125. const resp = await editCheckUnit({
  126. ...formVal
  127. });
  128. if (resp) {
  129. tableRef.current?.reload();
  130. message.success('操作成功!');
  131. }
  132. }
  133. return true;
  134. }
  135. const UpDataActBtn = ({ record, type }: { record: any, type: 'EDIT' | 'ADD' }) => {
  136. const [dicData, set_dicData] = useState<any[]>([]);
  137. const getDirecData = async (key?: string) => {
  138. const data = await getPubDicData();
  139. if (data) {
  140. set_dicData(data);
  141. }
  142. }
  143. useEffect(()=>{
  144. getDirecData();
  145. },[]);
  146. return (
  147. <ModalForm
  148. title={`${type == 'EDIT' ? '编辑' : '新增'}核算单元`}
  149. width={400}
  150. initialValues={type == 'EDIT' ? {
  151. ...record,
  152. } : {}}
  153. trigger={
  154. type == 'EDIT' ? <a key="edit" >编辑</a> : <span className='add'>新增</span>
  155. }
  156. onFinish={(val) => {
  157. return updateTable(type == 'EDIT' ? { ...record, ...val } : { ...val }, type);
  158. }}
  159. modalProps={{ destroyOnClose: true }}
  160. colProps={{ span: 24 }}
  161. grid
  162. >
  163. <ProFormText
  164. name="unitName"
  165. label="核算单元名称:"
  166. placeholder="请输入"
  167. rules={[{ required: true, message: '名称不能为空!' }]}
  168. />
  169. <ProFormText
  170. name="code"
  171. label="核算单元代码:"
  172. placeholder="请输入"
  173. rules={[{ required: true, message: '代码不能为空!' }]}
  174. />
  175. <ProFormRadio.Group
  176. label="特殊单元"
  177. name="specialUnit"
  178. options={[{ label: '是', value: 1 }, { label: '否', value: 0 }]}
  179. rules={[{ required: true, message: '特殊单元不能为空!' }]}
  180. />
  181. <ProFormSelect label="单元分级:"
  182. name='unitLevel'
  183. options={(getDataByKeyFromDic(dicData, '4')).list}
  184. rules={[{ required: true, message: '职类不能为空!' }]}
  185. />
  186. <ProFormTextArea
  187. name="description"
  188. label="说明:"
  189. placeholder="请输入"
  190. />
  191. </ModalForm>
  192. )
  193. }
  194. const getTableData = async (params: any, sort: any, filter: any) => {
  195. // console.log({ currentSelectedTreeNode });
  196. // console.log({ params, sort, filter });
  197. if (currentSelectedTreeNode) {
  198. const resp = await getCheckUnitTableDataByUnitClass({
  199. ...params,
  200. classCode: currentSelectedTreeNode.code,
  201. });
  202. if (resp) {
  203. return {
  204. data: resp.list,
  205. success: true,
  206. total: resp.totalCount,
  207. pageSize: resp.pageSize,
  208. totalPage: resp.totalPage,
  209. }
  210. }
  211. return {
  212. data: [],
  213. success: true
  214. }
  215. }
  216. return []
  217. }
  218. const dataList: any[] = [];
  219. const getParentKey = (key: React.Key, tree: any[]): React.Key => {
  220. let parentKey: React.Key;
  221. for (let i = 0; i < tree.length; i++) {
  222. const node = tree[i];
  223. if (node.children) {
  224. if (node.children.some((item: { code: React.Key; }) => item.code === key)) {
  225. parentKey = node.code;
  226. } else if (getParentKey(key, node.children)) {
  227. parentKey = getParentKey(key, node.children);
  228. }
  229. }
  230. }
  231. return parentKey!;
  232. };
  233. const onTreeSearchKeyChange = (e: React.ChangeEvent<HTMLInputElement>) => {
  234. const { value } = e.target;
  235. const newExpandedKeys = dataList
  236. .map((item) => {
  237. if (item.className.indexOf(value) > -1) {
  238. return getParentKey(item.code, treeData);
  239. }
  240. return null;
  241. });
  242. const b = newExpandedKeys.filter((item, i, self) => item && self.indexOf(item) === i);
  243. setExpandedKeys(newExpandedKeys as React.Key[]);
  244. setSearchValue(value);
  245. setAutoExpandParent(true);
  246. }
  247. const onExpand = (newExpandedKeys: React.Key[]) => {
  248. setExpandedKeys(newExpandedKeys);
  249. setAutoExpandParent(false);
  250. };
  251. const generateList = (data: any[]) => {
  252. for (let i = 0; i < data.length; i++) {
  253. const node = data[i];
  254. const { code, className } = node;
  255. dataList.push({ code, className });
  256. if (node.children) {
  257. generateList(node.children);
  258. }
  259. }
  260. };
  261. generateList(treeData as any);
  262. const getTreeReqFunc = async () => {
  263. const resp = await getTreeData();
  264. set_treeData(resp);
  265. }
  266. const tableDataSearchHandle = (paramName: string) => {
  267. set_tableDataFilterParams({
  268. ...tableDataFilterParams,
  269. [`${paramName}`]: tableDataSearchKeywords
  270. })
  271. }
  272. useEffect(() => {
  273. tableRef.current?.reload();
  274. }, [currentSelectedTreeNode]);
  275. useEffect(() => {
  276. //初始化左侧树结构数据后
  277. if (treeData?.length > 0) {
  278. if (treeData[0].children && treeData[0].children.length > 0) {
  279. const [node, nodeParent] = getDeepestTreeData(treeData[0], 'children');
  280. set_currentSelectedTreeNode(node);
  281. setExpandedKeys([nodeParent.code]);
  282. }
  283. }
  284. }, [treeData]);
  285. useEffect(() => {
  286. set_tableColumn(column as ProColumns[]);
  287. getTreeReqFunc();
  288. }, []);
  289. return (
  290. <div className='CheckUnitMana'>
  291. <div className='leftTree'>
  292. <div className='search'>
  293. <Input
  294. className='searchInput'
  295. placeholder="请输入类目名称"
  296. size='small'
  297. allowClear
  298. style={{ marginBottom: 16 }}
  299. onChange={onTreeSearchKeyChange}
  300. suffix={
  301. <SearchIcon type='iconsousuo' />
  302. }
  303. />
  304. </div>
  305. {
  306. treeData && treeData.length > 0 && currentSelectedTreeNode && (
  307. <DirectoryTree
  308. fieldNames={{ title: 'className', key: 'code' }}
  309. rootStyle={{ height: '100%', paddingBottom: 50, overflowY: 'scroll', overflowX: 'hidden' }}
  310. onSelect={onSelect}
  311. onExpand={onExpand}
  312. expandedKeys={expandedKeys}
  313. autoExpandParent={autoExpandParent}
  314. selectedKeys={[currentSelectedTreeNode.code]}
  315. blockNode={true}
  316. icon={() => null}
  317. titleRender={
  318. (nodeData: any) => {
  319. const strTitle = nodeData.className as string;
  320. const index = strTitle.indexOf(searchValue);
  321. const beforeStr = strTitle.substring(0, index);
  322. const afterStr = strTitle.slice(index + searchValue.length);
  323. const title =
  324. index > -1 ? (
  325. <span>
  326. {beforeStr}
  327. <span className="site-tree-search-value" style={{ color: 'red', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{searchValue}</span>
  328. {afterStr}
  329. </span>
  330. ) : (
  331. <span className='strTitle'>{strTitle}</span>
  332. );
  333. return <div style={{
  334. display: 'flex', flexDirection: 'row',
  335. width: '100%',
  336. justifyContent: 'flex-start', alignItems: 'center', height: 32,
  337. borderRadius: '4px',
  338. overflow: 'hidden',
  339. color: '#17181A',
  340. textOverflow: 'ellipsis',
  341. whiteSpace: 'nowrap'
  342. }}>{title}</div>
  343. }
  344. }
  345. defaultSelectedKeys={[treeData[0].children[0].code]}
  346. treeData={treeData as unknown as DataNode[]}
  347. // treeData={treeDataNew}
  348. switcherIcon={(props: any) => {
  349. const { expanded } = props;
  350. 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} />
  351. }}
  352. />
  353. )
  354. }
  355. </div>
  356. {/* <div style={{width:16,height:'92vh',background:'#F5F7FA'}}></div> */}
  357. <div className='rightContent'>
  358. <BMSPagecontainer title={false} ghost>
  359. <div className='content'>
  360. <div className='tableToolbar'>
  361. <div className='search'>
  362. <span>检索:</span><Input className='searchInput' allowClear placeholder="请输入核算单元名称" onChange={(e) => {
  363. set_tableDataSearchKeywords(e.target.value);
  364. if (e.target.value.length == 0) {
  365. set_tableDataFilterParams({ ...tableDataFilterParams, unitName: '' });
  366. }
  367. }} suffix={
  368. <IconFont type="iconsousuo" onClick={() => tableDataSearchHandle('unitName')} />
  369. }
  370. onPressEnter={(e) => {
  371. set_tableDataFilterParams({
  372. ...tableDataFilterParams,
  373. unitName: (e.target as HTMLInputElement).value
  374. });
  375. }}
  376. />
  377. </div>
  378. <div className='btnGroup'>
  379. <UpDataActBtn record type='ADD' />
  380. </div>
  381. </div>
  382. {currentSelectedTreeNode && <BMSTable actionRef={tableRef} params={tableDataFilterParams} rowKey='id' columns={tableColumn} request={(params, sort, filter) => getTableData(params, sort, filter)} />}
  383. </div>
  384. </BMSPagecontainer>
  385. </div>
  386. </div>
  387. );
  388. };
  389. export default CheckUnitMana;