index.tsx 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  1. /*
  2. * @Author: code4eat awesomedema@gmail.com
  3. * @Date: 2023-03-03 11:30:33
  4. * @LastEditors: code4eat awesomedema@gmail.com
  5. * @LastEditTime: 2024-08-16 10:34:01
  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 KCIMPagecontainer from '@/components/KCIMPageContainer';
  10. import { KCIMTable } from '@/components/KCIMTable';
  11. import { formatMoneyNumber } from '@/utils/format';
  12. import { createFromIconfontCN } from '@ant-design/icons';
  13. import FormItem from 'antd/es/form/FormItem';
  14. import { ActionType, DrawerForm, ProFormInstance, ProFormText, ProTable, TableDropdown } from '@ant-design/pro-components';
  15. import { ModalForm, ProFormDigit, ProFormSelect, ProFormSwitch } from '@ant-design/pro-form'
  16. import { ProColumns } from '@ant-design/pro-table';
  17. import type { MenuProps } from 'antd';
  18. import { Input, message, Dropdown, Modal, Popconfirm, Drawer, Breadcrumb } from 'antd';
  19. import { useEffect, useRef, useState } from 'react';
  20. import 'moment/locale/zh-cn';
  21. import locale from 'antd/es/date-picker/locale/zh_CN';
  22. import { addData, delData, editData, getAllNeedMatchItems, getDepartmentListsReq, getTableDataReq, importDataPost, mapItemAndStandItem } from './service';
  23. import './style.less';
  24. import KCIMUpload from '@/components/KCIMUpload';
  25. import { downloadTemplateReq } from '@/utils/tooljs';
  26. import { getStandItemList } from '../standardProjectMana/service';
  27. import { getDicDataBySysId } from '@/services/getDic';
  28. import { KcimCenterSysId } from '@/constant';
  29. import { Setting } from './components/setting';
  30. import KCIMDrawerForm from '@/components/KCIMDrawerForm';
  31. import { MatchPage } from './components/match';
  32. const IconFont = createFromIconfontCN({
  33. scriptUrl: '',
  34. });
  35. let currentRow: any = undefined;
  36. export const fetchAllDepartments = async (params:any) => {
  37. const {keyWords} = params;
  38. let currentPage = 1;
  39. const pageSize = 500;
  40. let allDepartments: any[] = [];
  41. let hasMore = true;
  42. do {
  43. const resp = await getDepartmentListsReq({ current: currentPage, pageSize,departName:keyWords });
  44. if (resp) {
  45. const { list = [] } = resp;
  46. allDepartments = [...allDepartments, ...list];
  47. if (list.length < pageSize) {
  48. hasMore = false; // 如果返回的数据少于每页数量,说明已经是最后一页
  49. } else {
  50. currentPage++; // 否则继续请求下一页
  51. }
  52. } else {
  53. hasMore = false; // 如果请求失败,终止循环
  54. }
  55. } while (hasMore);
  56. return allDepartments.map((a: any) => ({ label:`${a.name}(${a.code})`, value: a.code }));
  57. };
  58. export default function ChargeItemsMana() {
  59. const [tableDataFilterParams, set_tableDataFilterParams] = useState<any | undefined>();
  60. const [tableDataSearchKeywords, set_tableDataSearchKeywords] = useState<string>('');
  61. const tableRef = useRef<ActionType>();
  62. const formRef = useRef<ProFormInstance>();
  63. const [stopStat, set_stopStat] = useState(0);
  64. const [drawerVisible, set_drawerVisible] = useState(false);
  65. const [drawerType, set_drawerType] = useState(1);
  66. const [currentSelectRow, set_currentSelectRow] = useState(undefined);
  67. const [ifBatchMatch, set_ifBatchMatch] = useState(false);
  68. const columns: ProColumns[] = [
  69. {
  70. title: '科室',
  71. dataIndex: 'departmentName',
  72. width: 160,
  73. renderText(text, record, index, action) {
  74. return `[${record.departmentCode}]${record.departmentName}`
  75. },
  76. },
  77. {
  78. title: '收费项目编码',
  79. dataIndex: 'code',
  80. width: 100
  81. },
  82. {
  83. title: '收费项目名称',
  84. dataIndex: 'name',
  85. width: 260
  86. },
  87. {
  88. title: '国家编码',
  89. dataIndex: 'nationalCode',
  90. width: 100
  91. },
  92. {
  93. title: '项目类别',
  94. dataIndex: 'type',
  95. width: 100
  96. },
  97. {
  98. title: '项目分类',
  99. dataIndex: 'itemTypeName',
  100. width: 100
  101. },
  102. {
  103. title: '康程分类',
  104. dataIndex: 'kcCodeName',
  105. width: 280
  106. },
  107. {
  108. title: '标准项目编码',
  109. dataIndex: 'standItemCode',
  110. width: 100
  111. },
  112. {
  113. title: '标准项目名称',
  114. dataIndex: 'standItemName',
  115. width: 260
  116. },
  117. {
  118. title: '参与人员',
  119. dataIndex: 'empMaps',
  120. width: 260,
  121. renderText(arr, record, index, action) {
  122. if (arr)
  123. return arr.reduce((prev: any, cur: any) => `${prev.length > 0 ? prev + '|' : prev}${cur.empTypeCodeName + '*' + cur.num + '*' + cur.executeTime}`, '')
  124. },
  125. },
  126. {
  127. title: '使用设备',
  128. dataIndex: 'equipmentMaps',
  129. width: 260,
  130. renderText(arr, record, index, action) {
  131. if (arr)
  132. return arr.reduce((prev: any, cur: any) => `${prev.length > 0 ? prev + '|' : prev}${cur.equipmentCodeName + '*' + cur.num + '*' + cur.executeTime}`, '')
  133. },
  134. },
  135. {
  136. title: '使用空间',
  137. dataIndex: 'spaceMaps',
  138. width: 260,
  139. renderText(arr, record, index, action) {
  140. if (arr)
  141. return arr.reduce((prev: any, cur: any) => `${prev.length > 0 ? prev + '|' : prev}${cur.spaceCodeName + '*' + cur.num + '*' + cur.executeTime}`, '')
  142. },
  143. },
  144. {
  145. title: '计价药材',
  146. dataIndex: 'valuation',
  147. width: 260,
  148. renderText(arr) {
  149. if (arr)
  150. return arr.reduce((prev: any, cur: any) => `${prev.length > 0 ? prev + '|' : prev}${cur.code + '*' + cur.name + '*' + cur.num}`, '')
  151. },
  152. },
  153. {
  154. title: '不计价药材成本',
  155. dataIndex: 'noValuation',
  156. width: 260,
  157. renderText(arr, record, index, action) {
  158. if (arr)
  159. return arr.reduce((prev: any, cur: any) => `${prev.length > 0 ? prev + '|' : prev}${cur.code + '*' + cur.name + '*' + cur.num}`, '')
  160. },
  161. },
  162. {
  163. title: '单价',
  164. dataIndex: 'price',
  165. width: 90
  166. },
  167. {
  168. title: '操作',
  169. key: 'option',
  170. width: 120,
  171. fixed: 'right',
  172. valueType: 'option',
  173. render: (_: any, record: any) => {
  174. const items: MenuProps['items'] = [
  175. {
  176. key: '1',
  177. label: (
  178. <UpDataActBtn key={'act'} record={record} type='EDIT' />
  179. ),
  180. },
  181. // {
  182. // key: '2',
  183. // label: (
  184. // <a >
  185. // 同步设置
  186. // </a>
  187. // ),
  188. // },
  189. {
  190. key: '3',
  191. label: (
  192. <Popconfirm
  193. title="是否确认删除?"
  194. key="del"
  195. onConfirm={() => delTableData(record)}
  196. >
  197. <a>删除</a>
  198. </Popconfirm>
  199. ),
  200. },
  201. ];
  202. return [
  203. // <UpDataActBtn key={'act'} record={record} type='EDIT' />,
  204. // <Popconfirm
  205. // title="是否确认删除?"
  206. // key="del"
  207. // onConfirm={() => delTableData(record)}
  208. // >
  209. // <a>删除</a>
  210. // </Popconfirm>
  211. <a key='1' onClick={() => { set_currentSelectRow(record); currentRow = record; set_drawerType(2); set_drawerVisible(true) }}>匹配</a>,
  212. <a key='2' onClick={() => { currentRow = record; set_drawerType(1); set_currentSelectRow(record);set_drawerVisible(true); }}>设置</a>,
  213. <Dropdown menu={{ items }} placement="bottomLeft" arrow>
  214. <a><IconFont type="icongengduochuizhi" style={{ color: '#3377FF', width: 16, height: 16 }} /></a>
  215. </Dropdown>
  216. ]
  217. },
  218. },
  219. ]
  220. const getTableData = async (params: any) => {
  221. const resp = await getTableDataReq({ ...params, type: stopStat });
  222. if (resp) {
  223. return {
  224. data: resp.list,
  225. success: true,
  226. total: resp.totalCount,
  227. pageSize: resp.pageSize,
  228. totalPage: resp.totalPage,
  229. }
  230. }
  231. return []
  232. }
  233. const delTableData = async (record: any) => {
  234. const resp = await delData(record.id);
  235. if (resp) {
  236. message.success('操作成功!');
  237. tableRef.current?.reload();
  238. // message.success('操作成功!');
  239. }
  240. }
  241. const updateTable = async (formVal: any, type: 'EDIT' | "ADD") => {
  242. const result = {
  243. ...formVal,
  244. standItemCode: formVal.standItem ? formVal.standItem.label : undefined,
  245. standItemName: formVal.standItem ? formVal.standItem.label : undefined,
  246. departmentCode: formVal.department ? formVal.department.value : undefined,
  247. departmentName: formVal.department ? formVal.department.label : undefined,
  248. department:null
  249. }
  250. if (type == 'ADD') {
  251. const resp = await addData(result);
  252. if (resp) {
  253. tableRef.current?.reload();
  254. message.success('操作成功!');
  255. }
  256. }
  257. if (type == 'EDIT') {
  258. const resp = await editData({ ...result });
  259. if (resp) {
  260. tableRef.current?.reload();
  261. message.success('操作成功!');
  262. }
  263. }
  264. return true;
  265. }
  266. const UpDataActBtn = ({ record, type }: { record: any, type: 'EDIT' | 'ADD' }) => {
  267. return (
  268. <ModalForm
  269. title={`${type == 'EDIT' ? '编辑' : '新增'}收费项目`}
  270. width={350}
  271. formRef={formRef}
  272. initialValues={type == 'EDIT' ? {
  273. ...record, standItem: record.standItemCode,
  274. department:record.departmentCode
  275. } : {}}
  276. trigger={
  277. type == 'EDIT' ? <a key="edit" >编辑</a> : <span className='add'>新增</span>
  278. }
  279. onFinish={(val) => {
  280. return updateTable(type == 'EDIT' ? { ...record, ...val } : { ...val }, type);
  281. }}
  282. modalProps={{ destroyOnClose: true }}
  283. colProps={{ span: 24 }}
  284. grid
  285. >
  286. <ProFormSelect
  287. name="department"
  288. label="科室:"
  289. placeholder="请输入"
  290. params={['departName']}
  291. request={fetchAllDepartments}
  292. fieldProps={{labelInValue:true,showSearch:true}}
  293. rules={[{ required: false, message: '科室不能为空!' }]}
  294. />
  295. <ProFormText
  296. name="code"
  297. label="收费项目编码:"
  298. placeholder="请输入"
  299. rules={[{ required: true, message: '收费项目编码不能为空!' }]}
  300. />
  301. <ProFormText
  302. name="name"
  303. label="收费项目名称:"
  304. placeholder="请输入"
  305. rules={[{ required: true, message: '收费项目名称不能为空!' }]}
  306. />
  307. <ProFormSelect
  308. name="itemType"
  309. label="项目分类:"
  310. placeholder="请输入"
  311. request={async () => {
  312. const resp = await getDicDataBySysId(KcimCenterSysId, 'MED_SERVICE_ITEM_TYPE');
  313. if (resp) {
  314. const { dataVoList = [] } = resp;
  315. return dataVoList.map((a: any) => ({ label: a.name, value: a.code }))
  316. }
  317. return []
  318. }}
  319. rules={[{ required: false, message: '项目分类不能为空!' }]}
  320. />
  321. <ProFormText
  322. name="type"
  323. label="收费项目类别:"
  324. placeholder="请输入"
  325. // rules={[{ required: true, message: '收费项目类别不能为空!' }]}
  326. />
  327. <ProFormText
  328. name="nationalCode"
  329. label="国家编码:"
  330. placeholder="请输入"
  331. />
  332. <ProFormSelect
  333. name="standItem"
  334. label="标准项目名称:"
  335. placeholder="请选择"
  336. showSearch
  337. fieldProps={{
  338. labelInValue: true,
  339. }}
  340. request={async ({ keyWords }) => {
  341. const resp = await getStandItemList({ name: keyWords, pageSize: 100, current: 1 });
  342. if (resp) {
  343. return resp.list.map((a: any) => ({ label: a.name, value: a.code }))
  344. } else {
  345. return []
  346. }
  347. }}
  348. />
  349. <ProFormDigit
  350. name="price"
  351. label="单价:"
  352. placeholder="请输入"
  353. rules={[{ required: true, message: '单价不能为空!' }]}
  354. />
  355. </ModalForm>
  356. )
  357. }
  358. const tableDataSearchHandle = (paramName: string) => {
  359. set_tableDataFilterParams({
  360. ...tableDataFilterParams,
  361. [`${paramName}`]: tableDataSearchKeywords
  362. })
  363. }
  364. const downloadTemplate = async () => {
  365. await downloadTemplateReq('/costAccount/setting/exportItem');
  366. };
  367. const closeDrawer = () => {
  368. set_drawerVisible(false);
  369. }
  370. const switchBatchHandle = (bool:boolean)=>{
  371. set_ifBatchMatch(bool);
  372. }
  373. const importData = () => {
  374. return (
  375. <ModalForm
  376. width={360}
  377. title={`导入数据`}
  378. trigger={
  379. <a className="import" key="3">
  380. 导入
  381. </a>
  382. }
  383. submitter={{
  384. render: (props, defaultDoms) => {
  385. const needBtn = defaultDoms.filter((b) => {
  386. return b.key != 'rest';
  387. });
  388. return [
  389. ...needBtn,
  390. ];
  391. },
  392. }}
  393. onFinish={async (values) => {
  394. const {
  395. importFile: { fileList },
  396. } = values;
  397. let formData = new FormData();
  398. formData.append('file', fileList[0].originFileObj);
  399. const resp = await importDataPost(formData);
  400. if (resp) {
  401. tableRef.current?.reload();
  402. return true;
  403. }
  404. }}
  405. >
  406. <FormItem name={'importFile'}>
  407. <KCIMUpload downloadTemplateFile={() => downloadTemplate()} />
  408. </FormItem>
  409. </ModalForm>
  410. );
  411. };
  412. const batchMatchInit = async () => {
  413. const resp = await getAllNeedMatchItems();
  414. if (resp) {
  415. let needItem = undefined;
  416. for (const item of resp) {
  417. if (!item.match) {
  418. set_currentSelectRow(item);
  419. needItem = item;
  420. break; // 满足条件后退出循环
  421. }
  422. }
  423. if(!needItem){
  424. set_currentSelectRow(resp[0]);
  425. }
  426. }
  427. }
  428. useEffect(() => {
  429. if (ifBatchMatch) {
  430. batchMatchInit();
  431. }
  432. }, [ifBatchMatch]);
  433. return (
  434. <>
  435. <div style={{ padding: '0 16px', paddingTop: 16 }}>
  436. <Breadcrumb>
  437. <Breadcrumb.Item>收费项目设置</Breadcrumb.Item>
  438. <Breadcrumb.Item>
  439. {ifBatchMatch ? <a onClick={()=>set_ifBatchMatch(false)}>收费项目管理</a> : '收费项目管理'}
  440. </Breadcrumb.Item>
  441. {ifBatchMatch && <Breadcrumb.Item>项目匹配</Breadcrumb.Item>}
  442. </Breadcrumb>
  443. </div>
  444. <KCIMPagecontainer className='ChargeItemsMana' title={false} style={{padding:ifBatchMatch?0:16}}>
  445. <Drawer
  446. width={drawerType == 1 ? 800 : 1200}
  447. title={false}
  448. open={drawerVisible}
  449. afterOpenChange={bool => {
  450. set_drawerVisible(bool);
  451. if (!bool){ set_currentSelectRow(undefined); tableRef.current?.reload(); }
  452. }}
  453. headerStyle={{ height: 0, padding: 0, overflow: 'hidden' }}
  454. bodyStyle={{ padding: 0 }}
  455. destroyOnClose={true}
  456. >
  457. {drawerType == 1 && <Setting record={currentSelectRow} onVisibleChange={(bool: boolean) => set_drawerVisible(bool)} />}
  458. {drawerType == 2 && <MatchPage closeDrawer={closeDrawer} record={currentSelectRow} onVisibleChange={(bool: boolean) => set_drawerVisible(bool)} />}
  459. </Drawer>
  460. {
  461. !ifBatchMatch ? (
  462. <>
  463. <div className='toolBar'>
  464. <div className='filter'>
  465. <div className='filterItem'>
  466. <span className='label' style={{ whiteSpace: 'nowrap' }}> 检索:</span>
  467. <Input placeholder={'项目名称/国家编码'} allowClear
  468. suffix={
  469. <IconFont type="iconsousuo" style={{ color: '#99A6BF' }} onClick={() => tableDataSearchHandle('name')} />
  470. }
  471. onChange={(e) => {
  472. set_tableDataSearchKeywords(e.target.value);
  473. if (e.target.value.length == 0) {
  474. set_tableDataFilterParams({
  475. ...tableDataFilterParams,
  476. name: ''
  477. });
  478. }
  479. }}
  480. onPressEnter={(e) => {
  481. set_tableDataFilterParams({
  482. ...tableDataFilterParams,
  483. name: (e.target as HTMLInputElement).value
  484. });
  485. }}
  486. />
  487. </div>
  488. </div>
  489. <div className='btnGroup'>
  490. <span style={{ paddingRight: 16 }}><ProFormSwitch noStyle fieldProps={{
  491. size: 'small', onChange: (bool) => {
  492. set_stopStat(bool ? 1 : 0);
  493. tableRef.current?.reload();
  494. }
  495. }} />只显示未对照项目</span>
  496. {/* <span className='mapBtn' onClick={() => mapBtnHandle()}>对照</span> */}
  497. <span className='mapBtn' onClick={() => set_ifBatchMatch(true)}>批量匹配</span>
  498. {importData()}
  499. <UpDataActBtn record type='ADD' />
  500. </div>
  501. </div>
  502. <div style={{ marginTop: 16 }}>
  503. <KCIMTable
  504. scroll={{ x: 1500,y:`calc(100vh - 271px)` }}
  505. columns={columns as ProColumns[]}
  506. actionRef={tableRef} rowKey='id' params={tableDataFilterParams}
  507. request={(params) => getTableData(params)}
  508. // expandable={{ expandedRowRender }}
  509. />
  510. </div>
  511. </>
  512. ):(
  513. currentSelectRow&&<MatchPage closeDrawer={closeDrawer} switchBatchHandle={switchBatchHandle} single={false} record={currentSelectRow} onVisibleChange={(bool: boolean) => set_drawerVisible(bool)} />
  514. )
  515. }
  516. </KCIMPagecontainer>
  517. </>
  518. )
  519. }