index.tsx 22 KB

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