306 lines
8.8 KiB
Markdown
306 lines
8.8 KiB
Markdown
# 合同起草页面 UI 修复
|
||
|
||
## 修复内容
|
||
|
||
### 1. 修复 `json` 弃用警告
|
||
|
||
**问题**:
|
||
```
|
||
"json"已弃用。ts(6385)
|
||
This utility is deprecated in favor of opting into Single Fetch via future.v3_singleFetch
|
||
and returning raw objects. This method will be removed in React Router v7.
|
||
```
|
||
|
||
**解决方案**:
|
||
使用 `Response.json()` 替代 Remix 的 `json()` 函数。
|
||
|
||
**修改的代码**:
|
||
|
||
```typescript
|
||
// ❌ 旧代码(已弃用)
|
||
import { json, redirect } from '@remix-run/node';
|
||
|
||
export async function loader() {
|
||
return json({ data });
|
||
}
|
||
|
||
export async function action() {
|
||
return json({ success: true }, { status: 200 });
|
||
}
|
||
```
|
||
|
||
```typescript
|
||
// ✅ 新代码(使用标准 Web API)
|
||
import { redirect } from '@remix-run/node';
|
||
|
||
export async function loader() {
|
||
return Response.json({ data });
|
||
}
|
||
|
||
export async function action() {
|
||
return Response.json({ success: true }, { status: 200 });
|
||
}
|
||
```
|
||
|
||
**优势**:
|
||
- 使用标准 Web API,兼容性更好
|
||
- 未来 React Router v7 不会移除
|
||
- 符合现代 Web 标准
|
||
|
||
### 2. 修复 FilePreview 高度问题
|
||
|
||
**问题**:
|
||
FilePreview 组件没有占满父级容器的高度,导致页面布局不完整。
|
||
|
||
**根本原因**:
|
||
1. 父容器没有高度限制
|
||
2. FilePreview 根元素没有设置 `h-full`
|
||
3. 内容区域使用固定的 `maxHeight: calc(100vh - 150px)`,不适用于嵌套布局
|
||
|
||
**解决方案**:
|
||
|
||
#### 修改 1:父容器添加高度
|
||
|
||
`app/routes/contract-draft.$draftId.tsx`:
|
||
|
||
```typescript
|
||
// ❌ 旧代码
|
||
<div className="w-[60%] border-r border-gray-200 bg-white">
|
||
<FilePreview ... />
|
||
</div>
|
||
|
||
<div className="w-[40%] bg-white">
|
||
<PlaceholderForm ... />
|
||
</div>
|
||
```
|
||
|
||
```typescript
|
||
// ✅ 新代码
|
||
<div className="w-[60%] border-r border-gray-200 bg-white h-full overflow-hidden">
|
||
<FilePreview ... />
|
||
</div>
|
||
|
||
<div className="w-[40%] bg-white h-full overflow-hidden">
|
||
<PlaceholderForm ... />
|
||
</div>
|
||
```
|
||
|
||
**变化**:
|
||
- 添加 `h-full` - 高度占满父容器
|
||
- 添加 `overflow-hidden` - 防止内容溢出
|
||
|
||
#### 修改 2:FilePreview 根元素使用 Flex 布局
|
||
|
||
`app/components/reviews/FilePreview.tsx`:
|
||
|
||
```typescript
|
||
// ❌ 旧代码
|
||
return (
|
||
<div className="file-preview">
|
||
<div className="file-preview-header ...">...</div>
|
||
<div className="file-preview-content" style={{ maxHeight: 'calc(100vh - 150px)' }}>...</div>
|
||
</div>
|
||
);
|
||
```
|
||
|
||
```typescript
|
||
// ✅ 新代码
|
||
return (
|
||
<div className="file-preview h-full flex flex-col">
|
||
<div className="file-preview-header ... flex-shrink-0">...</div>
|
||
<div className="file-preview-content flex-1 overflow-auto">...</div>
|
||
</div>
|
||
);
|
||
```
|
||
|
||
**变化**:
|
||
- 根元素:添加 `h-full flex flex-col` - 占满高度,使用垂直 Flex 布局
|
||
- Header:添加 `flex-shrink-0` - 固定高度,不压缩
|
||
- Content:使用 `flex-1 overflow-auto` 替代固定 `maxHeight` - 占据剩余空间,自动滚动
|
||
|
||
## 布局原理
|
||
|
||
### Flex 布局结构
|
||
|
||
```
|
||
┌─────────────────────────────────────────┐
|
||
│ h-screen flex flex-col │ ← 全屏容器
|
||
├─────────────────────────────────────────┤
|
||
│ 顶部工具栏 (固定高度) │ ← flex-shrink-0
|
||
├─────────────────────────────────────────┤
|
||
│ flex-1 flex overflow-hidden │ ← 主内容区(占据剩余空间)
|
||
│ ┌─────────────┬─────────────────────┐ │
|
||
│ │ w-[60%] │ w-[40%] │ │
|
||
│ │ h-full │ h-full │ │
|
||
│ │ ┌─────────┐ │ ┌─────────────────┐ │ │
|
||
│ │ │FilePreview│ │PlaceholderForm │ │ │
|
||
│ │ │h-full │ │ │ │ │
|
||
│ │ │flex-col │ │ │ │ │
|
||
│ │ │┌────────┐│ │ │ │ │
|
||
│ │ ││Header ││ │ │ │ │
|
||
│ │ ││(固定) ││ │ │ │ │
|
||
│ │ │├────────┤│ │ │ │ │
|
||
│ │ ││Content ││ │ │ │ │
|
||
│ │ ││flex-1 ││ │ │ │ │
|
||
│ │ ││(自适应)││ │ │ │ │
|
||
│ │ │└────────┘│ │ │ │ │
|
||
│ │ └─────────┘ │ └─────────────────┘ │ │
|
||
│ └─────────────┴─────────────────────┘ │
|
||
└─────────────────────────────────────────┘
|
||
```
|
||
|
||
### 关键 CSS 类
|
||
|
||
| 类名 | 作用 | 使用位置 |
|
||
|------|------|----------|
|
||
| `h-screen` | 高度 100vh | 根容器 |
|
||
| `flex flex-col` | 垂直 Flex 布局 | 根容器、FilePreview |
|
||
| `flex-1` | 占据剩余空间 | 主内容区、Content |
|
||
| `h-full` | 高度 100% | 左右侧容器、FilePreview |
|
||
| `overflow-hidden` | 隐藏溢出 | 左右侧容器 |
|
||
| `overflow-auto` | 自动滚动 | Content 区域 |
|
||
| `flex-shrink-0` | 不压缩 | Header |
|
||
|
||
## 测试验证
|
||
|
||
### 1. 启动开发服务器
|
||
|
||
```bash
|
||
npm run dev
|
||
```
|
||
|
||
### 2. 访问草稿页面
|
||
|
||
```
|
||
http://localhost:5173/contract-draft/1
|
||
```
|
||
|
||
### 3. 验证布局
|
||
|
||
✅ **应该看到**:
|
||
- 页面占满整个屏幕(无滚动条)
|
||
- 左侧文档预览占 60% 宽度,**高度占满**
|
||
- 右侧表单占 40% 宽度,**高度占满**
|
||
- FilePreview 内容区域可以独立滚动
|
||
- 表单区域可以独立滚动
|
||
|
||
✅ **不应该看到**:
|
||
- FilePreview 底部有空白
|
||
- 页面外层有滚动条(应该在内容区域内滚动)
|
||
- 布局错乱或内容溢出
|
||
|
||
### 4. 响应式测试
|
||
|
||
- 调整浏览器窗口大小
|
||
- FilePreview 和 PlaceholderForm 应该始终占满高度
|
||
- 内容区域应该自动调整滚动
|
||
|
||
## 修改的文件
|
||
|
||
### 1. `app/routes/contract-draft.$draftId.tsx`
|
||
|
||
**变化**:
|
||
- ✅ 移除 `json` 导入
|
||
- ✅ 所有 `json()` 替换为 `Response.json()`
|
||
- ✅ 左右侧容器添加 `h-full overflow-hidden`
|
||
|
||
**位置**:
|
||
- Line 7: 移除 `json` 导入
|
||
- Line 104: `Response.json({ draft, template })`
|
||
- Line 117, 123, 138, 141, 144: `Response.json()`
|
||
- Line 353, 374: 添加 `h-full overflow-hidden`
|
||
|
||
### 2. `app/components/reviews/FilePreview.tsx`
|
||
|
||
**变化**:
|
||
- ✅ 根元素添加 `h-full flex flex-col`
|
||
- ✅ Header 添加 `flex-shrink-0`
|
||
- ✅ Content 改用 `flex-1 overflow-auto`,移除固定 `maxHeight`
|
||
|
||
**位置**:
|
||
- Line 429: `<div className="file-preview h-full flex flex-col">`
|
||
- Line 430: Header 添加 `flex-shrink-0`
|
||
- Line 525: `<div className="file-preview-content flex-1 overflow-auto">`
|
||
|
||
## 常见问题
|
||
|
||
### Q1: FilePreview 仍然没有占满高度
|
||
|
||
**原因**:浏览器缓存了旧的样式
|
||
|
||
**解决**:
|
||
1. 硬刷新页面(Ctrl+Shift+R 或 Cmd+Shift+R)
|
||
2. 清除浏览器缓存
|
||
3. 重启开发服务器
|
||
|
||
### Q2: 内容区域滚动不流畅
|
||
|
||
**原因**:可能是 `overflow-hidden` 和 `overflow-auto` 冲突
|
||
|
||
**解决**:
|
||
确保父容器使用 `overflow-hidden`,子容器(内容区域)使用 `overflow-auto`
|
||
|
||
### Q3: 在其他页面 FilePreview 布局变了
|
||
|
||
**影响范围**:此修改影响所有使用 FilePreview 的页面
|
||
|
||
**如果出现问题**:
|
||
- 检查该页面的父容器是否有足够的高度
|
||
- 可能需要给父容器添加 `h-full` 或明确的高度值
|
||
- 或者给 FilePreview 添加一个 prop 来控制是否使用 flex 布局
|
||
|
||
### Q4: 响应式布局问题
|
||
|
||
**现象**:小屏幕下布局错乱
|
||
|
||
**解决**:
|
||
可以添加响应式类,例���:
|
||
```typescript
|
||
<div className="w-full md:w-[60%] h-full overflow-hidden">
|
||
```
|
||
|
||
## 后续优化
|
||
|
||
### 1. 添加 prop 控制布局模式(可选)
|
||
|
||
```typescript
|
||
interface FilePreviewProps {
|
||
// ... existing props
|
||
layoutMode?: 'flex' | 'fixed'; // 新增:控制布局模式
|
||
}
|
||
|
||
// 在组件中使用
|
||
<div className={`file-preview ${layoutMode === 'flex' ? 'h-full flex flex-col' : ''}`}>
|
||
```
|
||
|
||
### 2. 优化滚动性能
|
||
|
||
```typescript
|
||
<div
|
||
className="file-preview-content flex-1 overflow-auto"
|
||
style={{ scrollBehavior: 'smooth' }} // 平滑滚动
|
||
>
|
||
```
|
||
|
||
### 3. 添加加载状态
|
||
|
||
在文档加载时显示骨架屏或加载动画,占满高度,避免布局跳动。
|
||
|
||
## 总结
|
||
|
||
✅ **已修复**:
|
||
1. `json` 弃用警告 - 使用 `Response.json()`
|
||
2. FilePreview 高度问题 - 使用 Flex 布局占满父容器
|
||
|
||
✅ **布局改进**:
|
||
- 使用现代 Flex 布局替代固定高度
|
||
- 更好的响应式支持
|
||
- 内容区域独立滚动
|
||
|
||
✅ **代码质量**:
|
||
- 符合 Web 标准
|
||
- 更易维护
|
||
- 类型检查通过
|
||
|
||
🎯 **可以开始测试了**!页面布局应该正常了。
|