index.tsx 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733
  1. /*
  2. * @Author: code4eat awesomedema@gmail.com
  3. * @Date: 2023-03-03 11:30:33
  4. * @LastEditors: code4eat awesomedema@gmail.com
  5. * @LastEditTime: 2025-02-28 15:18:53
  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 { createFromIconfontCN } from '@ant-design/icons';
  10. import { ModalForm, ProFormDependency, ProFormInstance, ProFormRadio, ProFormSelect, ProFormText, ProFormTextArea } from '@ant-design/pro-form';
  11. import { ActionType, ProColumns } from '@ant-design/pro-table';
  12. import { Input, message, Popconfirm, Switch, Tooltip } from 'antd';
  13. import { useEffect, useRef, useState } from 'react';
  14. import 'moment/locale/zh-cn';
  15. import { addData, applyBatchItemValueReq, delData, editData, generateTableDataReq, getCurrentHospAlldeps, getTableList } from './service';
  16. import './style.less';
  17. import React from 'react';
  18. import generateTableData from './generateTableData';
  19. import { useModel } from 'umi';
  20. import KCTable from '@/components/kcTable';
  21. const IconFont = createFromIconfontCN({
  22. scriptUrl: '',
  23. });
  24. //填报周期
  25. export const DATAFILL_PERIODTYPE = [
  26. { label: '月度', value: 1 },
  27. { label: '季度', value: 2 },
  28. { label: '年度', value: 3 },
  29. { label: '变动时', value: 4 },
  30. ];
  31. //填报主体类型
  32. export const DATAFILL_MAINTYPE = [
  33. { label: '职能部门', value: 1 },
  34. { label: '相关科室', value: 2 },
  35. ];
  36. //填报维度
  37. export const DATAFILL_DIMENSIONTYPE = [
  38. { label: '按全院 ', value: 1 },
  39. { label: '按科室', value: 2 },
  40. ];
  41. type Data = {
  42. // 键为科室/部门编码,保持字符串类型
  43. [key: string]: string;
  44. };
  45. type LabelValue = {
  46. label: string;
  47. // value 需保持为字符串编码,避免多选时因 NaN 造成同值冲突
  48. value: string;
  49. };
  50. // 全局简单缓存,避免每次打开不同弹窗都重复请求
  51. let cachedDeptOptions: LabelValue[] | null = null;
  52. export function transformToLabelValue(data: Data): LabelValue[] {
  53. const result: LabelValue[] = [];
  54. for (const key in data) {
  55. if (data.hasOwnProperty(key)) {
  56. result.push({
  57. label: data[key],
  58. value: key,
  59. });
  60. }
  61. }
  62. return result;
  63. }
  64. export const searchTree = (tree: any[], searchTerm: string) => {
  65. const searchTermLower = searchTerm.toLowerCase();
  66. function searchNode(node: any) {
  67. const matchedChildren: any[] = [];
  68. if (node.children && node.children.length > 0) {
  69. node.children.forEach((child: any) => {
  70. const matchedChild = searchNode(child);
  71. if (matchedChild) {
  72. matchedChildren.push(matchedChild);
  73. }
  74. });
  75. }
  76. if (node.responsibilityName.toLowerCase().includes(searchTermLower) || (node.responsibilityCode && node.responsibilityCode.toLowerCase().includes(searchTermLower))) {
  77. return {
  78. ...node,
  79. children: matchedChildren.length > 0 ? matchedChildren : node.children,
  80. };
  81. } else if (matchedChildren.length > 0) {
  82. return {
  83. ...node,
  84. children: matchedChildren,
  85. };
  86. }
  87. return null;
  88. }
  89. return tree.map((rootNode) => searchNode(rootNode)).filter((node) => node !== null);
  90. };
  91. const defaultYear = new Date().getFullYear();
  92. let table_columns: any[] = [];
  93. let total_tableDataSource: any[] = [];
  94. export default function FillingMana() {
  95. const { initialState, setInitialState } = useModel('@@initialState');
  96. const [tableDataFilterParams, set_tableDataFilterParams] = useState<{
  97. current: number;
  98. pageSize: number;
  99. name?: string;
  100. }>({
  101. current: 1,
  102. pageSize: 10
  103. });
  104. const [tableDataSearchKeywords, set_tableDataSearchKeywords] = useState<string>('');
  105. const tableRef = useRef<ActionType>();
  106. const detailTableRef = useRef<ActionType>();
  107. const formRef = useRef<ProFormInstance>();
  108. const [tableDataSource, set_tableDataSource] = useState<any[]>([]);
  109. const [tableColumns, set_tableColumns] = useState<ProColumns[]>([]);
  110. const [currentEditRow, set_currentEditRow] = useState<any>(undefined);
  111. const [actionType, set_actionType] = useState<'NORMAL' | 'DETAIL' | undefined>('NORMAL');
  112. const [currentEditTableRow, set_currentEditTableRow] = useState<any>(undefined);
  113. const [currentYear, set_currentYear] = useState(defaultYear);
  114. const [isFirstLoad, setIsFirstLoad] = useState(true);
  115. const tableColumns_default: ProColumns[] = [
  116. {
  117. title: '操作',
  118. key: 'option',
  119. fixed: 'right',
  120. width: 80,
  121. valueType: 'option',
  122. render: (_: any, record: any) => {
  123. return (
  124. <a
  125. key={'edit'}
  126. onClick={() => {
  127. set_currentEditTableRow(record);
  128. }}
  129. >
  130. 编辑
  131. </a>
  132. );
  133. },
  134. },
  135. ];
  136. const columns: ProColumns[] = [
  137. {
  138. title: '填报项目',
  139. ellipsis: true,
  140. dataIndex: 'name',
  141. },
  142. {
  143. title: '填报周期',
  144. ellipsis: true,
  145. dataIndex: 'periodType',
  146. renderText(code, record, index, action) {
  147. const item = DATAFILL_PERIODTYPE.find((item) => item.value === code);
  148. return item ? item.label : '';
  149. },
  150. },
  151. {
  152. title: '填报维度',
  153. ellipsis: true,
  154. dataIndex: 'dimensionType',
  155. renderText(code, record, index, action) {
  156. const item = DATAFILL_DIMENSIONTYPE.find((item) => item.value === code);
  157. return item ? item.label : '';
  158. },
  159. },
  160. {
  161. title: '填报主体类型',
  162. ellipsis: true,
  163. dataIndex: 'type',
  164. renderText(code, record, index, action) {
  165. const item = DATAFILL_MAINTYPE.find((item) => item.value === code);
  166. return item ? item.label : '';
  167. },
  168. },
  169. {
  170. title: '填报主体',
  171. ellipsis: true,
  172. dataIndex: 'typeName',
  173. renderText(_, record) {
  174. // 根据维度类型从 fillDeptList 提取名称并用逗号拼接
  175. const list = Array.isArray(record?.fillDeptList) ? record.fillDeptList : [];
  176. const names = list
  177. .map((item: any) => {
  178. if (record?.dimensionType === 2) {
  179. return item?.dimensionTypeName ?? item?.departmentName ?? '';
  180. }
  181. // 默认按全院/维度类型为 1 时取 departmentName
  182. return item?.departmentName ?? item?.dimensionTypeName ?? '';
  183. })
  184. .filter((s: string) => s);
  185. return names.join(',');
  186. },
  187. },
  188. {
  189. title: '填报单位',
  190. ellipsis: true,
  191. dataIndex: 'unit',
  192. },
  193. {
  194. title: '填报说明',
  195. ellipsis: true,
  196. dataIndex: 'description',
  197. },
  198. {
  199. title: '启用',
  200. width: 60,
  201. ellipsis: true,
  202. dataIndex: 'status',
  203. renderText(num, record) {
  204. return (
  205. <Switch
  206. size="small"
  207. checked={num}
  208. onChange={(bool) =>
  209. updateTable(
  210. {
  211. ...record,
  212. status: bool ? 1 : 0,
  213. fillDeptList: record?.fillDeptList.map((a: any) => ({ value: a.departmentCode, label: a.departmentName })),
  214. relateDeptList: record?.relateDeptList.map((a: any) => ({ value: a.departmentCode, label: a.departmentName })),
  215. },
  216. 'EDIT',
  217. )
  218. }
  219. />
  220. );
  221. },
  222. },
  223. {
  224. title: '操作',
  225. key: 'option',
  226. fixed: 'right',
  227. width: 120,
  228. valueType: 'option',
  229. render: (_: any, record: any) => {
  230. const { applyStatus } = record;
  231. return [
  232. <a
  233. key={'detail'}
  234. onClick={() => {
  235. set_currentEditRow(record);
  236. }}
  237. >
  238. 详情
  239. </a>,
  240. <UpDataActBtn record={record} type={'EDIT'} />,
  241. <Popconfirm title="是否确认删除?" key="del" onConfirm={() => delTableData(record)}>
  242. <a>删除</a>
  243. </Popconfirm>,
  244. ];
  245. },
  246. },
  247. ];
  248. const getGenerateTableData = async () => {
  249. const resp = await generateTableDataReq({ fillItemCode: currentEditRow?.code, dataYear: currentYear });
  250. if (resp) {
  251. const { itemTitles, itemDatas } = resp;
  252. const { columns, dataSource } = generateTableData(itemTitles, itemDatas, [0]);
  253. table_columns = columns;
  254. total_tableDataSource = dataSource;
  255. set_tableColumns(columns);
  256. set_tableDataSource(dataSource);
  257. }
  258. };
  259. const getTableData = async (params: any) => {
  260. const { current = 1, pageSize = 10, name } = params;
  261. const resp = await getTableList({
  262. current,
  263. pageSize,
  264. name
  265. });
  266. if (resp) {
  267. return {
  268. data: resp.list,
  269. success: true,
  270. total: resp.totalCount
  271. };
  272. }
  273. return {
  274. data: [],
  275. success: false,
  276. total: 0
  277. };
  278. };
  279. const delTableData = async (record: any) => {
  280. const resp = await delData(record.code);
  281. if (resp) {
  282. tableRef.current?.reload();
  283. }
  284. };
  285. const updateTable = async (data: any, type: 'ADD' | 'EDIT') => {
  286. try {
  287. const result = {
  288. name: data.name,
  289. type: data.type,
  290. dimensionType: data.type == 2 ? 2 : data.dimensionType,
  291. periodType: data.periodType,
  292. unit: data.unit,
  293. status: type == 'ADD' ? null : data.status,
  294. description: data.description,
  295. fillDeptList:
  296. data.fillDeptList instanceof Array
  297. ? data.fillDeptList.map((a: any) => ({ departmentCode: a.value, departmentName: a.label }))
  298. : [{ departmentCode: data.fillDeptList.value, departmentName: data.fillDeptList.label }],
  299. relateDeptList: data.type != 2 && data.dimensionType != 1 && data.relateDeptList ? data.relateDeptList.map((a: any) => ({ departmentCode: a.value, departmentName: a.label })) : [],
  300. };
  301. if (type == 'ADD') {
  302. const resp = await addData(result);
  303. if (resp) {
  304. tableRef.current?.reload();
  305. return true;
  306. }
  307. }
  308. if (type == 'EDIT') {
  309. const resp = await editData({ code: data.code, ...result });
  310. if (resp) {
  311. tableRef.current?.reload();
  312. }
  313. return true;
  314. }
  315. } catch (error) {
  316. console.log({ 'updateTable error': error });
  317. }
  318. return false;
  319. };
  320. const handleTableChange = (pagination: any) => {
  321. set_tableDataFilterParams({
  322. ...tableDataFilterParams,
  323. current: pagination.current,
  324. pageSize: pagination.pageSize
  325. });
  326. }
  327. const tableDataSearchHandle = (paramName: string) => {
  328. set_tableDataFilterParams({
  329. ...tableDataFilterParams,
  330. current: 1,
  331. [`${paramName}`]: tableDataSearchKeywords
  332. });
  333. }
  334. const detailtableDataSearchHandle = (paramName: string) => {
  335. const result = total_tableDataSource.filter((a: any) => a[`${paramName}`].indexOf(tableDataSearchKeywords) != -1);
  336. set_tableDataSource(result);
  337. };
  338. const UpDataActBtn = ({ record, type, sideHandle }: { record: any; type: 'EDIT' | 'ADD'; sideHandle?: { [key: string]: any } }) => {
  339. const actType = type;
  340. const ref = React.createRef<{ save: any }>();
  341. const [maintype, set_maintype] = useState(undefined);
  342. const [dimensionType, set_dimensionType] = useState(undefined);
  343. // 本地选项缓存,避免每次搜索触发远程过滤
  344. const [deptOptions, set_deptOptions] = useState<LabelValue[]>([]);
  345. const { commitResult } = sideHandle ? sideHandle : {};
  346. useEffect(() => {
  347. if (type !== undefined) {
  348. formRef.current?.setFieldValue('fillDeptList', []); // 清空填报主体
  349. }
  350. }, [maintype]);
  351. useEffect(() => {
  352. if (dimensionType !== undefined) {
  353. formRef.current?.setFieldValue('relateDeptList', []); // 清空填相关科室
  354. }
  355. }, [dimensionType]);
  356. // 弹窗打开时才加载选项,并使用文件级缓存
  357. const ensureDeptOptions = async () => {
  358. if (deptOptions && deptOptions.length > 0) return;
  359. if (cachedDeptOptions && cachedDeptOptions.length > 0) {
  360. set_deptOptions(cachedDeptOptions);
  361. return;
  362. }
  363. const depLists = await getCurrentHospAlldeps();
  364. const opts = depLists ? transformToLabelValue(depLists) : [];
  365. cachedDeptOptions = opts;
  366. set_deptOptions(opts);
  367. };
  368. return (
  369. <ModalForm
  370. title={`${type == 'EDIT' ? '编辑' : '新增'}`}
  371. width={352}
  372. formRef={formRef}
  373. initialValues={
  374. type == 'EDIT'
  375. ? {
  376. ...record,
  377. // 使用字符串编码,避免多选时因 NaN 造成同值冲突
  378. fillDeptList: record?.fillDeptList?.map((a: any) => ({ label: a.departmentName, value: a.departmentCode })) || [],
  379. relateDeptList: record?.relateDeptList?.map((a: any) => ({ label: a.departmentName, value: a.departmentCode })) || [],
  380. }
  381. : { periodType: 1, type: 1, dimensionType: 1 }
  382. }
  383. trigger={
  384. type == 'EDIT' ? (
  385. <a key="edit" onClick={() => ensureDeptOptions()}>编辑</a>
  386. ) : (
  387. <a className="add" onClick={() => ensureDeptOptions()}>新增</a>
  388. )
  389. }
  390. onFinish={(val) => {
  391. commitResult && commitResult();
  392. return updateTable(type == 'EDIT' ? { ...val, status: record.status } : { ...val }, type);
  393. }}
  394. modalProps={{ destroyOnClose: true }}
  395. colProps={{ span: 24 }}
  396. grid
  397. >
  398. {
  399. <>
  400. <ProFormText
  401. name="name"
  402. label="填报项目:"
  403. placeholder="请输入"
  404. // disabled={type == 'EDIT'}
  405. rules={[{ required: true, message: '填报项目不能为空!' }]}
  406. />
  407. <ProFormText name="code" label="填报编码:" hidden={type == 'ADD'} disabled={type == 'EDIT'} />
  408. <ProFormRadio.Group label="填报周期:" name="periodType" disabled={type == 'EDIT' && record.limitFlag} options={DATAFILL_PERIODTYPE} rules={[{ required: true }]} />
  409. <ProFormRadio.Group
  410. label="填报主体类型:"
  411. name="type"
  412. disabled={type == 'EDIT' && record.limitFlag}
  413. options={DATAFILL_MAINTYPE}
  414. rules={[{ required: true }]}
  415. fieldProps={{
  416. onChange(e) {
  417. set_maintype(e.target.value);
  418. },
  419. }}
  420. />
  421. <ProFormDependency name={['type']}>
  422. {({ type }) => {
  423. return (
  424. <>
  425. <ProFormSelect
  426. label="填报主体:"
  427. name="fillDeptList"
  428. disabled={actType == 'EDIT' && record.limitFlag}
  429. options={deptOptions}
  430. fieldProps={
  431. type === 2
  432. ? {
  433. mode: 'multiple', // 禁止自由录入,避免检索词生成新项
  434. maxTagCount: 'responsive',
  435. labelInValue: true,
  436. size: 'small',
  437. // 开启检索(按名称与编码匹配)
  438. showSearch: true,
  439. optionFilterProp: 'label',
  440. filterOption: (input: string, option: any) => {
  441. const label: string = (option?.label ?? '').toString();
  442. const value: string = (option?.value ?? '').toString();
  443. const kw = input.toLowerCase();
  444. return label.toLowerCase().includes(kw) || value.toLowerCase().includes(kw);
  445. },
  446. }
  447. : {
  448. labelInValue: true,
  449. size: 'small',
  450. // 开启检索(按名称与编码匹配)
  451. showSearch: true,
  452. optionFilterProp: 'label',
  453. filterOption: (input: string, option: any) => {
  454. const label: string = (option?.label ?? '').toString();
  455. const value: string = (option?.value ?? '').toString();
  456. const kw = input.toLowerCase();
  457. return label.toLowerCase().includes(kw) || value.toLowerCase().includes(kw);
  458. },
  459. }
  460. }
  461. rules={[{ required: true, message: '填报主体不能为空!' }]}
  462. />
  463. {type != 2 && (
  464. <>
  465. <ProFormRadio.Group label="填报维度:" name="dimensionType" disabled={type == 'EDIT' && record.limitFlag} options={DATAFILL_DIMENSIONTYPE} rules={[{ required: true }]} />
  466. <ProFormDependency name={['dimensionType']}>
  467. {({ dimensionType }) => {
  468. return (
  469. dimensionType == 2 && (
  470. <ProFormSelect
  471. label="相关科室:"
  472. disabled={type == 'EDIT' && record.limitFlag}
  473. name={'relateDeptList'}
  474. options={deptOptions}
  475. fieldProps={{
  476. mode: 'multiple', // 禁止自由录入
  477. maxTagCount: 'responsive',
  478. labelInValue: true,
  479. size: 'small',
  480. // 开启检索(按名称与编码匹配)
  481. showSearch: true,
  482. optionFilterProp: 'label',
  483. filterOption: (input: string, option: any) => {
  484. const label: string = (option?.label ?? '').toString();
  485. const value: string = (option?.value ?? '').toString();
  486. const kw = input.toLowerCase();
  487. return label.toLowerCase().includes(kw) || value.toLowerCase().includes(kw);
  488. },
  489. }}
  490. rules={[{ required: true, message: '相关科室不能为空!' }]}
  491. />
  492. )
  493. );
  494. }}
  495. </ProFormDependency>
  496. </>
  497. )}
  498. </>
  499. );
  500. }}
  501. </ProFormDependency>
  502. <ProFormText name="unit" label="填报值单位:" placeholder="请输入" rules={[{ required: true, message: '填报值单位不能为空!' }]} />
  503. <ProFormTextArea
  504. name="description"
  505. label="填报说明:"
  506. placeholder="请输入"
  507. fieldProps={{
  508. rows: 4,
  509. }}
  510. rules={[{ required: false }]}
  511. />
  512. </>
  513. }
  514. </ModalForm>
  515. );
  516. };
  517. useEffect(() => {
  518. if (!isFirstLoad) {
  519. getGenerateTableData();
  520. } else {
  521. setIsFirstLoad(false); // 标记首次加载已完成
  522. }
  523. }, [currentYear]);
  524. useEffect(() => {
  525. if (currentEditRow) {
  526. set_actionType('DETAIL');
  527. getGenerateTableData();
  528. } else {
  529. set_actionType('NORMAL');
  530. }
  531. }, [currentEditRow]);
  532. return (
  533. <div className="FillingMana">
  534. {actionType == 'DETAIL' && (
  535. <div className="FillingMana-detail">
  536. <div className="FillingMana-detail-header">
  537. <div className="FillingMana-detail-header-title">
  538. <div className="backBtn" onClick={() => set_currentEditRow(undefined)}>
  539. <IconFont style={{ fontSize: 15 }} type={'iconfanhui'} />
  540. </div>
  541. <span>{currentEditRow?.name}</span>
  542. </div>
  543. <div className="FillingMana-detail-header-title-sub">
  544. <span>
  545. 填报周期:
  546. {currentEditRow &&
  547. `${DATAFILL_PERIODTYPE.find((item) => item.value === currentEditRow.periodType) ? DATAFILL_PERIODTYPE.find((item) => item.value === currentEditRow.periodType)?.label : ''}`}
  548. </span>
  549. <span>
  550. 填报维度:
  551. {currentEditRow &&
  552. `${
  553. DATAFILL_DIMENSIONTYPE.find((item) => item.value === currentEditRow.dimensionType) ? DATAFILL_DIMENSIONTYPE.find((item) => item.value === currentEditRow.dimensionType)?.label : ''
  554. }`}
  555. </span>
  556. <span>填报单位:{currentEditRow?.unit}</span>
  557. </div>
  558. </div>
  559. <div className="FillingMana-detail-content">
  560. <div className="toolBar">
  561. <div className="filter">
  562. <div className="filterItem">
  563. <span className="label" style={{ whiteSpace: 'nowrap' }}>
  564. {' '}
  565. 检索:
  566. </span>
  567. <Input
  568. placeholder={'填报科室'}
  569. allowClear
  570. autoComplete="off"
  571. suffix={<IconFont type="iconsousuo" style={{ color: '#99A6BF' }} onClick={() => detailtableDataSearchHandle('dimensionName')} />}
  572. onChange={(e) => {
  573. set_tableDataSearchKeywords(e.target.value);
  574. if (e.target.value.length == 0) {
  575. set_tableDataSource(total_tableDataSource);
  576. }
  577. }}
  578. onPressEnter={(e: any) => {
  579. const result = total_tableDataSource.filter((a: any) => a.dimensionName.indexOf(e.target.value) != -1);
  580. set_tableDataSource(result);
  581. }}
  582. />
  583. </div>
  584. </div>
  585. <div className="btnGroup">
  586. {(currentEditRow?.periodType == 1 || currentEditRow?.periodType == 2) && (
  587. <div className="changeBtn">
  588. <div className="actBtn" onClick={() => set_currentYear(currentYear - 1)}>
  589. <IconFont type={'iconshuangzuo'} />
  590. </div>
  591. <span style={{ padding: '0 8px' }}>{currentYear}</span>
  592. <div className="actBtn" onClick={() => set_currentYear(currentYear + 1)}>
  593. <IconFont type={'iconshuangyou'} />
  594. </div>
  595. </div>
  596. )}
  597. </div>
  598. </div>
  599. <KCTable
  600. newVer
  601. actionRef={detailTableRef}
  602. columns={[...tableColumns, ...tableColumns_default]}
  603. scroll={{ y: 'calc(100vh - 298px)', x: `${tableColumns.length * 120}px` }}
  604. rowKey="id"
  605. dataSource={tableDataSource}
  606. pagination={false}
  607. editable={{
  608. editableKeys: currentEditTableRow ? [currentEditTableRow.id] : [],
  609. actionRender: (row, config, defaultDom) => [defaultDom.save, defaultDom.cancel],
  610. onSave: async (key, record, originRow, newLineConfig) => {
  611. let unEditableColum: any = [];
  612. const editableColumn = table_columns.filter((a: any) => {
  613. !a.editable && unEditableColum.push(a);
  614. return a.editable;
  615. });
  616. const result = editableColumn.map((a: any) => ({
  617. fillItemCode: record[`${unEditableColum[0].dataIndex}_fillItemCode`],
  618. dimensionCode: record[`${unEditableColum[0].dataIndex}_dimensionCode`],
  619. periodCode: a.key,
  620. value: record[`${a.key}`] ?? null,
  621. dataYear: currentYear,
  622. }));
  623. const resp = await applyBatchItemValueReq(result);
  624. if (resp) {
  625. set_currentEditTableRow(undefined);
  626. getGenerateTableData();
  627. }
  628. return Promise.resolve(true);
  629. },
  630. onCancel: (key, record, originRow, newLineConfig) => {
  631. set_currentEditTableRow(undefined);
  632. return Promise.resolve(true);
  633. },
  634. }}
  635. />
  636. </div>
  637. </div>
  638. )}
  639. {actionType != 'DETAIL' && (
  640. <div style={{ padding: 16, background: '#fff', borderRadius: 4 }}>
  641. <div className="toolBar">
  642. <div className="filter">
  643. <div className="filterItem">
  644. <span className="label" style={{ whiteSpace: 'nowrap' }}>
  645. {' '}
  646. 检索:
  647. </span>
  648. <Input
  649. placeholder={'填报项目'}
  650. allowClear
  651. autoComplete="off"
  652. suffix={<IconFont type="iconsousuo" style={{ color: '#99A6BF' }} onClick={() => tableDataSearchHandle('name')} />}
  653. onChange={(e) => {
  654. set_tableDataSearchKeywords(e.target.value);
  655. if (e.target.value.length == 0) {
  656. set_tableDataFilterParams({
  657. ...tableDataFilterParams,
  658. current: 1,
  659. name: '',
  660. });
  661. }
  662. }}
  663. onPressEnter={(e) => {
  664. set_tableDataFilterParams({
  665. ...tableDataFilterParams,
  666. current: 1,
  667. name: (e.target as HTMLInputElement).value,
  668. });
  669. }}
  670. />
  671. </div>
  672. </div>
  673. <div className="btnGroup">
  674. <UpDataActBtn record={undefined} type={'ADD'} />
  675. </div>
  676. </div>
  677. <KCTable
  678. columns={columns}
  679. scroll={{ y: `calc(100vh - 250px)` }}
  680. rowKey="id"
  681. newVer
  682. params={tableDataFilterParams}
  683. request={(params) => getTableData(params)}
  684. onChange={handleTableChange}
  685. />
  686. </div>
  687. )}
  688. </div>
  689. );
  690. }