all in
This commit is contained in:
@@ -0,0 +1,305 @@
|
||||
# 合同起草页面 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 标准
|
||||
- 更易维护
|
||||
- 类型检查通过
|
||||
|
||||
🎯 **可以开始测试了**!页面布局应该正常了。
|
||||
Reference in New Issue
Block a user