ActionPanel.tsx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. import React from 'react';
  2. import { Button, Tooltip, Modal, message } from 'antd';
  3. import { useDispatch, useSelector } from 'react-redux';
  4. import {
  5. deleteWorkThunk,
  6. lockWorkInWorklistThunk,
  7. } from '@/states/patient/worklist/slices/workSlice';
  8. import { switchToSendPanel } from '@/states/patient/worklist/slices/historyPanelSwitchSlice';
  9. import { FormattedMessage } from 'react-intl';
  10. import { AppDispatch, RootState, useAppSelector } from '@/states/store';
  11. import Icon from '@/components/Icon';
  12. import DiagnosticReport from '../DiagnosticReport';
  13. import { Popup } from 'antd-mobile';
  14. import { setVisible } from '@/states/patient/DiagnosticReport/slice';
  15. import EditTaskModal from './EditTaskModal';
  16. import { openEditModal } from '@/states/patient/edit/editFormSlice';
  17. interface ActionButtonProps {
  18. icon: React.ReactNode;
  19. tooltip: React.ReactNode;
  20. onClick?: () => void;
  21. }
  22. const ActionButton: React.FC<ActionButtonProps> = ({
  23. icon,
  24. tooltip,
  25. onClick,
  26. }) => (
  27. <Tooltip title={tooltip}>
  28. <Button icon={icon} onClick={onClick} style={{ width: '2.5rem' }} />
  29. </Tooltip>
  30. );
  31. const ActionPanel: React.FC = () => {
  32. const dispatch = useDispatch<AppDispatch>();
  33. const workSelectedIds = useSelector(
  34. (state: RootState) => state.workSelection.selectedIds
  35. );
  36. const historySelectedIds = useSelector(
  37. (state: RootState) => state.historySelection.selectedIds
  38. );
  39. const visible = useSelector(
  40. (state: RootState) => state.diagnosticReport.visible
  41. );
  42. const themeType = useAppSelector((state) => state.theme.themeType);
  43. const currentKey = useSelector(
  44. (state: RootState) => state.BusinessFlow.currentKey
  45. );
  46. const workEntities = useSelector(
  47. (state: RootState) => state.workEntities.data
  48. );
  49. const workEntitiesFromHistory = useSelector(
  50. (state: RootState) => state.historyEntities.data
  51. );
  52. // 使用 worklist 或 history 的选中项,取决于哪个有值
  53. const selectedIds =
  54. workSelectedIds.length > 0 ? workSelectedIds : historySelectedIds;
  55. const handleDelete = () => {
  56. if (selectedIds.length === 0) {
  57. message.warning('请先选择要删除的项目');
  58. return;
  59. }
  60. Modal.confirm({
  61. title: '确认删除',
  62. content: `确定要删除选中的 ${selectedIds.length} 个项目吗?此操作不可撤销。`,
  63. okText: '确认删除',
  64. cancelText: '取消',
  65. okButtonProps: { danger: true },
  66. centered: true,
  67. onOk: () => {
  68. dispatch(deleteWorkThunk(selectedIds));
  69. },
  70. });
  71. };
  72. const handleSend = () => {
  73. dispatch(switchToSendPanel());
  74. };
  75. const handleShowReport = () => {
  76. dispatch(setVisible(true));
  77. };
  78. const getSelectedWorkIds = () => {
  79. const selectedIds =
  80. currentKey === 'worklist' ? workSelectedIds : historySelectedIds;
  81. return selectedIds;
  82. };
  83. const getWorksFromWorklistOrHistory = () => {
  84. return currentKey === 'worklist' ? workEntities : workEntitiesFromHistory;
  85. };
  86. const handleEdit = () => {
  87. const selectedIds = getSelectedWorkIds();
  88. if (selectedIds.length === 0) {
  89. message.warning('请先选择要编辑的任务');
  90. return;
  91. }
  92. if (selectedIds.length > 1) {
  93. message.warning('只能编辑一个任务');
  94. return;
  95. }
  96. const works = getWorksFromWorklistOrHistory();
  97. const task = works.find((item) => item.StudyID === selectedIds[0]);
  98. if (task) {
  99. // 通过 dispatch action 传递数据到 slice
  100. dispatch(openEditModal(task));
  101. }
  102. };
  103. const handleLock = () => {
  104. const selectedIds = getSelectedWorkIds();
  105. // 2. 检查是否有选中项
  106. if (selectedIds.length === 0) {
  107. message.warning('请先选择要锁定/解锁的项目');
  108. return;
  109. }
  110. // 3. 获取第一个选中项的锁定状态
  111. const works = getWorksFromWorklistOrHistory();
  112. const selectedItem = works.find((item) => item.StudyID === selectedIds[0]);
  113. if (!selectedItem) return;
  114. // 4. 根据当前状态切换
  115. const newLockState =
  116. selectedItem.StudyLock === 'Locked' ? 'Unlocked' : 'Locked';
  117. // 为每个选中项执行锁定/解锁操作
  118. selectedIds.forEach((studyId) => {
  119. console.log(
  120. `锁定,触发action ,目标 studyid是 ${studyId},新状态是 ${newLockState}`
  121. );
  122. dispatch(lockWorkInWorklistThunk({ studyId, lock: newLockState }));
  123. });
  124. };
  125. return (
  126. <div className="flex flex-wrap gap-2 w-full">
  127. <ActionButton
  128. icon={
  129. <Icon
  130. module="module-patient"
  131. name="Delete"
  132. userId="base"
  133. theme="default"
  134. size="2x"
  135. state="normal"
  136. />
  137. }
  138. tooltip={
  139. <FormattedMessage
  140. id="actionPanel.deleteTask"
  141. defaultMessage="actionPanel.deleteTask"
  142. />
  143. }
  144. onClick={handleDelete}
  145. />
  146. <ActionButton
  147. icon={
  148. <Icon
  149. module="module-patient"
  150. name="EditPatient"
  151. userId="base"
  152. theme="default"
  153. size="2x"
  154. state="normal"
  155. />
  156. }
  157. tooltip={
  158. <FormattedMessage
  159. id="actionPanel.editPatient"
  160. defaultMessage="actionPanel.editPatient"
  161. />
  162. }
  163. onClick={handleEdit}
  164. />
  165. <ActionButton
  166. icon={
  167. <Icon
  168. module="module-patient"
  169. name="Protect"
  170. userId="base"
  171. theme="default"
  172. size="2x"
  173. state="normal"
  174. />
  175. }
  176. tooltip={
  177. <FormattedMessage
  178. id="actionPanel.lockTask"
  179. defaultMessage="actionPanel.lockTask"
  180. />
  181. }
  182. onClick={handleLock}
  183. />
  184. <ActionButton
  185. icon={
  186. <Icon
  187. module="module-patient"
  188. name="RIS"
  189. userId="base"
  190. theme="default"
  191. size="2x"
  192. state="normal"
  193. />
  194. }
  195. tooltip={
  196. <FormattedMessage
  197. id="actionPanel.risSync"
  198. defaultMessage="actionPanel.risSync"
  199. />
  200. }
  201. />
  202. <ActionButton
  203. icon={
  204. <Icon
  205. module="module-patient"
  206. name="ReRegister"
  207. userId="base"
  208. theme="default"
  209. size="2x"
  210. state="normal"
  211. />
  212. }
  213. tooltip={
  214. <FormattedMessage
  215. id="actionPanel.reRegister"
  216. defaultMessage="actionPanel.reRegister"
  217. />
  218. }
  219. />
  220. <ActionButton
  221. icon={
  222. <Icon
  223. module="module-patient"
  224. name="btn_SaveLocally"
  225. userId="base"
  226. theme="default"
  227. size="2x"
  228. state="normal"
  229. />
  230. }
  231. tooltip={
  232. <FormattedMessage
  233. id="actionPanel.saveLocal"
  234. defaultMessage="actionPanel.saveLocal"
  235. />
  236. }
  237. />
  238. <ActionButton
  239. icon={
  240. <Icon
  241. module="module-patient"
  242. name="btn_Import"
  243. userId="base"
  244. theme="default"
  245. size="2x"
  246. state="normal"
  247. />
  248. }
  249. tooltip={
  250. <FormattedMessage
  251. id="actionPanel.importXLS"
  252. defaultMessage="actionPanel.importXLS"
  253. />
  254. }
  255. />
  256. <ActionButton
  257. icon={
  258. <Icon
  259. module="module-patient"
  260. name="Sort"
  261. userId="base"
  262. theme="default"
  263. size="2x"
  264. state="normal"
  265. />
  266. }
  267. tooltip={
  268. <FormattedMessage
  269. id="actionPanel.sortList"
  270. defaultMessage="actionPanel.sortList"
  271. />
  272. }
  273. />
  274. <ActionButton
  275. icon={
  276. <Icon
  277. module="module-patient"
  278. name="CloudShare"
  279. userId="base"
  280. theme="default"
  281. size="2x"
  282. state="normal"
  283. />
  284. }
  285. tooltip={
  286. <FormattedMessage
  287. id="actionPanel.cloudShare"
  288. defaultMessage="actionPanel.cloudShare"
  289. />
  290. }
  291. />
  292. <ActionButton
  293. icon={
  294. <Icon
  295. module="module-patient"
  296. name="Swap"
  297. userId="base"
  298. theme="default"
  299. size="2x"
  300. state="normal"
  301. />
  302. }
  303. tooltip={
  304. <FormattedMessage
  305. id="actionPanel.imageExchange"
  306. defaultMessage="actionPanel.imageExchange"
  307. />
  308. }
  309. />
  310. <ActionButton
  311. icon={
  312. <Icon
  313. module="module-patient"
  314. name="QRCodePrint"
  315. userId="base"
  316. theme="default"
  317. size="2x"
  318. state="normal"
  319. />
  320. }
  321. tooltip={
  322. <FormattedMessage
  323. id="actionPanel.qrPrint"
  324. defaultMessage="actionPanel.qrPrint"
  325. />
  326. }
  327. />
  328. <ActionButton
  329. icon={
  330. <Icon
  331. module="module-patient"
  332. name="Send"
  333. userId="base"
  334. theme="default"
  335. size="2x"
  336. state="normal"
  337. />
  338. }
  339. tooltip={
  340. <FormattedMessage
  341. id="actionPanel.send"
  342. defaultMessage="actionPanel.send"
  343. />
  344. }
  345. onClick={handleSend}
  346. />
  347. <ActionButton
  348. icon={
  349. <Icon
  350. module="module-patient"
  351. name="Export"
  352. userId="base"
  353. theme="default"
  354. size="2x"
  355. state="normal"
  356. />
  357. }
  358. tooltip={
  359. <FormattedMessage
  360. id="actionPanel.export"
  361. defaultMessage="actionPanel.export"
  362. />
  363. }
  364. />
  365. <ActionButton
  366. icon={
  367. <Icon
  368. module="module-patient"
  369. name="Import"
  370. userId="base"
  371. theme="default"
  372. size="2x"
  373. state="normal"
  374. />
  375. }
  376. tooltip={
  377. <FormattedMessage
  378. id="actionPanel.import"
  379. defaultMessage="actionPanel.import"
  380. />
  381. }
  382. />
  383. <ActionButton
  384. icon={
  385. <Icon
  386. module="module-patient"
  387. name="report"
  388. userId="base"
  389. theme={themeType}
  390. size="2x"
  391. state="normal"
  392. width={40}
  393. height={40}
  394. />
  395. }
  396. tooltip={
  397. <FormattedMessage
  398. id="actionPanel.showReport"
  399. defaultMessage="actionPanel.showReport"
  400. />
  401. }
  402. onClick={handleShowReport}
  403. />
  404. <Popup
  405. visible={visible}
  406. onMaskClick={() => dispatch(setVisible(false))}
  407. position="right"
  408. bodyStyle={{ width: '100vw', height: '100vh' }}
  409. >
  410. <DiagnosticReport />
  411. </Popup>
  412. <EditTaskModal />
  413. </div>
  414. );
  415. };
  416. export default ActionPanel;