在患者注册流程中,用户需要选择患者类型、身体部位,然后选择体位(View)或协议(Protocol)。已选择的体位会被添加到"已选择体位列表"中。
当用户切换患者类型时,需要自动清空已选择的体位列表(selectedViews)
不同患者类型对应不同的体位选项,当患者类型改变时,之前选择的体位可能不再适用于新的患者类型,因此需要清空已选择的体位列表,让用户重新选择。
patientTypeSlice.ts
- 患者类型切片位置: src/states/patientTypeSlice.ts
State 结构:
interface PatientTypeState {
items: PatientType[]; // 所有患者类型列表
loading: boolean;
error: string | null;
current: PatientType | null; // 当前选中的患者类型
}
关键 Action:
setCurrentPatientType: createAction<PatientType | null>
- 设置当前患者类型
bodyPartSlice.ts
- 身体部位切片位置: src/states/bodyPartSlice.ts
State 结构:
interface BodyPartState {
items: BodyPart[]; // 所有身体部位列表
loading: boolean;
error: string | null;
byPatientType: BodyPart[]; // 根据患者类型过滤后的身体部位
current: BodyPart | null; // 当前选中的身体部位
}
关键 Reducer:
setCurrentBodyPart
- 设置当前身体部位监听关系:
setCurrentPatientType
,根据患者类型过滤身体部位列表viewSelection/index.ts
- 体位选择切片(核心)位置: src/states/patient/viewSelection/index.ts
State 结构:
interface ViewSelectionState {
selectedViews: ExtendedView[]; // ⭐ 已选择体位列表(本次需求要清空的)
availableViews: View[]; // 待选择体位列表
protocols: Procedure[]; // 协议列表
currentBodyPart: BodyPart | null;
currentPatientType: PatientType | null;
currentSelectionType: { selected: 'protocol' | 'view' };
}
关键 Reducers:
addSelectedView
- 添加单个体位到已选列表clearSelectedViews
- 清空已选体位列表removeSelectedView
- 移除单个已选体位监听关系:
setCurrentPatientType
- 更新当前患者类型,清空协议和待选体位setCurrentBodyPart
- 更新当前身体部位,清空协议和待选体位setSelected
- 更新选择模式(协议/体位)SelectionTypeSlice.ts
- 选择类型切片位置: src/states/patient/register/SelectionTypeSlice.ts
State 结构:
interface SelectionState {
selected: 'protocol' | 'view'; // 当前选择模式:协议或体位
}
关键 Action:
setSelected
- 切换选择模式// 在 patientTypeSlice.ts 中
export const setCurrentPatientType = createAction<PatientType | null>(
'patientType/setCurrentPatientType'
);
这个 action 被多个 slice 监听:
bodyPartSlice
- 过滤身体部位viewSelectionSlice
- 清空协议和待选体位// 在各自的 slice 中定义
setCurrentBodyPart; // bodyPartSlice
setSelected; // SelectionTypeSlice
addSelectedView; // viewSelectionSlice
clearSelectedViews; // viewSelectionSlice
用户选择患者类型
↓
dispatch(setCurrentPatientType(patientType))
↓
├─→ patientTypeSlice
│ └─→ 更新 state.current
│
├─→ bodyPartSlice (监听)
│ └─→ 过滤身体部位: state.byPatientType = filter(items, patientTypeId)
│ └─→ 清空当前选择: state.current = null
│
└─→ viewSelectionSlice (监听)
└─→ 更新 state.currentPatientType
└─→ 清空 state.protocols = []
└─→ 清空 state.availableViews = []
└─→ ⭐ 需要添加:清空 state.selectedViews = []
在 viewSelectionSlice
的 extraReducers 中:
.addCase(setCurrentPatientType, (state, action) => {
const currentPatientType = action.payload;
if (currentPatientType) {
state.currentPatientType = currentPatientType;
} else {
// 患者类型被清空,清空相关数据
state.currentPatientType = null;
state.protocols = [];
state.availableViews = [];
console.log('患者类型已清空,协议和体位列表已重置');
}
// ⚠️ 问题:这里没有清空 selectedViews
})
问题: 当患者类型改变时,只清空了 protocols
和 availableViews
,但没有清空 selectedViews
(已选择体位列表)。
文件: src/states/patient/viewSelection/index.ts
修改的监听器: setCurrentPatientType
的 case 处理
修改前:
.addCase(setCurrentPatientType, (state, action) => {
const currentPatientType = action.payload;
if (currentPatientType) {
state.currentPatientType = currentPatientType;
} else {
// 患者类型被清空,清空相关数据
state.currentPatientType = null;
state.protocols = [];
state.availableViews = [];
console.log('患者类型已清空,协议和体位列表已重置');
}
})
修改后:
.addCase(setCurrentPatientType, (state, action) => {
const currentPatientType = action.payload;
if (currentPatientType) {
state.currentPatientType = currentPatientType;
} else {
// 患者类型被清空,清空相关数据
state.currentPatientType = null;
state.protocols = [];
state.availableViews = [];
console.log('患者类型已清空,协议和体位列表已重置');
}
// ⭐ 新增:无论是选择新患者类型还是清空,都清空已选择体位列表
state.selectedViews = [];
})
在 setCurrentPatientType
监听器的 if-else
代码块之后,添加一行:
state.selectedViews = [];
为什么放在 if-else 之后?
if
分支)else
分支)这样可以避免代码重复。
setCurrentBodyPart
监听器 - 保持不变
setSelected
监听器 - 保持不变
其他任何文件 - 都不需要修改
Given(前置条件):
When(操作步骤):
Then(预期结果):
selectedViews
为空数组Given(前置条件):
When(操作步骤):
Then(预期结果):
selectedViews
保持原有内容Given(前置条件):
When(操作步骤):
Then(预期结果):
selectedViews
保持原有内容describe('viewSelectionSlice - setCurrentPatientType', () => {
it('should clear selectedViews when patient type changes', () => {
const initialState = {
selectedViews: [
{ view_id: 'View_1', guid: 'guid-1' },
{ view_id: 'View_2', guid: 'guid-2' },
],
availableViews: [],
protocols: [],
currentBodyPart: null,
currentPatientType: { patient_type_id: 'Human' },
currentSelectionType: { selected: 'protocol' },
};
const newPatientType = {
patient_type_id: 'SpecialType',
patient_type_name: 'SpecialType',
};
const action = setCurrentPatientType(newPatientType);
const newState = viewSelectionReducer(initialState, action);
expect(newState.selectedViews).toEqual([]);
expect(newState.currentPatientType).toEqual(newPatientType);
});
});
功能验证:
selectedViews
被清空selectedViews
保持不变selectedViews
保持不变UI 验证:
边界情况:
src/states/patient/viewSelection/index.ts
src/states/patientTypeSlice.ts
src/states/bodyPartSlice.ts
src/states/patient/register/SelectionTypeSlice.ts
src/domain/patient/registerLogic.ts
(使用 selectedViews 的地方)Redux Toolkit 的 Immer 集成:
state.selectedViews = []
来修改状态Action 监听顺序:
setCurrentPatientType
是一个独立创建的 action日志输出:
selectedViews
后添加日志,方便调试console.log('患者类型已变更,已选择体位列表已清空')
当切换患者类型导致已选体位被清空时,是否需要:
建议: 根据业务需要决定。如果用户可能误操作,建议添加确认对话框。
日期 | 修改人 | 修改内容 |
---|---|---|
2025/10/7 | - | 创建文档,定义需求和实现方案 |