transform.tsx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. import React, { Key, useEffect, useImperativeHandle, useState } from "react";
  2. import { Transfer } from 'antd'
  3. import { TransferItem, TransferProps } from 'antd/es/transfer';
  4. import { ColumnsType } from 'antd/es/table';
  5. import { difference } from "lodash";
  6. import { TableRowSelection } from 'antd/es/table/interface';
  7. import { KCIMTable } from "@/components/KCIMTable";
  8. import { ProColumns } from "@ant-design/pro-components";
  9. import { Tabs,Tree } from 'antd';
  10. import { log } from "mathjs";
  11. import { getAccountingSubjectList } from "../../accountingAccountSet/accountingSubMana/service";
  12. import { getApportionmentLevelList } from "../../costAllocationSet/allocationLevelSet/service";
  13. import { getResponsibilityCenterList } from "../../responsibilityCenterSet/responsibilityCenter/service";
  14. import { findAllParents, renameChildListToChildren, searchLeaves } from "@/utils/tooljs";
  15. import { getHasSetReportRelation } from "./service";
  16. interface TableTransferProps extends TransferProps<TransferItem> {
  17. leftColumns: ProColumns[];
  18. rightColumns: ProColumns[];
  19. record: any,
  20. settingType: number,
  21. keyName: string,
  22. onSave: (selectedKeys: Key[], selectedRowKeys: any[], settingType: number) => void;
  23. }
  24. const flattenTreeData = (treeData:any[], childKey = 'children', parentKey = 'parentId') => {
  25. let result:any[] = [];
  26. function flatten(node:any, parentId = null) {
  27. // 创建一个新对象,包含原始节点的所有属性,除了 children,并添加 parentId
  28. const { [childKey]: _, ...flatNode } = node;
  29. result.push({ ...flatNode, [parentKey]: parentId });
  30. // 如果节点有子节点,递归扁平化这些子节点
  31. if (node[childKey] && node[childKey].length > 0) {
  32. node[childKey].forEach((childNode:any) => flatten(childNode, node.id));
  33. }
  34. }
  35. // 遍历每个根级节点
  36. treeData.forEach(node => flatten(node));
  37. return result;
  38. }
  39. function buildTree(flatData:any[], rootParentId = null, idKey = 'id', parentKey = 'parentId', childrenKey = 'children') {
  40. const nodeMap = new Map();
  41. // 首先,将所有节点存储到一个 Map 中,以便快速访问
  42. flatData.forEach(node => nodeMap.set(node[idKey], { ...node }));
  43. const tree:any[] = [];
  44. flatData.forEach(node => {
  45. const parentNode = nodeMap.get(node[parentKey]);
  46. if (parentNode) {
  47. // 检查父节点是否已经有了 children 属性
  48. if (!parentNode[childrenKey]) {
  49. parentNode[childrenKey] = [];
  50. }
  51. // 将当前节点添加到父节点的 children 数组中
  52. parentNode[childrenKey].push(nodeMap.get(node[idKey]));
  53. } else if (node[parentKey] === rootParentId) {
  54. // 如果没有父节点且 parentId 与根 parentId 匹配,则为根节点
  55. tree.push(nodeMap.get(node[idKey]));
  56. }else{
  57. tree.push(nodeMap.get(node[idKey]));
  58. }
  59. });
  60. // 清除那些 children 长度为 0 的节点的 children 属性
  61. function clearEmptyChildren(node:any) {
  62. if (node[childrenKey] && node[childrenKey].length === 0) {
  63. delete node[childrenKey];
  64. } else if (node[childrenKey]) {
  65. node[childrenKey].forEach(clearEmptyChildren);
  66. }
  67. }
  68. tree.forEach(clearEmptyChildren);
  69. return tree;
  70. }
  71. const TableTransfer = React.forwardRef(({ leftColumns, rightColumns, keyName, record, settingType, onSave, ...restProps }: TableTransferProps, ref) => {
  72. const [_data, _set_data] = useState<any>();
  73. const [targetKeys, setTargetKeys] = useState<string[]>(record.accountingIds ? [...((record.accountingIds).map((a: string) => Number(a)))] : []);
  74. const [datasource, set_datasource] = useState<any[]>([]);
  75. const [selectedKeys, setSelectedKeys] = useState<string[]>(record.accountingIds ? [...((record.accountingIds).map((a: string) => Number(a)))] : []);
  76. const [accountType, set_accountType] = useState(1);
  77. const [tabs, set_tabs] = useState<any[]>([]);
  78. //获取列表
  79. const getFuncList = async () => {
  80. if (settingType == 1) {
  81. const resp = await getAccountingSubjectList({ pageSize: 500, current: 1, accountType });
  82. if (resp) {
  83. const initData = await getHasSetReportRelation({ reportId: record.id, relation: settingType });
  84. if (initData) {
  85. const hasSelectedKeys = initData.map((a: any) => a.code);
  86. console.log(flattenTreeData(resp.list));
  87. const hasSelectedRows = flattenTreeData(resp.list).filter((a: any) => hasSelectedKeys.includes(a.accountingCode));
  88. const selectedKeys = hasSelectedRows.map((a: any) => a.id)
  89. // setSelectedKeys(selectedKeys);
  90. setTargetKeys(selectedKeys);
  91. }
  92. set_datasource(resp.list);
  93. _set_data(resp.list);
  94. }
  95. }
  96. if (settingType == 2) {
  97. const resp = await getApportionmentLevelList({ pageSize: 500, current: 1 });
  98. if (resp) {
  99. const initData = await getHasSetReportRelation({ reportId: record.id, relation: settingType });
  100. if (initData) {
  101. const hasSelectedKeys = initData.map((a: any) => Number(a.id));
  102. const hasSelectedRows = resp.list.filter((a: any) => hasSelectedKeys.includes(a.id));
  103. const selectedKeys = hasSelectedRows.map((a: any) => a.id)
  104. // setSelectedKeys(selectedKeys);
  105. setTargetKeys(selectedKeys);
  106. }
  107. set_datasource(resp.list);
  108. _set_data(resp.list);
  109. }
  110. }
  111. if (settingType == 3) {
  112. const resp = await getResponsibilityCenterList({ pageSize: 500, current: 1 });
  113. //const opendedArr = renameChildListToChildren(resp.list, 'child');
  114. if (resp) {
  115. const initData = await getHasSetReportRelation({ reportId: record.id, relation: settingType });
  116. if (initData) {
  117. const hasSelectedKeys = initData.map((a: any) => a.code);
  118. const hasSelectedRows = resp.list.filter((a: any) => hasSelectedKeys.includes(a.responsibilityCode));
  119. const selectedKeys = hasSelectedRows.map((a: any) => a.id)
  120. // setSelectedKeys(selectedKeys);
  121. setTargetKeys(selectedKeys);
  122. }
  123. set_datasource(renameChildListToChildren(resp.list, 'child'));
  124. _set_data(renameChildListToChildren(resp.list, 'child'));
  125. }
  126. }
  127. }
  128. const onChange = (nextTargetKeys: string[]) => {
  129. // console.log({ nextTargetKeys });
  130. setTargetKeys(nextTargetKeys);
  131. };
  132. const onSelectChange = (sourceSelectedKeys: string[], targetSelectedKeys: string[]) => {
  133. // console.log('sourceSelectedKeys:', sourceSelectedKeys, 'targetSelectedKeys:', targetSelectedKeys);
  134. setSelectedKeys([...sourceSelectedKeys, ...targetSelectedKeys]);
  135. };
  136. useImperativeHandle(ref, () => ({
  137. save: async () => {
  138. if(settingType == 1||settingType == 3){
  139. const items = flattenTreeData(datasource).filter(a => targetKeys.includes(a[`${keyName}`]));
  140. onSave(targetKeys, items, settingType);
  141. }else{
  142. const items = datasource.filter(a => targetKeys.includes(a[`${keyName}`]));
  143. onSave(targetKeys, items, settingType);
  144. }
  145. }
  146. }));
  147. const onTabChanged = (key: string) => {
  148. set_accountType(Number(key));
  149. }
  150. useEffect(() => {
  151. getFuncList();
  152. }, [accountType]);
  153. useEffect(() => {
  154. set_tabs([
  155. {
  156. label: '收入',
  157. key: 1,
  158. },
  159. {
  160. label: '支出',
  161. key: 2,
  162. },
  163. ])
  164. }, []);
  165. return (
  166. <div>
  167. {settingType == 1 && (
  168. <Tabs
  169. defaultActiveKey={tabs.length > 0 ? tabs[0].key : undefined}
  170. items={tabs}
  171. key={'key'}
  172. onChange={(key) => onTabChanged(key)}
  173. />
  174. )}
  175. <Transfer className='TableTransfer' showSearch
  176. titles={['待选项', '已选项']}
  177. locale={{
  178. itemUnit: '项',
  179. itemsUnit: '项',
  180. searchPlaceholder: '请输入',
  181. }}
  182. oneWay={false}
  183. onChange={onChange}
  184. onSelectChange={onSelectChange}
  185. dataSource={settingType == 2?datasource:flattenTreeData(datasource)}
  186. rowKey={record => record[`${keyName}`]}
  187. targetKeys={targetKeys}
  188. selectedKeys={selectedKeys}
  189. filterOption={(inputValue, item) => {
  190. if(settingType == 1){
  191. return item['accountingName']!.indexOf(inputValue) !== -1
  192. }
  193. if(settingType == 2){
  194. return item['shareName']!.indexOf(inputValue) !== -1
  195. }
  196. if(settingType == 3){
  197. return item['responsibilityName']!.indexOf(inputValue) !== -1
  198. }
  199. return false
  200. }}
  201. >
  202. {({
  203. direction,
  204. filteredItems,
  205. onItemSelectAll,
  206. onItemSelect,
  207. selectedKeys: listSelectedKeys,
  208. disabled: listDisabled,
  209. }) => {
  210. const columns = direction === 'left' ? leftColumns : rightColumns;
  211. const rowSelection: TableRowSelection<TransferItem> = {
  212. getCheckboxProps: (item) => ({ disabled: listDisabled || item.disabled }),
  213. onSelectAll(selected, selectedRows) {
  214. const treeSelectedKeys = selectedRows.map((a) => a[`${keyName}`]);
  215. const diffKeys = selected
  216. ? difference(treeSelectedKeys, listSelectedKeys)
  217. : difference(listSelectedKeys, treeSelectedKeys);
  218. onItemSelectAll(diffKeys as string[], selected);
  219. },
  220. onSelect(item, selected) {
  221. onItemSelect(item[`${keyName}`], selected);
  222. },
  223. selectedRowKeys: listSelectedKeys,
  224. };
  225. return (
  226. <KCIMTable
  227. rowSelection={rowSelection}
  228. columns={columns as TransferItem[]}
  229. dataSource={settingType == 2?filteredItems:direction == 'left'?buildTree(filteredItems):filteredItems}
  230. size="small"
  231. bordered={false}
  232. rowKey={keyName}
  233. scroll={{ y: 280 }}
  234. pagination={{ showTitle: false, pageSize: 9, showLessItems: false, simple: true, showTotal: () => false }}
  235. tableAlertRender={false}
  236. style={{ pointerEvents: listDisabled ? 'none' : undefined }}
  237. onRow={(row) => ({
  238. onClick: () => {
  239. if (row.itemDisabled || listDisabled) return;
  240. onItemSelect(row[`${keyName}`], !listSelectedKeys.includes(row[`${keyName}`]));
  241. },
  242. })}
  243. />
  244. )
  245. }}
  246. </Transfer>
  247. </div>
  248. )
  249. });
  250. export default TableTransfer