fix: 修复页面间状态丢失问题并优化选择页面
- 修复选择审批人后再选择抄送人导致状态丢失的问题 - 使用独立的 sessionStorage key (selectedApprovers, selectedCc) - 组件每次挂载时从 sessionStorage 恢复状态 - 只在提交/保存成功后清除 sessionStorage - 优化人员选择页面布局和样式 - 更新 CLAUDE.md 文档记录问题和解决方案 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -180,6 +180,127 @@ docker logs x-server-backend -f
|
||||
|
||||
## 已知问题和解决方案
|
||||
|
||||
### 页面间状态丢失问题 ⚠️ 重要!
|
||||
|
||||
#### 问题1:navigate(-1) 不传递 state
|
||||
**现象:** 使用 `navigate(-1, { state })` 返回上一页时,`location.state` 为 `null`
|
||||
|
||||
**原因:** React Router 在使用 `navigate(-1)` 时,`state` 参数不可靠
|
||||
|
||||
**解决方案:** 使用 sessionStorage 传递数据
|
||||
|
||||
#### 问题2:多次选择导致状态丢失
|
||||
**现象:**
|
||||
- 选择审批人后,再选择抄送人,审批人状态丢失
|
||||
- 先选择抄送人,再选择审批人,抄送人状态丢失
|
||||
|
||||
**原因:**
|
||||
- 每次导航时,目标页面组件会重新挂载
|
||||
- 重新挂载时,所有 useState 都会重置为初始值
|
||||
- sessionStorage 在第一次读取后被清除,第二次挂载时无数据可恢复
|
||||
|
||||
**解决方案:**
|
||||
1. **使用独立的 sessionStorage key**(不要共用一个 key)
|
||||
2. **不在 useEffect 中立即清除 sessionStorage**
|
||||
3. **每次挂载时从 sessionStorage 恢复状态**
|
||||
4. **只在业务操作完成后才清除 sessionStorage**(提交、保存等)
|
||||
|
||||
**正确实现:**
|
||||
|
||||
```tsx
|
||||
// 选择页面 - 使用独立的 key
|
||||
const handleConfirm = () => {
|
||||
if (type === 'approver') {
|
||||
sessionStorage.setItem('selectedApprovers', JSON.stringify(selectedUsers))
|
||||
} else if (type === 'cc') {
|
||||
sessionStorage.setItem('selectedCc', JSON.stringify(selectedUsers))
|
||||
}
|
||||
navigate(-1)
|
||||
}
|
||||
|
||||
// 申请页面 - 每次挂载时恢复状态
|
||||
useEffect(() => {
|
||||
const approversData = sessionStorage.getItem('selectedApprovers')
|
||||
const ccData = sessionStorage.getItem('selectedCc')
|
||||
|
||||
if (approversData) {
|
||||
setApprovers(JSON.parse(approversData))
|
||||
}
|
||||
if (ccData) {
|
||||
setCcUsers(JSON.parse(ccData))
|
||||
}
|
||||
}, [])
|
||||
|
||||
// 提交/保存成功后清除
|
||||
const handleSubmit = async () => {
|
||||
// ... 提交逻辑 ...
|
||||
sessionStorage.removeItem('selectedApprovers')
|
||||
sessionStorage.removeItem('selectedCc')
|
||||
navigate('/business-trip')
|
||||
}
|
||||
```
|
||||
|
||||
**关键点:**
|
||||
- ✅ 不同类型数据使用独立的 sessionStorage key
|
||||
- ✅ 不在 useEffect 中清除 sessionStorage
|
||||
- ✅ 每次挂载都恢复状态,确保组件重新挂载时状态不丢失
|
||||
- ✅ 只在业务操作完成后清除 sessionStorage
|
||||
|
||||
**相关文件:**
|
||||
- `frontend/src/pages/business-trip/select-approver.tsx`
|
||||
- `frontend/src/pages/business-trip/select-cc.tsx`
|
||||
- `frontend/src/pages/business-trip/apply.tsx`
|
||||
|
||||
### Ant Design Mobile DatePicker 点击无反应
|
||||
**问题:** DatePicker 组件使用 children render prop 方式时,点击无法弹出选择框
|
||||
|
||||
**原因:** antd-mobile 5.x 的 DatePicker children render prop 点击事件绑定存在问题
|
||||
|
||||
**解决方案:** 使用 `visible` 属性手动控制弹框显示
|
||||
|
||||
```tsx
|
||||
// ❌ 错误用法 - 点击无反应
|
||||
<DatePicker value={value} onConfirm={setValue}>
|
||||
{(value) => <button>{value ? '已选择' : '请选择'}</button>}
|
||||
</DatePicker>
|
||||
|
||||
// ✅ 正确用法 - 使用 visible 属性
|
||||
const [visible, setVisible] = useState(false)
|
||||
|
||||
<div onClick={() => setVisible(true)}>
|
||||
{value ? '已选择' : '请选择'}
|
||||
</div>
|
||||
<DatePicker
|
||||
visible={visible}
|
||||
onConfirm={(val) => {
|
||||
setValue(val)
|
||||
setVisible(false)
|
||||
}}
|
||||
onClose={() => setVisible(false)}
|
||||
onCancel={() => setVisible(false)}
|
||||
/>
|
||||
```
|
||||
|
||||
**相关文件:**
|
||||
- `frontend/src/main.tsx` - 需要导入 `import 'antd-mobile/es/global'`
|
||||
- `frontend/src/pages/business-trip/apply.tsx` - 正确使用示例
|
||||
|
||||
### Ant Design Mobile 全局样式导入
|
||||
**必须导入全局样式:**
|
||||
```tsx
|
||||
import 'antd-mobile/es/global'
|
||||
```
|
||||
|
||||
否则弹框、遮罩等组件将无法正常显示。
|
||||
|
||||
### Selector 组件对号图标隐藏
|
||||
**问题:** Selector 组件选中时显示对号图标和背景色,想要只保留背景色
|
||||
|
||||
**解决方案:** 使用 `showCheckMark` 属性
|
||||
```tsx
|
||||
<Selector showCheckMark={false} options={options} />
|
||||
```
|
||||
|
||||
### PSR-4 自动加载
|
||||
- 目录名必须是 PascalCase(Controller、Model、Service、Util)
|
||||
- 不能用小写(controller、model、service、util)
|
||||
|
||||
Reference in New Issue
Block a user