| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 |
- /**
- * 滑动参数调节面板状态管理
- */
- import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit';
- import type { RootState } from '../store';
- import type {
- ProcessingStyle,
- LUTType,
- FullProcessingParams
- } from '../../types/imageProcessing';
- import {
- PROCESSING_PRESETS,
- DEFAULT_ALGORITHM
- } from '../../domain/processingPresets';
- import { DEFAULT_LUT } from '../../domain/lutConfig';
- import {
- getImageProcessingParams,
- saveImageProcessingParams
- } from '../../API/imageActions';
- /**
- * 状态接口
- */
- interface SliderAdjustmentPanelState {
- // 当前图像ID
- currentImageId: string | null;
-
- // 当前参数值
- parameters: FullProcessingParams;
-
- // 当前选择的风格
- selectedStyle: ProcessingStyle;
-
- // 当前选择的算法(独立管理)
- selectedAlgorithm: string;
-
- // 当前选择的LUT(独立管理)
- selectedLUT: LUTType;
-
- // 是否正在加载
- isLoading: boolean;
-
- // 是否正在保存
- isSaving: boolean;
-
- // 初始加载标志(区分初始加载和用户操作)
- isInitialLoad: boolean;
-
- // 错误信息
- error: string | null;
- }
- /**
- * 初始状态
- */
- const initialState: SliderAdjustmentPanelState = {
- currentImageId: null,
- parameters: PROCESSING_PRESETS['均衡'].params,
- selectedStyle: '均衡',
- selectedAlgorithm: DEFAULT_ALGORITHM,
- selectedLUT: DEFAULT_LUT,
- isLoading: false,
- isSaving: false,
- isInitialLoad: true,
- error: null,
- };
- /**
- * 异步操作:加载图像处理参数
- */
- export const loadImageProcessingParams = createAsyncThunk(
- 'sliderAdjustmentPanel/loadParams',
- async (sopInstanceUid: string, { rejectWithValue }) => {
- try {
- const response = await getImageProcessingParams(sopInstanceUid);
- return {
- sopInstanceUid,
- params: response.data,
- };
- } catch (error) {
- return rejectWithValue(
- error instanceof Error ? error.message : '加载参数失败'
- );
- }
- }
- );
- /**
- * 异步操作:保存图像处理参数
- */
- export const saveProcessingParams = createAsyncThunk(
- 'sliderAdjustmentPanel/saveParams',
- async (
- {
- sopInstanceUid,
- params
- }: {
- sopInstanceUid: string;
- params: { contrast: number; detail: number; latitude: number; noise: number }
- },
- { rejectWithValue }
- ) => {
- try {
- await saveImageProcessingParams(sopInstanceUid, params);
- return params;
- } catch (error) {
- return rejectWithValue(
- error instanceof Error ? error.message : '保存参数失败'
- );
- }
- }
- );
- /**
- * Slice
- */
- const sliderAdjustmentPanelSlice = createSlice({
- name: 'sliderAdjustmentPanel',
- initialState,
- reducers: {
- /**
- * 设置当前图像ID
- */
- setCurrentImageId: (state, action: PayloadAction<string>) => {
- state.currentImageId = action.payload;
- state.isInitialLoad = true;
- },
-
- /**
- * 更新单个参数
- */
- updateParameter: (
- state,
- action: PayloadAction<{ name: keyof FullProcessingParams; value: number }>
- ) => {
- const { name, value } = action.payload;
- state.parameters[name] = value;
- // 用户手动调整参数后,不再是初始加载状态
- state.isInitialLoad = false;
- },
-
- /**
- * 应用风格预设
- */
- applyPreset: (state, action: PayloadAction<ProcessingStyle>) => {
- const preset = PROCESSING_PRESETS[action.payload];
- state.selectedStyle = action.payload;
- state.parameters = { ...preset.params };
- // 应用风格后,不再是初始加载状态
- state.isInitialLoad = false;
- },
-
- /**
- * 重置为当前风格的默认值
- */
- resetToPreset: (state) => {
- const preset = PROCESSING_PRESETS[state.selectedStyle];
- state.parameters = { ...preset.params };
- state.isInitialLoad = false;
- },
-
- /**
- * 设置算法
- */
- setAlgorithm: (state, action: PayloadAction<string>) => {
- state.selectedAlgorithm = action.payload;
- },
-
- /**
- * 设置LUT
- */
- setLUT: (state, action: PayloadAction<LUTType>) => {
- state.selectedLUT = action.payload;
- },
-
- /**
- * 清除错误
- */
- clearError: (state) => {
- state.error = null;
- },
-
- /**
- * 重置状态
- */
- resetState: () => initialState,
- },
- extraReducers: (builder) => {
- builder
- // 加载参数
- .addCase(loadImageProcessingParams.pending, (state) => {
- state.isLoading = true;
- state.error = null;
- })
- .addCase(loadImageProcessingParams.fulfilled, (state, action) => {
- state.isLoading = false;
- state.currentImageId = action.payload.sopInstanceUid;
- // 只更新后端返回的4个参数,保持前端的 brightness 和 sharpness
- state.parameters.contrast = action.payload.params.contrast;
- state.parameters.detail = action.payload.params.detail;
- state.parameters.latitude = action.payload.params.latitude;
- state.parameters.noise = action.payload.params.noise;
- // 标记为初始加载,避免触发自动保存
- state.isInitialLoad = true;
- })
- .addCase(loadImageProcessingParams.rejected, (state, action) => {
- state.isLoading = false;
- state.error = action.payload as string;
- // 加载失败时使用默认值
- state.parameters = PROCESSING_PRESETS[state.selectedStyle].params;
- })
- // 保存参数
- .addCase(saveProcessingParams.pending, (state) => {
- state.isSaving = true;
- state.error = null;
- })
- .addCase(saveProcessingParams.fulfilled, (state) => {
- state.isSaving = false;
- })
- .addCase(saveProcessingParams.rejected, (state, action) => {
- state.isSaving = false;
- state.error = action.payload as string;
- });
- },
- });
- /**
- * Actions
- */
- export const {
- setCurrentImageId,
- updateParameter,
- applyPreset,
- resetToPreset,
- setAlgorithm,
- setLUT,
- clearError,
- resetState,
- } = sliderAdjustmentPanelSlice.actions;
- /**
- * Selectors
- */
- export const selectCurrentImageId = (state: RootState) =>
- state.sliderAdjustmentPanel.currentImageId;
- export const selectParameters = (state: RootState) =>
- state.sliderAdjustmentPanel.parameters;
- export const selectSelectedStyle = (state: RootState) =>
- state.sliderAdjustmentPanel.selectedStyle;
- export const selectSelectedAlgorithm = (state: RootState) =>
- state.sliderAdjustmentPanel.selectedAlgorithm;
- export const selectSelectedLUT = (state: RootState) =>
- state.sliderAdjustmentPanel.selectedLUT;
- export const selectIsLoading = (state: RootState) =>
- state.sliderAdjustmentPanel.isLoading;
- export const selectIsSaving = (state: RootState) =>
- state.sliderAdjustmentPanel.isSaving;
- export const selectIsInitialLoad = (state: RootState) =>
- state.sliderAdjustmentPanel.isInitialLoad;
- export const selectError = (state: RootState) =>
- state.sliderAdjustmentPanel.error;
- /**
- * Reducer
- */
- export default sliderAdjustmentPanelSlice.reducer;
|