aprSlice.ts 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. /* eslint-disable */
  2. import { createSlice, PayloadAction, Middleware, createAsyncThunk } from '@reduxjs/toolkit';
  3. import { AprConfig, getAprExposureParams, getAprByThickness, SetAPR } from '../../API/exam/APRActions';
  4. import { workstationIdFromWorkstation, WorkstationType } from '../workstation';
  5. import { ExtendedBodyPosition, setSelectedBodyPosition } from '../exam/bodyPositionListSlice';
  6. import { initializeProductState } from '../productSlice';
  7. interface AprState {
  8. aprConfig: AprConfig;
  9. bodysize: string;
  10. workstation: string;
  11. thickness: number;
  12. isAECEnabled: boolean;
  13. currentExposureMode: string;
  14. /**
  15. * 是否正在设置中
  16. */
  17. isPending:boolean;
  18. }
  19. const initialState: AprState = {
  20. aprConfig: {
  21. AECDensity: 0,
  22. AECField: '',
  23. AECFilm: 0,
  24. Dose: 0,
  25. ExposureMode: 0,
  26. Focus: 0,
  27. TOD: 0,
  28. TubeLoad: 0,
  29. kV: 0,
  30. mA: 0,
  31. mAs: 0,
  32. ms: 0,
  33. },
  34. bodysize: '',
  35. workstation: '',
  36. thickness: 0,
  37. isAECEnabled: false,
  38. currentExposureMode: 'mAs',
  39. isPending:false
  40. };
  41. const aprSlice = createSlice({
  42. name: 'apr',
  43. initialState,
  44. reducers: {
  45. setAprConfig: (state, action: PayloadAction<AprConfig>) => {
  46. state.aprConfig = action.payload;
  47. },
  48. setBodysize: (state, action: PayloadAction<string>) => {
  49. state.bodysize = action.payload;
  50. },
  51. setWorkstation: (state, action: PayloadAction<string>) => {
  52. state.workstation = action.payload;
  53. },
  54. setThickness: (state, action: PayloadAction<number>) => {
  55. state.thickness = action.payload;
  56. },
  57. setIsAECEnabled: (state, action: PayloadAction<boolean>) => {
  58. state.isAECEnabled = action.payload;
  59. },
  60. setCurrentExposureMode: (state, action: PayloadAction<string>) => {
  61. state.currentExposureMode = action.payload;
  62. },
  63. },
  64. extraReducers: (builder) => {
  65. builder
  66. .addCase(incKV.pending, (state) => {
  67. console.log('Increasing kV...');
  68. })
  69. .addCase(incKV.fulfilled, (state, action) => {
  70. console.log('kV increased successfully');
  71. state.aprConfig.kV = action.payload;
  72. })
  73. .addCase(incKV.rejected, (state, action) => {
  74. console.error('Failed to increase kV', action.error);
  75. })
  76. .addCase(decKV.pending, (state) => {
  77. console.log('Decreasing kV...');
  78. })
  79. .addCase(decKV.fulfilled, (state, action) => {
  80. console.log('kV decreased successfully');
  81. state.aprConfig.kV = action.payload;
  82. })
  83. .addCase(decKV.rejected, (state, action) => {
  84. console.error('Failed to decrease kV', action.error);
  85. })
  86. .addCase(incMA.pending, (state) => {
  87. console.log('Increasing mA...');
  88. })
  89. .addCase(incMA.fulfilled, (state, action) => {
  90. console.log('mA increased successfully');
  91. state.aprConfig.mA = action.payload;
  92. })
  93. .addCase(incMA.rejected, (state, action) => {
  94. console.error('Failed to increase mA', action.error);
  95. })
  96. .addCase(decMA.pending, (state) => {
  97. console.log('Decreasing mA...');
  98. })
  99. .addCase(decMA.fulfilled, (state, action) => {
  100. console.log('mA decreased successfully');
  101. state.aprConfig.mA = action.payload;
  102. })
  103. .addCase(decMA.rejected, (state, action) => {
  104. console.error('Failed to decrease mA', action.error);
  105. })
  106. .addCase(incMAS.pending, (state) => {
  107. console.log('Increasing mAs...');
  108. })
  109. .addCase(incMAS.fulfilled, (state, action) => {
  110. console.log('mAs increased successfully');
  111. state.aprConfig.mAs = action.payload;
  112. })
  113. .addCase(incMAS.rejected, (state, action) => {
  114. console.error('Failed to increase mAs', action.error);
  115. })
  116. .addCase(decMAS.pending, (state) => {
  117. console.log('Decreasing mAs...');
  118. })
  119. .addCase(decMAS.fulfilled, (state, action) => {
  120. console.log('mAs decreased successfully');
  121. state.aprConfig.mAs = action.payload;
  122. })
  123. .addCase(decMAS.rejected, (state, action) => {
  124. console.error('Failed to decrease mAs', action.error);
  125. })
  126. .addCase(incMS.pending, (state) => {
  127. console.log('Increasing ms...');
  128. })
  129. .addCase(incMS.fulfilled, (state, action) => {
  130. console.log('ms increased successfully');
  131. state.aprConfig.ms = action.payload;
  132. })
  133. .addCase(incMS.rejected, (state, action) => {
  134. console.error('Failed to increase ms', action.error);
  135. })
  136. .addCase(decMS.pending, (state) => {
  137. console.log('Decreasing ms...');
  138. })
  139. .addCase(decMS.fulfilled, (state, action) => {
  140. console.log('ms decreased successfully');
  141. state.aprConfig.ms = action.payload;
  142. })
  143. .addCase(decMS.rejected, (state, action) => {
  144. console.error('Failed to decrease ms', action.error);
  145. })
  146. .addCase(incDensity.pending, (state) => {
  147. console.log('Increasing Density...');
  148. })
  149. .addCase(incDensity.fulfilled, (state, action) => {
  150. console.log('Density increased successfully');
  151. state.aprConfig.AECDensity = action.payload;
  152. })
  153. .addCase(incDensity.rejected, (state, action) => {
  154. console.error('Failed to increase Density', action.error);
  155. })
  156. .addCase(decDensity.pending, (state) => {
  157. console.log('Decreasing Density...');
  158. })
  159. .addCase(decDensity.fulfilled, (state, action) => {
  160. console.log('Density decreased successfully');
  161. state.aprConfig.AECDensity = action.payload;
  162. })
  163. .addCase(decDensity.rejected, (state, action) => {
  164. console.error('Failed to decrease Density', action.error);
  165. })
  166. .addCase(incThickness.pending, (state) => {
  167. console.log('Increasing Thickness...');
  168. })
  169. .addCase(incThickness.fulfilled, (state, action) => {
  170. console.log('Thickness increased successfully');
  171. state.thickness = action.payload;
  172. })
  173. .addCase(incThickness.rejected, (state, action) => {
  174. console.error('Failed to increase Thickness', action.error);
  175. })
  176. .addCase(decThickness.pending, (state) => {
  177. console.log('Decreasing Thickness...');
  178. })
  179. .addCase(decThickness.fulfilled, (state, action) => {
  180. console.log('Thickness decreased successfully');
  181. state.thickness = action.payload;
  182. })
  183. .addCase(decThickness.rejected, (state, action) => {
  184. console.error('Failed to decrease Thickness', action.error);
  185. })
  186. .addCase(setExposureModeThunk.pending, (state) => {
  187. console.log('Setting exposure mode...');
  188. state.isPending = true;
  189. })
  190. .addCase(setExposureModeThunk.fulfilled, (state, action) => {
  191. console.log('Exposure mode set successfully:', action.payload);
  192. state.currentExposureMode = action.payload;
  193. state.isPending = false;
  194. })
  195. .addCase(setExposureModeThunk.rejected, (state, action) => {
  196. console.error('Failed to set exposure mode', action.error);
  197. state.isPending = false;
  198. })
  199. .addCase(setSelectedBodyPosition, (state, action: PayloadAction<ExtendedBodyPosition | null>) => {
  200. console.log('APR Extra Reducer triggered for setSelectedBodyPosition action');
  201. const selectedBodyPosition = action.payload;
  202. if (selectedBodyPosition) {
  203. // 初始化厚度值
  204. state.thickness = selectedBodyPosition.work?.Thickness || 0;
  205. console.log('Initialized thickness from selected body position:', state.thickness);
  206. const reqParam = JSON.stringify({
  207. P0:{
  208. FOCUS: "0",
  209. TECHMODE: state.aprConfig.ExposureMode.toString(),
  210. AECFIELD: "101",
  211. AECFILM: "0",
  212. AECDENSITY: "0",
  213. KV: state.aprConfig.kV.toString(),
  214. MA: state.aprConfig.mA.toString(),
  215. MS: state.aprConfig.ms.toString(),
  216. MAS: state.aprConfig.mAs.toString(),
  217. KV2: "0.0",
  218. MA2: "0.0",
  219. MS2: "0.0",
  220. DOSE: "0.0",
  221. FILTER: "null",
  222. TUBELOAD: "0.0",
  223. WORKSTATION: selectedBodyPosition.work_station_id
  224. }});
  225. SetAPR(reqParam)
  226. .then(() => {
  227. console.log('SetAPR method called successfully');
  228. })
  229. .catch((error) => {
  230. console.error('Error calling SetAPR method:', error);
  231. });
  232. }
  233. })
  234. .addCase(initializeProductState.fulfilled, (state, action) => {
  235. console.log('APR监听到产品初始化完成:', action.payload.productName);
  236. if (action.payload.productName === 'VETDROS') {
  237. state.workstation = WorkstationType.Free;
  238. console.log('自动设置 workstation 为 Free (VETDROS 环境)');
  239. }
  240. });
  241. },
  242. });
  243. const aprMiddleware: Middleware = (store) => (next) => (action: any) => {
  244. const result = next(action);
  245. if (
  246. action.type === aprSlice.actions.setBodysize.type ||
  247. action.type === aprSlice.actions.setWorkstation.type
  248. ) {
  249. console.log('APR Middleware triggered:', action.type);
  250. const state = store.getState();
  251. const id =
  252. state.bodyPositionList.selectedBodyPosition?.view_id || 'default_id'; // Dynamically determined based on selectedBodyPosition
  253. const workStationId = workstationIdFromWorkstation(
  254. state.apr.workstation,
  255. state.product.productName
  256. );
  257. const patientSize = state.apr.bodysize;
  258. console.log(
  259. `Fetching APR exposure parameters for ID: ${id}, Workstation ID: ${workStationId}, Patient Size: ${patientSize}`
  260. );
  261. // Fetch APR exposure parameters based on the current state
  262. if (!!patientSize) {
  263. getAprExposureParams(id, workStationId, patientSize)
  264. .then((data) => {
  265. console.log('Received APR exposure parameters:', data);
  266. // Dispatch the action to set the APR config in the store
  267. if (data) {
  268. store.dispatch(setAprConfig(data));
  269. // After updating the store, send the APR parameters to the device
  270. const currentState = store.getState();
  271. const selectedBodyPosition = currentState.bodyPositionList.selectedBodyPosition;
  272. if (selectedBodyPosition) {
  273. const reqParam = JSON.stringify({
  274. P0: {
  275. FOCUS: "0",
  276. TECHMODE: data.ExposureMode.toString(),
  277. AECFIELD: "101",
  278. AECFILM: "0",
  279. AECDENSITY: "0",
  280. KV: data.kV.toString(),
  281. MA: data.mA.toString(),
  282. MS: data.ms.toString(),
  283. MAS: data.mAs.toString(),
  284. KV2: "0.0",
  285. MA2: "0.0",
  286. MS2: "0.0",
  287. DOSE: "0.0",
  288. FILTER: "null",
  289. TUBELOAD: "0.0",
  290. WORKSTATION: selectedBodyPosition.work_station_id
  291. }
  292. });
  293. SetAPR(reqParam)
  294. .then(() => {
  295. console.log('[aprMiddleware] SetAPR called successfully after body size/workstation change');
  296. })
  297. .catch((error) => {
  298. console.error('[aprMiddleware] Error calling SetAPR after body size/workstation change:', error);
  299. });
  300. } else {
  301. console.warn('[aprMiddleware] No selected body position found, skipping SetAPR call');
  302. }
  303. }
  304. })
  305. .catch((error) => {
  306. console.error('Error fetching APR exposure parameters:', error);
  307. })
  308. .finally(() => {
  309. console.log('APR exposure parameters fetch attempt finished.');
  310. });
  311. }
  312. } else if (action.type === aprSlice.actions.setThickness.type) {
  313. console.log('APR Middleware triggered by thickness change:', action.type);
  314. const state = store.getState();
  315. const thickness = state.apr.thickness;
  316. console.log(`Fetching APR exposure parameters by thickness: ${thickness}`);
  317. // 确保厚度值在有效范围内 (1-50)
  318. if (thickness >= 1 && thickness <= 50) {
  319. getAprByThickness(thickness)
  320. .then((data) => {
  321. console.log('Received APR exposure parameters by thickness:', data);
  322. if (data) {
  323. store.dispatch(setAprConfig(data));
  324. // After updating the store, send the APR parameters to the device
  325. const currentState = store.getState();
  326. const selectedBodyPosition = currentState.bodyPositionList.selectedBodyPosition;
  327. console.info(`根据厚度得到arp后,下发kv ms mas ma 给设备`);
  328. if (selectedBodyPosition) {
  329. const reqParam = JSON.stringify({
  330. P0: {
  331. FOCUS: "0",
  332. TECHMODE:data.ExposureMode.toString(),
  333. AECFIELD: "101",
  334. AECFILM: "0",
  335. AECDENSITY: "0",
  336. KV: data.kV.toString(),
  337. MA: data.mA.toString(),
  338. MS: (data.mAs/data.mA).toString(),
  339. MAS: data.mAs.toString(),
  340. KV2: "0.0",
  341. MA2: "0.0",
  342. MS2: "0.0",
  343. DOSE: "0.0",
  344. FILTER: "null",
  345. TUBELOAD: "0.0",
  346. WORKSTATION: selectedBodyPosition.work_station_id
  347. }
  348. });
  349. console.info(`根据厚度得到arp后,下发之前 kv ms mas ma = ${reqParam}`);
  350. SetAPR(reqParam)
  351. .then(() => {
  352. console.log('[aprMiddleware] SetAPR called successfully after thickness change');
  353. })
  354. .catch((error) => {
  355. console.error('[aprMiddleware] Error calling SetAPR after thickness change:', error);
  356. });
  357. } else {
  358. console.warn('[aprMiddleware] No selected body position found, skipping SetAPR call');
  359. }
  360. }
  361. })
  362. .catch((error) => {
  363. console.error('Error fetching APR exposure parameters by thickness:', error);
  364. })
  365. .finally(() => {
  366. console.log('APR exposure parameters fetch by thickness attempt finished.');
  367. });
  368. } else {
  369. console.warn(`Thickness value ${thickness} is out of valid range (1-50), skipping API call`);
  370. }
  371. }
  372. return result;
  373. };
  374. export const incKV = createAsyncThunk<number, number>('apr/incKV', async (amount: number) => {
  375. return amount;
  376. });
  377. export const decKV = createAsyncThunk<number, number>('apr/decKV', async (amount: number) => {
  378. return amount;
  379. });
  380. export const incMA = createAsyncThunk<number, number>('apr/incMA', async (amount: number) => {
  381. return amount;
  382. });
  383. export const decMA = createAsyncThunk<number, number>('apr/decMA', async (amount: number) => {
  384. return amount;
  385. });
  386. export const incMAS = createAsyncThunk<number, number>('apr/incMAS', async (amount: number) => {
  387. return amount;
  388. });
  389. export const decMAS = createAsyncThunk<number, number>('apr/decMAS', async (amount: number) => {
  390. return amount;
  391. });
  392. export const incMS = createAsyncThunk<number, number>('apr/incMS', async (amount: number) => {
  393. return amount;
  394. });
  395. export const decMS = createAsyncThunk<number, number>('apr/decMS', async (amount: number) => {
  396. return amount;
  397. });
  398. export const incDensity = createAsyncThunk<number, number>('apr/incDensity', async (amount: number) => {
  399. return amount;
  400. });
  401. export const decDensity = createAsyncThunk<number, number>('apr/decDensity', async (amount: number) => {
  402. return amount;
  403. });
  404. export const incThickness = createAsyncThunk<number, number>('apr/incThickness', async (amount: number) => {
  405. return amount;
  406. });
  407. export const decThickness = createAsyncThunk<number, number>('apr/decThickness', async (amount: number) => {
  408. return amount;
  409. });
  410. export const setExposureModeThunk = createAsyncThunk<string, string>('apr/setExposureMode', async (mode: string) => {
  411. return mode;
  412. });
  413. export const {
  414. setAprConfig,
  415. setBodysize,
  416. setWorkstation,
  417. setThickness,
  418. setIsAECEnabled,
  419. setCurrentExposureMode,
  420. } = aprSlice.actions;
  421. export default aprSlice.reducer;
  422. export { aprMiddleware };