index.tsx 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  1. /*
  2. * @Author: code4eat awesomedema@gmail.com
  3. * @Date: 2023-03-03 11:30:33
  4. * @LastEditors: code4eat awesomedema@gmail.com
  5. * @LastEditTime: 2023-07-07 13:46:13
  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 BMSPagecontainer from '@/components/BMSPageContainer';
  10. import { BMSTable } from '@/components/BMSTable';
  11. import { createFromIconfontCN } from '@ant-design/icons';
  12. import { ActionType, arrayMoveImmutable, useRefFunction } from '@ant-design/pro-components';
  13. import { ModalForm, ProFormSelect, ProFormText } from '@ant-design/pro-form';
  14. import { ProColumns } from '@ant-design/pro-table';
  15. import { Dropdown, Input, MenuProps, message, Modal, Switch, Table } from 'antd';
  16. import { ColumnsType, TableRowSelection } from 'antd/es/table/interface';
  17. import Transfer, { TransferItem, TransferProps } from 'antd/es/transfer';
  18. import React from 'react';
  19. import { useEffect, useImperativeHandle, useRef, useState } from 'react';
  20. import difference from 'lodash/difference';
  21. import { getReportColumn, getClolumnTableData, addReport, editReport, editReportTbaleData, delLeftReportData } from './service';
  22. import './style.less';
  23. import { addReportTableList, getReportListTableData, getReportListType } from '../reportListMana/service';
  24. import { SortableContainer, SortableElement, SortableHandle } from 'react-sortable-hoc';
  25. import '../../../../utils/zhongtaiB'
  26. const IconFont = createFromIconfontCN({
  27. scriptUrl: '',
  28. });
  29. var temp_dataSource: any[] = [];
  30. const ReportSetting = () => {
  31. const [tableDataFilterParams, set_tableDataFilterParams] = useState<any | undefined>();
  32. const [tableDataSearchKeywords, set_tableDataSearchKeywords] = useState<string>('');
  33. const [typeList, set_typeList] = useState<any[]>([]);
  34. const [showTypeListArr, set_showTypeListArr] = useState<any[]>([]);
  35. const [currentSelectedType, set_currentSelectedType] = useState<any | undefined>(undefined);
  36. const [dataSource, setDataSource] = useState<any[]>([]);
  37. const SortableItem = SortableElement((props: any) => <tr {...props} />);
  38. const SortContainer = SortableContainer((props: any) => <tbody {...props} />);
  39. const [currentEditLeftData, set_currentEditLeftData] = useState<any | undefined>(undefined);
  40. const [ifEditTable, set_ifEditTable] = useState(false);
  41. const tableRef = useRef<ActionType>();
  42. const DragHandle = SortableHandle(() => <img width={16} style={{ cursor: 'pointer' }} src={require('../../../../../static/tuozhuai_icon.png')} alt="" />);
  43. const column = [
  44. {
  45. title: '列名称',
  46. width: 120,
  47. ellipsis: true,
  48. dataIndex: 'columnName',
  49. },
  50. {
  51. title: '列标题',
  52. width: 160,
  53. dataIndex: 'columnHeaderText',
  54. },
  55. {
  56. title: '主键',
  57. width: 120,
  58. dataIndex: 'primaryKey',
  59. render: (_: any, record: any) => {
  60. return <Switch disabled={!ifEditTable} size='small' checked={_} onChange={(bool) => switchChangeHandle(bool, record, 'primaryKey')} />
  61. }
  62. },
  63. {
  64. title: '隐藏',
  65. width: 120,
  66. dataIndex: 'hide',
  67. render: (_: any, record: any) => {
  68. return <Switch disabled={!ifEditTable} size='small' checked={_} onChange={(bool) => switchChangeHandle(bool, record, 'hide')} />
  69. }
  70. },
  71. ]
  72. const [tableColumn, set_tableColumn] = useState<ProColumns[] | any[]>(column);
  73. const getTableData = async (params: any) => {
  74. const { reportCode } = params;
  75. if (reportCode) {
  76. const resp = await getClolumnTableData(params);
  77. if (resp) {
  78. //const dataSorted = resp.sort((prev:any,cur:any)=>prev.sort - cur.sort);
  79. setDataSource(resp);
  80. temp_dataSource = [...resp];
  81. }
  82. }
  83. }
  84. const switchChangeHandle = (checked: boolean, record: any, key: string) => {
  85. const newData = temp_dataSource.map((a: any) => {
  86. if (a.id == record.id) {
  87. return { ...a, [`${key}`]: checked ? 1 : 0 }
  88. }
  89. return a
  90. });
  91. setDataSource([...newData]);
  92. }
  93. //获取左侧单元
  94. const getPageLeftReports = async () => {
  95. const resp = await getReportColumn();
  96. if (resp) {
  97. set_typeList(resp);
  98. set_showTypeListArr(resp);
  99. }
  100. }
  101. const updateTable = async (formVal: any, type: 'EDIT' | "ADD" | 'ADD_LEFTDATA' | 'EDIT_LEFTDATA') => {
  102. // console.log({formVal,type});
  103. if (type == 'ADD_LEFTDATA') {
  104. const resp = await addReport({
  105. reportName: formVal.reportName,
  106. reportShortName: formVal.reportShortName,
  107. reportType: formVal.reportType
  108. });
  109. if (resp) {
  110. getPageLeftReports();
  111. }
  112. }
  113. if (type == 'EDIT_LEFTDATA') {
  114. const resp = await editReport({
  115. id: formVal.id,
  116. reportName: formVal.reportName,
  117. reportShortName: formVal.reportShortName,
  118. reportType: formVal.reportType
  119. });
  120. if (resp) {
  121. getPageLeftReports();
  122. }
  123. }
  124. if (type == 'EDIT') {
  125. let newDataSource = dataSource.map((a: any, index: number) => {
  126. //更新排序
  127. return { ...a, sort: index + 1 }
  128. })
  129. const resp = await editReportTbaleData(newDataSource);
  130. set_ifEditTable(false);
  131. if (resp) {
  132. getTableData({ reportCode: currentSelectedType.code });
  133. }
  134. }
  135. return true;
  136. }
  137. const UpDataActBtn = ({ record, type }: { record: any, type: 'EDIT' | 'ADD' | 'ADD_LEFTDATA' | 'EDIT_LEFTDATA' }) => {
  138. const getTrriger = () => {
  139. if (type == 'ADD') {
  140. return <span className='add'>新增</span>
  141. }
  142. if (type == 'EDIT') {
  143. return <a key="edit" >编辑</a>
  144. }
  145. if (type == 'ADD_LEFTDATA') {
  146. return (
  147. <div className='add'>
  148. <img src={require('../../../../../static/addIcon_black.png')} alt="" />
  149. </div>
  150. )
  151. }
  152. if (type == 'EDIT_LEFTDATA') {
  153. return <a key="edit" >编辑</a>
  154. }
  155. }
  156. return (
  157. <ModalForm
  158. title={type == 'ADD_LEFTDATA' ? `新增报表` : `编辑报表`}
  159. width={352}
  160. initialValues={type == 'EDIT_LEFTDATA' ? { ...record } : {}}
  161. trigger={
  162. getTrriger()
  163. }
  164. onFinish={(val) => {
  165. return updateTable(type == 'EDIT_LEFTDATA' ? { ...record, ...val } : val, type);
  166. }}
  167. >
  168. <ProFormText
  169. label='报表名称:'
  170. name='reportName'
  171. rules={[{ required: true, message: '报表名称不能为空!' }]}
  172. />
  173. <ProFormText
  174. label='报表简称:'
  175. name='reportShortName'
  176. rules={[{ required: true, message: '报表简称不能为空!' }]}
  177. />
  178. <ProFormSelect
  179. name="reportType"
  180. label="报表类型:"
  181. placeholder="请选择"
  182. request={async () => {
  183. const resp = await getReportListType();
  184. if (resp) {
  185. return resp.list.map((a: any) => ({ label: a.name, value: a.code }))
  186. }
  187. }}
  188. rules={[{ required: true, message: '列类型不能为空!' }]}
  189. />
  190. </ModalForm>
  191. )
  192. }
  193. interface DataType {
  194. key: string;
  195. title: string;
  196. description: string;
  197. disabled: boolean;
  198. tag: string;
  199. }
  200. interface TableTransferProps extends TransferProps<TransferItem> {
  201. dataSource: DataType[];
  202. leftColumns: ColumnsType<DataType>;
  203. rightColumns: ColumnsType<DataType>;
  204. record: any
  205. }
  206. const transferTableColumn: any[] = [
  207. {
  208. title: '列名称',
  209. dataIndex: 'name',
  210. with: 100,
  211. ellipsis: true,
  212. key: 'name',
  213. },
  214. {
  215. title: '列标题',
  216. width: 120,
  217. dataIndex: 'headerText',
  218. key: 'headerText',
  219. ellipsis: true
  220. },
  221. ];
  222. const addReportColumnHandle = () => {
  223. const ref = React.createRef<{ save: any; }>();
  224. Modal.confirm({
  225. title: `选择报表列`,
  226. icon: <></>,
  227. width: 750,
  228. centered: true,
  229. okText: '确定',
  230. cancelText: '取消',
  231. content: <TableTransfer
  232. ref={ref}
  233. record={undefined}
  234. leftColumns={transferTableColumn}
  235. rightColumns={transferTableColumn} dataSource={[]}
  236. ></TableTransfer>,
  237. onOk: () => {
  238. return ref.current && ref.current.save();
  239. }
  240. })
  241. }
  242. const TableTransfer = React.forwardRef(({ leftColumns, rightColumns, record, ...restProps }: TableTransferProps, ref) => {
  243. const [targetKeys, setTargetKeys] = useState<string[]>([]);
  244. const [datasource, set_datasource] = useState<any[]>([]);
  245. const [selectedKeys, setSelectedKeys] = useState<string[]>([]);
  246. //获取报表列管理
  247. const getFuncList = async () => {
  248. const resp = await getReportListTableData({ pageSize: 100000, current: 1 });
  249. if (resp) {
  250. set_datasource(resp.list);
  251. const defaultSelctedkeys = dataSource.map((item: any) => item.columnCode);
  252. setTargetKeys(defaultSelctedkeys);
  253. }
  254. }
  255. const onChange = (nextTargetKeys: string[]) => {
  256. setTargetKeys(nextTargetKeys);
  257. };
  258. const onSelectChange = (sourceSelectedKeys: string[], targetSelectedKeys: string[]) => {
  259. //console.log('sourceSelectedKeys:', sourceSelectedKeys,'targetSelectedKeys:',targetSelectedKeys);
  260. setSelectedKeys([...sourceSelectedKeys, ...targetSelectedKeys]);
  261. };
  262. useImperativeHandle(ref, () => ({
  263. save: async () => {
  264. const needData = datasource.filter(item => targetKeys.includes(item.code));
  265. const result = needData.map((a,index) => {
  266. const hasEditedInfo = dataSource.filter((c: any) => c.columnCode == a.code);
  267. return {
  268. reportCode: currentSelectedType.code,
  269. columnCode: a.code,
  270. columnHeaderText: a.headerText,
  271. columnName: a.name,
  272. sort: hasEditedInfo.length>0?hasEditedInfo[0].sort:dataSource.length+1,
  273. primaryKey:hasEditedInfo.length>0?hasEditedInfo[0].primaryKey:0,
  274. hide:hasEditedInfo.length>0?hasEditedInfo[0].hide:0,
  275. }
  276. });
  277. const resp = await addReportTableList(result);
  278. if (resp) {
  279. message.success('添加成功!');
  280. getTableData({ reportCode: currentSelectedType.code });
  281. }
  282. }
  283. }));
  284. useEffect(() => {
  285. getFuncList();
  286. }, [])
  287. return (
  288. <Transfer className='TableTransfer' showSearch
  289. titles={['待选项', '已选项']}
  290. locale={{
  291. itemUnit: '项',
  292. itemsUnit: '项',
  293. searchPlaceholder: '请输入'
  294. }}
  295. onChange={onChange}
  296. onSelectChange={onSelectChange}
  297. dataSource={datasource}
  298. rowKey={record => record.code}
  299. targetKeys={targetKeys}
  300. selectedKeys={selectedKeys}
  301. filterOption={(inputValue, item) => {
  302. return item.headerText!.indexOf(inputValue) !== -1
  303. }}
  304. >
  305. {({
  306. direction,
  307. filteredItems,
  308. onItemSelectAll,
  309. onItemSelect,
  310. selectedKeys: listSelectedKeys,
  311. disabled: listDisabled,
  312. }) => {
  313. // console.log({ filteredItems, listSelectedKeys,direction });
  314. const columns = direction === 'left' ? leftColumns : rightColumns;
  315. const rowSelection: TableRowSelection<TransferItem> = {
  316. getCheckboxProps: (item) => ({ disabled: listDisabled || item.disabled }),
  317. onSelectAll(selected, selectedRows) {
  318. const treeSelectedKeys = selectedRows.map(({ code }) => code);
  319. const diffKeys = selected
  320. ? difference(treeSelectedKeys, listSelectedKeys)
  321. : difference(listSelectedKeys, treeSelectedKeys);
  322. onItemSelectAll(diffKeys as string[], selected);
  323. },
  324. onSelect({ code }, selected) {
  325. onItemSelect(code as string, selected);
  326. },
  327. selectedRowKeys: listSelectedKeys,
  328. };
  329. return (
  330. <BMSTable
  331. rowSelection={rowSelection}
  332. columns={columns as TransferItem[]}
  333. dataSource={filteredItems}
  334. size="small"
  335. rowKey={'code'}
  336. scroll={{y:830}}
  337. tableAlertRender={false}
  338. pagination={{simple:true,pageSize:9,showTotal:()=>false}}
  339. style={{ pointerEvents: listDisabled ? 'none' : undefined }}
  340. onRow={({ code, disabled: itemDisabled }) => ({
  341. onClick: () => {
  342. if (itemDisabled || listDisabled) return;
  343. onItemSelect(code as string, !listSelectedKeys.includes(code as string));
  344. },
  345. })}
  346. />
  347. );
  348. }}
  349. </Transfer>
  350. )
  351. })
  352. const moreItems: MenuProps['items'] = [
  353. {
  354. key: '1',
  355. label: <UpDataActBtn key={'act'} record={currentEditLeftData} type='EDIT_LEFTDATA' />,
  356. },
  357. {
  358. key: '2',
  359. label: (
  360. <a onClick={async (e) => {
  361. e.preventDefault();
  362. const resp = await delLeftReportData(currentEditLeftData.id);
  363. if (resp) {
  364. getPageLeftReports();
  365. }
  366. }}>
  367. 删除
  368. </a>
  369. ),
  370. },
  371. {
  372. key: '3',
  373. label: (<a onClick={async (e) => {
  374. e.preventDefault();
  375. // 选取要复制的文本
  376. const textToCopy = currentEditLeftData.code;
  377. // 创建一个临时的textarea元素
  378. const tempTextArea = document.createElement("textarea");
  379. tempTextArea.value = textToCopy;
  380. document.body.appendChild(tempTextArea);
  381. // 选中并复制文本
  382. tempTextArea.select();
  383. document.execCommand("copy");
  384. // 移除临时元素
  385. document.body.removeChild(tempTextArea);
  386. message.success('复制成功!');
  387. }}>
  388. 复制报表code
  389. </a>),
  390. },
  391. ];
  392. const onSortEnd = useRefFunction(
  393. ({ oldIndex, newIndex }: { oldIndex: number; newIndex: number }) => {
  394. if (oldIndex !== newIndex) {
  395. const newData = arrayMoveImmutable({
  396. array: [...dataSource],
  397. fromIndex: oldIndex,
  398. toIndex: newIndex,
  399. }).filter((el) => !!el);
  400. const updatedSortArr = newData.map((item:any,index:number)=>({...item,sort:index}))
  401. setDataSource([...updatedSortArr]);
  402. }
  403. },
  404. );
  405. const DraggableContainer = (props: any) => (
  406. <SortContainer
  407. useDragHandle
  408. disableAutoscroll
  409. helperClass="row-dragging"
  410. onSortEnd={onSortEnd}
  411. {...props}
  412. />
  413. );
  414. const DraggableBodyRow = (props: any) => {
  415. const { className, style, ...restProps } = props;
  416. // function findIndex base on Table rowKey props and should always be a right array index
  417. const index = dataSource.findIndex((x) => x.id === restProps['data-row-key']);
  418. return <SortableItem index={index} {...restProps} />;
  419. };
  420. useEffect(() => {
  421. if (currentSelectedType) {
  422. set_tableDataFilterParams({ ...tableDataFilterParams, reportCode: currentSelectedType.code });
  423. getTableData({ reportCode: currentSelectedType.code });
  424. }
  425. }, [currentSelectedType])
  426. useEffect(() => {
  427. if (showTypeListArr.length > 0) {
  428. set_currentSelectedType(showTypeListArr[0]);
  429. set_tableDataFilterParams({ ...tableDataFilterParams, reportCode: showTypeListArr[0].code });
  430. }
  431. }, [showTypeListArr]);
  432. useEffect(() => {
  433. if (ifEditTable) {
  434. set_tableColumn([{
  435. title: '排序',
  436. dataIndex: 'sort',
  437. width: 60,
  438. className: 'drag-visible',
  439. render: () => <DragHandle />
  440. }, ...column,
  441. // {
  442. // title: '操作',
  443. // key: 'option',
  444. // width: 120,
  445. // valueType: 'option',
  446. // render: (_: any, record: any) => {
  447. // return [
  448. // <Popconfirm
  449. // title="是否确认移除?"
  450. // key="del"
  451. // onConfirm={() => { delData(record.id); getTableData({ reportCode: currentSelectedType.code }); }}
  452. // >
  453. // <a>移除</a>
  454. // </Popconfirm>
  455. // ]
  456. // },
  457. // }
  458. ])
  459. } else {
  460. set_tableColumn(column);
  461. }
  462. }, [ifEditTable]);
  463. useEffect(() => {
  464. temp_dataSource = [...dataSource];
  465. }, [dataSource])
  466. useEffect(() => {
  467. getPageLeftReports();
  468. }, [])
  469. return (
  470. <BMSPagecontainer title={false} className='ReportSetting'>
  471. <div className='left'>
  472. <div className='toolbar'>
  473. <Input placeholder={'报表名称'} allowClear
  474. suffix={
  475. <IconFont type="iconsousuo" />
  476. }
  477. style={{ width: 156 }}
  478. onChange={(e) => {
  479. const result = typeList.filter(item => item.reportName.indexOf(e.target.value) != -1);
  480. set_showTypeListArr(result);
  481. }}
  482. />
  483. <UpDataActBtn key={'act'} record={undefined} type='ADD_LEFTDATA' />
  484. </div>
  485. <div className='wrap'>
  486. {
  487. showTypeListArr.map((item, index) => {
  488. return (
  489. <div className={currentSelectedType ? currentSelectedType.id == item.id ? 'type on' : 'type' : 'type'}
  490. key={index}
  491. onClick={() => {
  492. if (ifEditTable) {
  493. //编辑状态还未保存
  494. Modal.confirm({
  495. title: '当前存在编辑未保存,请保存后再操作!',
  496. okText: '放弃编辑',
  497. cancelText: '继续编辑',
  498. onOk(...args) {
  499. set_ifEditTable(false);
  500. set_currentSelectedType(item);
  501. getTableData({ reportCode: item.code });
  502. },
  503. })
  504. } else {
  505. set_currentSelectedType(item)
  506. }
  507. }}
  508. >
  509. <img className='icon' src={require('../../../../../static/reportIcon.png')} alt="" />
  510. <div className='content'>
  511. <div className='name'>{item.reportName}</div>
  512. <div className='sub'>{item.reportTypeName}</div>
  513. </div>
  514. <Dropdown menu={{ items: moreItems }} placement="bottom" onOpenChange={(bool) => { bool && set_currentEditLeftData(item) }}>
  515. <div className='more'>
  516. <img src={require('../../../../../static/more_point_gray.png')} alt="" />
  517. </div>
  518. </Dropdown>
  519. </div>
  520. )
  521. })
  522. }
  523. </div>
  524. </div>
  525. <div className='right'>
  526. <div className='toolBar'>
  527. <div className='filter'>
  528. </div>
  529. <div className='btnGroup'>
  530. {!ifEditTable && <span className='manaBtn' onClick={() => set_ifEditTable(true)}>管理列</span>}
  531. {
  532. ifEditTable && (
  533. <div className='inner'>
  534. <span className='save' onClick={() => updateTable(undefined, 'EDIT')}>保存</span>
  535. <span className='add' onClick={() => addReportColumnHandle()}>添加列</span>
  536. </div>
  537. )
  538. }
  539. </div>
  540. </div>
  541. <div style={{ marginTop: 16 }}>
  542. {currentSelectedType && <BMSTable actionRef={tableRef} columns={tableColumn}
  543. scroll={{y:500}}
  544. rowKey='id' dataSource={dataSource}
  545. pagination={false}
  546. components={{
  547. body: {
  548. wrapper: DraggableContainer,
  549. row: DraggableBodyRow,
  550. },
  551. }}
  552. />}
  553. </div>
  554. </div>
  555. </BMSPagecontainer>
  556. )
  557. }
  558. export default ReportSetting;