SearchPanel.tsx 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. import React from 'react';
  2. import { Input, Button, DatePicker } from 'antd';
  3. import { SearchOutlined } from '@ant-design/icons';
  4. import { useIntl, FormattedMessage } from 'react-intl';
  5. import { useDispatch, useSelector } from 'react-redux';
  6. import dayjs from 'dayjs';
  7. import {
  8. setId,
  9. setName,
  10. setAccNo,
  11. setStartTime,
  12. setEndTime,
  13. // setStatus,
  14. setPage,
  15. setPageSize,
  16. } from '../../../states/patient/worklist/slices/searchSlice';
  17. import { fetchWorkThunk } from '../../../states/patient/worklist/slices/workSlice';
  18. import { fetchBinThunk } from '../../../states/patient/bin/slices/binSlice';
  19. import { AppDispatch, RootState } from '../../../states/store';
  20. import { WorkFilter } from '@/states/patient/worklist/types/workfilter';
  21. import { BinFilter } from '@/states/patient/bin/types/binFilter';
  22. import TimeRangeSelector from './TimeRangeSelector';
  23. // import { AnyAction } from '@reduxjs/toolkit';
  24. const { RangePicker } = DatePicker;
  25. const SearchPanel: React.FC = () => {
  26. const intl = useIntl();
  27. const dispatch = useDispatch<AppDispatch>();
  28. const id = useSelector((state: RootState) => state.search.id);
  29. const name = useSelector((state: RootState) => state.search.name);
  30. const accNo = useSelector((state: RootState) => state.search.acc_no);
  31. const startTime = useSelector((state: RootState) => state.search.start_time);
  32. const endTime = useSelector((state: RootState) => state.search.end_time);
  33. const currentKey = useSelector(
  34. (state: RootState) => state.BusinessFlow.currentKey
  35. );
  36. const productName = useSelector((state: RootState) => state.product.productName);
  37. return (
  38. <div className="flex flex-col gap-2 w-full">
  39. <Input
  40. placeholder={intl.formatMessage({
  41. id: productName === 'VETDROS' ? 'animal.searchPanel.name' : 'searchPanel.name',
  42. defaultMessage: productName === 'VETDROS' ? 'animal.searchPanel.name' : 'searchPanel.name',
  43. })}
  44. prefix={<SearchOutlined />}
  45. size="small"
  46. value={name}
  47. onChange={(e) => dispatch(setName(e.target.value))}
  48. />
  49. <Input
  50. placeholder={intl.formatMessage({
  51. id: productName === 'VETDROS' ? 'animal.searchPanel.patientId' : 'searchPanel.patientId',
  52. defaultMessage: productName === 'VETDROS' ? 'animal.searchPanel.patientId' : 'searchPanel.patientId',
  53. })}
  54. prefix={<SearchOutlined />}
  55. size="small"
  56. value={id}
  57. onChange={(e) => dispatch(setId(e.target.value))}
  58. />
  59. <Input
  60. placeholder={intl.formatMessage({
  61. id: 'searchPanel.registrationId',
  62. defaultMessage: 'searchPanel.registrationId',
  63. })}
  64. prefix={<SearchOutlined />}
  65. size="small"
  66. value={accNo}
  67. onChange={(e) => dispatch(setAccNo(e.target.value))}
  68. />
  69. <TimeRangeSelector />
  70. <RangePicker
  71. className="w-full"
  72. placeholder={[
  73. intl.formatMessage({
  74. id: 'searchPanel.startDate',
  75. defaultMessage: 'searchPanel.startDate',
  76. }),
  77. intl.formatMessage({
  78. id: 'searchPanel.endDate',
  79. defaultMessage: 'searchPanel.endDate',
  80. }),
  81. ]}
  82. size="small"
  83. value={startTime && endTime ? [dayjs(startTime), dayjs(endTime)] : null}
  84. onChange={(dates) => {
  85. if (dates && dates[0] && dates[1]) {
  86. // 使用RFC3339Nano格式
  87. dispatch(
  88. setStartTime(dates[0].format('YYYY-MM-DDTHH:mm:ss.SSS[+08:00]'))
  89. );
  90. dispatch(
  91. setEndTime(dates[1].format('YYYY-MM-DDTHH:mm:ss.SSS[+08:00]'))
  92. );
  93. } else {
  94. dispatch(setStartTime(''));
  95. dispatch(setEndTime(''));
  96. }
  97. }}
  98. />
  99. <Button
  100. type="primary"
  101. icon={<SearchOutlined />}
  102. onClick={() => {
  103. dispatch(setPage(1));
  104. dispatch(setPageSize(10));
  105. // 通用的过滤条件
  106. const commonFilters = {
  107. patient_id: id,
  108. patient_name: name,
  109. access_number: accNo,
  110. start_time: startTime,
  111. end_time: endTime,
  112. };
  113. // 根据 currentKey 调用不同的 thunk
  114. if (currentKey === 'bin') {
  115. // 回收站搜索
  116. dispatch(
  117. fetchBinThunk({
  118. page: 1,
  119. pageSize: 10,
  120. filters: commonFilters as BinFilter,
  121. })
  122. );
  123. } else {
  124. // worklist/history 搜索
  125. const status =
  126. currentKey === 'worklist' ? 'Arrived,InProgress' : 'Completed';
  127. dispatch(
  128. fetchWorkThunk({
  129. page: 1,
  130. pageSize: 10,
  131. filters: {
  132. ...commonFilters,
  133. status: status,
  134. } as WorkFilter,
  135. })
  136. );
  137. }
  138. }}
  139. >
  140. <FormattedMessage
  141. id="searchPanel.search"
  142. defaultMessage="searchPanel.search"
  143. />
  144. </Button>
  145. </div>
  146. );
  147. };
  148. export default SearchPanel;