以急诊身份登录系统后,退出到登录页面,然后使用正常账号登录,会直接进入检查页面,跳过了注册页面。
在 src/domain/patient/handleEmergencyOperation.ts 中,急诊登录时会设置多个状态:
// Step 2: Set system mode to Emergency
dispatch(setSystemMode(SystemMode.Emergency));
// Step 3: Set temporary user info with guest token
dispatch(setUserInfo({
token: guestToken,
expire: Date.now() + 24 * 60 * 60 * 1000,
uid: -1, // Special uid to identify emergency mode
name: 'Emergency User',
avatar: '',
}));
// Step 6: Save registration result to cache
const task = mapToTask(registrationResult.data);
dispatch(addWork(task)); // ← 添加急诊工单到缓存
// Step 7: Proceed to Examination
dispatch(setBusinessFlow('exam')); // ← 设置业务流程为检查页面
在修复前,src/components/ExitModal.tsx 的注销逻辑只清除了:
case 'logout':
actionName = '注销用户';
dispatch(clearUserInfo()); // ✅ 清除用户信息
dispatch(setSystemMode(SystemMode.Normal)); // ✅ 重置系统模式
message.success('已退出登录');
onClose();
return;
关键问题:注销时没有重置以下状态:
BusinessFlow.currentKey - 仍然是 'exam'examWorksCache.works - 仍包含急诊工单数据bodyPositionList.bodyPositions - 仍包含急诊体位数据bodyPositionList.selectedBodyPosition - 仍有选中的体位注销操作
↓
只清除 userInfo 和 systemMode
↓
BusinessFlow.currentKey 仍然是 'exam'
examWorksCache.works 仍包含急诊患者数据
bodyPositionList 仍包含急诊体位数据
↓
用户重新登录(普通账号)
↓
系统检测到 BusinessFlow.currentKey === 'exam'
↓
直接渲染检查页面
↓
用户看到上一个急诊患者的数据!(数据泄露)
const initialState: BusinessFlowState = {
currentKey: 'register', // ← 默认应该是注册页面
lastKey: '',
shouldKeepSelection: false,
keptSelectionSopUid: undefined,
};
const initialState: ExamWorksCacheState = {
works: [], // ← 默认是空数组
loading: false,
};
const initialState: BodyPositionListState = {
bodyPositions: [], // ← 默认是空数组
selectedBodyPosition: null, // ← 默认是 null
exposureStatus: null,
loading: false,
error: null,
};
如果不清理以下状态,会导致严重的患者隐私泄露:
examWorksCache.works - 包含患者信息:
bodyPositionList.bodyPositions - 包含详细的检查数据:
优点:
缺点:
优点:
缺点:
在 src/components/ExitModal.tsx 中完整清理所有相关状态:
case 'logout':
actionName = '注销用户';
// 应用级注销:清除所有用户相关状态
// 1. 清除用户信息
dispatch(clearUserInfo());
// 2. 重置系统模式,避免急诊模式注销后黑屏
dispatch(setSystemMode(SystemMode.Normal));
// 3. 重置业务流程到注册页面,避免直接进入检查页面
dispatch(setBusinessFlow('register'));
// 4. 清理工单缓存,避免患者数据泄露
dispatch(clearWorks());
// 5. 清理体位列表,避免患者数据泄露
dispatch(setBodyPositions([]));
dispatch(setSelectedBodyPosition(null));
message.success('已退出登录');
onClose();
return;
新增导入:
import { setBusinessFlow } from '../states/BusinessFlowSlice';
import { clearWorks } from '../states/exam/examWorksCacheSlice';
import {
setBodyPositions,
setSelectedBodyPosition,
} from '../states/exam/bodyPositionListSlice';
修改注销逻辑:添加了3个额外的状态清理操作。
| 序号 | State | 清理方法 | 原因 |
|---|---|---|---|
| 1 | userInfo |
clearUserInfo() |
清除用户登录信息 |
| 2 | systemMode |
setSystemMode(SystemMode.Normal) |
重置系统模式,避免黑屏 |
| 3 | BusinessFlow |
setBusinessFlow('register') |
重置到注册页面,避免直接进入检查 |
| 4 | examWorksCache |
clearWorks() |
清理工单缓存,避免患者数据泄露 |
| 5 | bodyPositionList |
setBodyPositions([]) + setSelectedBodyPosition(null) |
清理体位数据,避免患者数据泄露 |
注销后应确保:
userInfo.token = ''userInfo.uid = 0systemMode = 'Normal'BusinessFlow.currentKey = 'register'examWorksCache.works = []bodyPositionList.bodyPositions = []bodyPositionList.selectedBodyPosition = nullloggedIn = falsesrc/components/ExitModal.tsx数据安全:
业务逻辑:
与已有功能的兼容性:
状态管理最佳实践:
添加 Cypress 测试:
考虑添加统一的清理 action:
reset 或 clear action添加状态监控:
安全审计: