BusinessZone.tsx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. import React, { useState } from 'react';
  2. import { Flex } from 'antd';
  3. import { FormattedMessage } from 'react-intl';
  4. import { useSelector } from 'react-redux';
  5. import {
  6. DataState,
  7. getBtnAvailability,
  8. LocationKey,
  9. } from '@/domain/permissionMap';
  10. import { RootState } from '@/states/store';
  11. import { IconButton } from '@/components/IconButton';
  12. import Icon from '@/components/Icon';
  13. interface BusinessZoneProps {
  14. onMenuClick?: (key: string) => void;
  15. }
  16. function useItems(btnAvailability: Record<string, boolean>) {
  17. return [
  18. {
  19. key: 'patient_management',
  20. label: (
  21. <FormattedMessage
  22. id="patient"
  23. defaultMessage={'语言包中没有定义patient的翻译文本'}
  24. />
  25. ),
  26. icon: 'Registration',
  27. disabled: !btnAvailability['patient_management'],
  28. children: [
  29. {
  30. key: 'register',
  31. disabled: !btnAvailability['register'],
  32. label: (
  33. <FormattedMessage
  34. id="register"
  35. defaultMessage={'语言包中没有定义patient的翻译文本'}
  36. />
  37. ),
  38. icon: 'Registration',
  39. },
  40. {
  41. key: 'worklist',
  42. disabled: !btnAvailability['worklist'],
  43. label: (
  44. <FormattedMessage
  45. id="tasklist"
  46. defaultMessage={'语言包中没有定义patient的翻译文本'}
  47. />
  48. ),
  49. icon: 'Worklist',
  50. },
  51. {
  52. key: 'historylist',
  53. disabled: !btnAvailability['historylist'],
  54. label: (
  55. <FormattedMessage
  56. id="historylist"
  57. defaultMessage={'语言包中没有定义patient的翻译文本'}
  58. />
  59. ),
  60. icon: 'Registration',
  61. },
  62. {
  63. key: 'archivelist',
  64. disabled: !btnAvailability['archivelist'],
  65. label: (
  66. <FormattedMessage
  67. id="archivelist"
  68. defaultMessage={'语言包中没有定义patient的翻译文本'}
  69. />
  70. ),
  71. icon: 'Registration',
  72. },
  73. {
  74. key: 'bin',
  75. disabled: !btnAvailability['bin'],
  76. label: (
  77. <FormattedMessage
  78. id="bin"
  79. defaultMessage={'语言包中没有定义patient的翻译文本'}
  80. />
  81. ),
  82. },
  83. {
  84. key: 'outputlist',
  85. disabled: !btnAvailability['outputlist'],
  86. label: (
  87. <FormattedMessage
  88. id="outputlist"
  89. defaultMessage={'语言包中没有定义patient的翻译文本'}
  90. />
  91. ),
  92. icon: 'Registration',
  93. },
  94. ],
  95. },
  96. // {
  97. // key: 'emergency',
  98. // icon: 'Emergency',
  99. // label: '急诊',
  100. // disabled: false,
  101. // },
  102. {
  103. key: 'exam',
  104. disabled:
  105. (console.log(`我要看看exam对应的值:${!btnAvailability['exam']}`),
  106. !btnAvailability['exam']),
  107. label: (
  108. <FormattedMessage
  109. id="exam"
  110. defaultMessage={'语言包中没有定义patient的翻译文本'}
  111. />
  112. ),
  113. icon: 'Exam',
  114. },
  115. {
  116. type: 'divider',
  117. },
  118. {
  119. key: 'process',
  120. disabled:
  121. (console.log(
  122. `我要看看[process]对应的值:${!btnAvailability['process']}`
  123. ),
  124. !btnAvailability['process']),
  125. label: (
  126. <FormattedMessage
  127. id="process"
  128. defaultMessage={'语言包中没有定义patient的翻译文本'}
  129. />
  130. ),
  131. icon: 'Process',
  132. },
  133. {
  134. key: 'print',
  135. disabled: !btnAvailability['print'],
  136. label: (
  137. <FormattedMessage
  138. id="print"
  139. defaultMessage={'语言包中没有定义patient的翻译文本'}
  140. />
  141. ),
  142. icon: 'Output',
  143. },
  144. ];
  145. }
  146. const BusinessZone: React.FC<BusinessZoneProps> = ({ onMenuClick }) => {
  147. // eslint-disable-next-line
  148. const currentKey = useSelector((state: RootState) => state.BusinessFlow.currentKey);
  149. console.log('Current Business Flow Key:', currentKey);
  150. const dataState: DataState = useSelector((state: RootState) => {
  151. if (currentKey === 'worklist') {
  152. return {
  153. hasSelection: state.workSelection.selectedIds.length > 0,
  154. hasExposedImage:
  155. state.bodyPositionList.exposureStatus === 'Half Exposed' ||
  156. state.bodyPositionList.exposureStatus === 'Fully Exposed',
  157. };
  158. } else if (currentKey === 'historylist') {
  159. return {
  160. hasSelection: state.historySelection.selectedIds.length > 0,
  161. hasExposedImage:
  162. state.bodyPositionList.exposureStatus === 'Half Exposed' ||
  163. state.bodyPositionList.exposureStatus === 'Fully Exposed',
  164. };
  165. } else if (currentKey === 'exam') {
  166. return {
  167. // hasSelection: state.historySelection.selectedIds.length > 0,
  168. hasExposedImage:
  169. state.bodyPositionList.exposureStatus === 'Half Exposed' ||
  170. state.bodyPositionList.exposureStatus === 'Fully Exposed',
  171. };
  172. } else {
  173. return {};
  174. }
  175. });
  176. const btnAvailability = getBtnAvailability(
  177. currentKey as LocationKey,
  178. dataState
  179. );
  180. console.log('Button Availability:', btnAvailability);
  181. const items = useItems(btnAvailability);
  182. // const [visibleItems, setVisibleItems] = useState(items);
  183. const [floatingMenuVisible, setFloatingMenuVisible] = useState(false);
  184. // const businessZoneRef = useRef<HTMLDivElement>(null);
  185. // useEffect(() => {
  186. // const handleResize = () => {
  187. // if (businessZoneRef.current) {
  188. // const businessZoneHeight = businessZoneRef.current.offsetHeight;
  189. // const windowHeight = window.innerHeight;
  190. // const systemZoneHeight = 100; // Assuming SystemZone height is fixed
  191. // if (businessZoneHeight + systemZoneHeight > windowHeight) {
  192. // const visibleCount = Math.floor(
  193. // (windowHeight - systemZoneHeight) / 50
  194. // ); // Assuming each button height is 50px
  195. // setVisibleItems(items.slice(0, visibleCount));
  196. // } else {
  197. // setVisibleItems(items);
  198. // }
  199. // }
  200. // };
  201. // window.addEventListener('resize', handleResize);
  202. // handleResize(); // Initial check
  203. // return () => {
  204. // window.removeEventListener('resize', handleResize);
  205. // };
  206. // }, [items]);
  207. const handlePatientManagementClick = () => {
  208. setFloatingMenuVisible(!floatingMenuVisible);
  209. };
  210. const buttonClassNameGenerator = (
  211. itemkey: string,
  212. currentkey: string
  213. ): string => {
  214. const originalName =
  215. 'w-full max-w-full whitespace-nowrap overflow-hidden text-ellipsis min-w-0 truncate';
  216. if (itemkey === currentkey) {
  217. return originalName + ' border border-red-500 ';
  218. }
  219. return originalName;
  220. };
  221. useSelector((state: RootState) => state.permission.triggerPermissionCalc);
  222. return (
  223. // <div
  224. // className="grid grid-rows-[1fr] flex-grow h-0 overflow-y-auto"
  225. // >
  226. <Flex vertical className=" min-h-0 overflow-y-auto flex-grow px-1">
  227. {items.map((item) =>
  228. item.type === 'divider' ? (
  229. <hr
  230. key="divider"
  231. style={{
  232. width: '100%',
  233. borderTop: '1px solid #f0f0f0',
  234. margin: '8px 0',
  235. }}
  236. />
  237. ) : (
  238. <>
  239. <IconButton
  240. data-testid={item.key}
  241. onClick={
  242. item.key === 'patient_management'
  243. ? handlePatientManagementClick
  244. : () => onMenuClick?.(item.key ?? 'error')
  245. }
  246. iconSize={56}
  247. iconPlace="left"
  248. icon={
  249. <Icon
  250. module="module-common"
  251. name={item.icon ?? ''}
  252. userId="user-A"
  253. theme="default"
  254. size="2x"
  255. state="normal"
  256. />
  257. }
  258. style={{
  259. //flex: 1,
  260. minWidth: 0,
  261. overflow: 'hidden', // 超出隐藏
  262. textOverflow: 'ellipsis', // 超出用省略号
  263. whiteSpace: 'nowrap', // 不换行
  264. padding: '0px',
  265. minHeight: '1.5rem',
  266. }}
  267. className={buttonClassNameGenerator(
  268. item.key as string,
  269. currentKey
  270. )}
  271. disabled={item.disabled}
  272. >
  273. <span
  274. style={{
  275. overflow: 'hidden',
  276. textOverflow: 'ellipsis',
  277. whiteSpace: 'nowrap',
  278. display: 'block', // 或 inline-block
  279. flex: 1, // 占据剩余空间并允许收缩
  280. minWidth: 0, // 再次确保可以收缩
  281. }}
  282. >
  283. {item.label}
  284. </span>
  285. </IconButton>
  286. {item.key === 'patient_management' && floatingMenuVisible && (
  287. <Flex vertical className="px-1">
  288. {item.children?.map((child) => (
  289. <IconButton
  290. data-testid={child.key}
  291. iconSize={56}
  292. icon={
  293. <Icon
  294. module="module-common"
  295. name={item.icon ?? ''}
  296. userId="user-A"
  297. theme="default"
  298. size="2x"
  299. state="normal"
  300. />
  301. }
  302. key={child.key}
  303. onClick={() => onMenuClick?.(child.key)}
  304. className={buttonClassNameGenerator(
  305. item.key as string,
  306. currentKey
  307. )}
  308. style={{
  309. //flex: 1,
  310. minWidth: 0,
  311. overflow: 'hidden', // 超出隐藏
  312. textOverflow: 'ellipsis', // 超出用省略号
  313. whiteSpace: 'nowrap', // 不换行
  314. padding: '0px',
  315. }}
  316. disabled={item.disabled}
  317. >
  318. <span
  319. style={{
  320. overflow: 'hidden',
  321. textOverflow: 'ellipsis',
  322. whiteSpace: 'nowrap',
  323. display: 'block', // 或 inline-block
  324. flex: 1, // 占据剩余空间并允许收缩
  325. minWidth: 0, // 再次确保可以收缩
  326. }}
  327. >
  328. {child.label}
  329. </span>
  330. </IconButton>
  331. ))}
  332. </Flex>
  333. )}
  334. </>
  335. )
  336. )}
  337. </Flex>
  338. // </div>
  339. );
  340. };
  341. export default BusinessZone;