fix: 修复页面间状态丢失问题并优化选择页面

- 修复选择审批人后再选择抄送人导致状态丢失的问题
- 使用独立的 sessionStorage key (selectedApprovers, selectedCc)
- 组件每次挂载时从 sessionStorage 恢复状态
- 只在提交/保存成功后清除 sessionStorage
- 优化人员选择页面布局和样式
- 更新 CLAUDE.md 文档记录问题和解决方案

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
root
2026-02-25 15:22:12 +08:00
parent 2d39357cc3
commit 09d4cb8054
51 changed files with 2944 additions and 647 deletions
+121
View File
@@ -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)