unis_sip/oms_web/docs/components/DetailDrawer.md

470 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# DetailDrawer 组件
## 组件说明
详情抽屉组件,用于从页面右侧滑出显示详细信息。支持自定义标题、操作按钮、标签页等功能,内容区域可滚动,顶部标题栏固定。
## 组件位置
```
src/components/DetailDrawer/DetailDrawer.jsx
src/components/DetailDrawer/DetailDrawer.css
```
## 参数说明
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|--------|------|------|--------|------|
| visible | boolean | 是 | - | 是否显示抽屉 |
| onClose | function | 是 | - | 关闭抽屉回调 |
| title | TitleConfig | 否 | - | 标题配置对象 |
| headerActions | Array<ActionConfig> | 否 | [] | 顶部操作按钮数组 |
| width | number | 否 | 1080 | 抽屉宽度(像素) |
| children | ReactNode | 否 | - | 主要内容区域 |
| tabs | Array<TabConfig> | 否 | - | 标签页配置数组 |
### 1. 小型抽屉 (Small) - 480px
**适用场景:**
- 简单的信息展示
- 少量字段的表单1-3个字段
- 快速操作面板
- 通知详情
**示例:**
```jsx
<Drawer width={480} ... />
```
### 2. 中型抽屉 (Medium) - 720px
**适用场景:**
- 详细信息展示(如主机详情)
- 中等复杂度的表单4-10个字段
- 数据编辑面板
- 配置设置
**示例:**
```jsx
<Drawer width={720} ... />
```
**当前主机列表页面使用此宽度模式**
### 3. 大型抽屉 (Large) - 1080px
**适用场景:**
- 复杂的多步骤表单
- 需要并排展示多列信息
- 包含图表或复杂可视化内容
- 嵌套子表格或列表
**示例:**
```jsx
<Drawer width={1080} ... />
```
### TitleConfig 配置项
| 属性名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| text | string | 是 | 标题文本 |
| badge | ReactNode | 否 | 状态徽标(如 Tag、Badge 组件) |
| icon | ReactNode | 否 | 标题图标 |
### ActionConfig 配置项
| 属性名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| key | string | 是 | 按钮唯一标识 |
| label | string | 是 | 按钮文本 |
| icon | ReactNode | 否 | 按钮图标 |
| type | string | 否 | 按钮类型primary/default/dashed/text/link |
| danger | boolean | 否 | 是否为危险按钮 |
| disabled | boolean | 否 | 是否禁用 |
| onClick | function | 否 | 点击回调函数 |
### TabConfig 配置项
| 属性名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| key | string | 是 | 标签页唯一标识 |
| label | ReactNode | 是 | 标签页标题(支持图标+文字) |
| content | ReactNode | 是 | 标签页内容 |
## 使用示例
### 基础用法
```jsx
import { useState } from 'react'
import DetailDrawer from '../components/DetailDrawer/DetailDrawer'
function MyPage() {
const [showDrawer, setShowDrawer] = useState(false)
const [selectedItem, setSelectedItem] = useState(null)
return (
<>
<Button onClick={() => setShowDrawer(true)}>查看详情</Button>
<DetailDrawer
visible={showDrawer}
onClose={() => setShowDrawer(false)}
title={{
text: selectedItem?.name || '详情',
}}
>
<div style={{ padding: 24 }}>
<p>详情内容</p>
</div>
</DetailDrawer>
</>
)
}
```
### 带状态徽标
```jsx
import { Tag, Badge } from 'antd'
<DetailDrawer
visible={showDetailDrawer}
onClose={() => setShowDetailDrawer(false)}
title={{
text: selectedUser?.userName || '',
badge: (
<Tag color={selectedUser?.status === 'enabled' ? 'green' : 'default'}>
{selectedUser?.status === 'enabled' ? '启用' : '停用'}
</Tag>
),
}}
>
{/* 内容 */}
</DetailDrawer>
```
### 带操作按钮
```jsx
import { EditOutlined, DeleteOutlined } from '@ant-design/icons'
<DetailDrawer
visible={showDetailDrawer}
onClose={() => setShowDetailDrawer(false)}
title={{
text: selectedUser?.userName || '',
}}
headerActions={[
{
key: 'edit',
label: '编辑',
icon: <EditOutlined />,
onClick: () => {
setEditMode('edit')
setShowEditDrawer(true)
setShowDetailDrawer(false)
},
},
{
key: 'delete',
label: '删除',
icon: <DeleteOutlined />,
danger: true,
onClick: () => {
setShowDetailDrawer(false)
handleDelete(selectedUser)
},
},
]}
>
{/* 内容 */}
</DetailDrawer>
```
### 使用 InfoPanel 显示信息
```jsx
import DetailDrawer from '../components/DetailDrawer/DetailDrawer'
import InfoPanel from '../components/InfoPanel/InfoPanel'
const userFields = [
{ key: 'userName', label: '用户名', span: 6 },
{ key: 'group', label: '用户分组', span: 6 },
{ key: 'name', label: '姓名', span: 6 },
{ key: 'userType', label: '用户类型', span: 6 },
{
key: 'status',
label: '状态',
span: 6,
render: (value) => (
<Tag color={value === 'enabled' ? 'green' : 'default'}>
{value === 'enabled' ? '启用' : '停用'}
</Tag>
),
},
]
<DetailDrawer
visible={showDetailDrawer}
onClose={() => setShowDetailDrawer(false)}
title={{
text: selectedUser?.userName || '',
}}
>
<InfoPanel
data={selectedUser}
fields={userFields}
actions={[
{ key: 'reset', label: '重置密码', onClick: () => console.log('重置密码') },
{ key: 'disable', label: '停用', onClick: () => console.log('停用') },
]}
/>
</DetailDrawer>
```
### 带标签页
```jsx
import { DatabaseOutlined, UserOutlined } from '@ant-design/icons'
<DetailDrawer
visible={showDetailDrawer}
onClose={() => setShowDetailDrawer(false)}
title={{
text: selectedHost?.name || '',
badge: (
<Badge
status={selectedHost?.status === 'online' ? 'success' : 'default'}
text={selectedHost?.status === 'online' ? '在线' : '离线'}
/>
),
}}
headerActions={[
{
key: 'edit',
label: '编辑',
icon: <EditOutlined />,
onClick: handleEdit,
},
]}
width={1080}
tabs={[
{
key: 'images',
label: (
<span>
<DatabaseOutlined style={{ marginRight: 8 }} />
终端镜像
</span>
),
content: (
<div className="card-list">
{/* 镜像列表内容 */}
</div>
),
},
{
key: 'users',
label: (
<span>
<UserOutlined style={{ marginRight: 8 }} />
终端用户
</span>
),
content: (
<div className="card-list">
{/* 用户列表内容 */}
</div>
),
},
]}
>
<InfoPanel data={selectedHost} fields={hostFields} />
</DetailDrawer>
```
### 完整示例
```jsx
import { useState } from 'react'
import DetailDrawer from '../components/DetailDrawer/DetailDrawer'
import InfoPanel from '../components/InfoPanel/InfoPanel'
import { Tag, Badge, Card } from 'antd'
import { EditOutlined, DeleteOutlined, DatabaseOutlined, UserOutlined } from '@ant-design/icons'
function UserListPage() {
const [showDetailDrawer, setShowDetailDrawer] = useState(false)
const [selectedUser, setSelectedUser] = useState(null)
const userFields = [
{ key: 'userName', label: '用户名', span: 6 },
{ key: 'group', label: '用户分组', span: 6 },
{ key: 'name', label: '姓名', span: 6 },
{ key: 'grantedImages', label: '授权镜像', span: 6 },
{ key: 'userType', label: '用户类型', span: 6 },
{ key: 'grantedTerminals', label: '授权终端', span: 6 },
{
key: 'status',
label: '启停用',
span: 6,
render: (value) => (
<Tag color={value === 'enabled' ? 'green' : 'default'}>
{value === 'enabled' ? '启用' : '停用'}
</Tag>
),
},
]
const detailTabs = [
{
key: 'terminals',
label: (
<span>
<DesktopOutlined style={{ marginRight: 8 }} />
授权终端
</span>
),
content: (
<div className="card-list">
{selectedUser?.terminals?.map((terminal) => (
<Card key={terminal.id}>
<h4>{terminal.name}</h4>
<p>IP: {terminal.ip}</p>
</Card>
))}
</div>
),
},
{
key: 'images',
label: (
<span>
<DatabaseOutlined style={{ marginRight: 8 }} />
授权镜像
</span>
),
content: (
<div className="card-list">
{selectedUser?.images?.map((image) => (
<Card key={image.id}>
<h4>{image.name}</h4>
<p>系统: {image.os}</p>
</Card>
))}
</div>
),
},
]
return (
<>
{/* 列表页面 */}
<ListTable
columns={columns}
dataSource={users}
onRowClick={(record) => {
setSelectedUser(record)
setShowDetailDrawer(true)
}}
/>
{/* 详情抽屉 */}
<DetailDrawer
visible={showDetailDrawer}
onClose={() => setShowDetailDrawer(false)}
title={{
text: selectedUser?.userName || '',
badge: (
<Tag color={selectedUser?.status === 'enabled' ? 'green' : 'default'}>
{selectedUser?.status === 'enabled' ? '启用' : '停用'}
</Tag>
),
}}
headerActions={[
{
key: 'edit',
label: '编辑',
icon: <EditOutlined />,
onClick: () => {
setShowDetailDrawer(false)
handleEdit(selectedUser)
},
},
{
key: 'delete',
label: '删除',
icon: <DeleteOutlined />,
danger: true,
onClick: () => {
setShowDetailDrawer(false)
handleDelete(selectedUser)
},
},
]}
width={1080}
tabs={detailTabs}
>
<InfoPanel
data={selectedUser}
fields={userFields}
actions={[
{ key: 'move', label: '转移分组', type: 'primary', onClick: () => console.log('转移分组') },
{ key: 'reset', label: '重置密码', onClick: () => console.log('重置密码') },
{ key: 'disable', label: '停用', onClick: () => console.log('停用') },
]}
/>
</DetailDrawer>
</>
)
}
```
## 布局结构
抽屉采用固定头部、可滚动内容的布局:
```
┌─────────────────────────────────────┐
│ 标题栏(固定,不滚动) │
│ [关闭] [标题] [徽标] [操作按钮] │
├─────────────────────────────────────┤
│ │
│ 内容区域(可滚动) │
│ - children 主要内容 │
│ - tabs 标签页(可选) │
│ │
└─────────────────────────────────────┘
```
## 样式定制
组件提供以下 CSS 类名供自定义样式:
- `.detail-drawer-content` - 抽屉内容容器
- `.detail-drawer-header` - 顶部标题栏
- `.detail-drawer-header-left` - 标题栏左侧区域
- `.detail-drawer-header-right` - 标题栏右侧区域
- `.detail-drawer-close-button` - 关闭按钮
- `.detail-drawer-header-info` - 标题信息容器
- `.detail-drawer-title-icon` - 标题图标
- `.detail-drawer-title` - 标题文本
- `.detail-drawer-badge` - 徽标容器
- `.detail-drawer-scrollable-content` - 可滚动内容区域
- `.detail-drawer-tabs` - 标签页容器
- `.detail-drawer-tab-content` - 标签页内容
## 使用场景
1. **查看详细信息** - 点击列表行显示详细信息
2. **多标签页详情** - 在详情中展示不同类型的关联数据
3. **带快捷操作的详情** - 在详情顶部提供编辑、删除等操作
4. **复杂数据展示** - 配合 InfoPanel、Card 等组件展示复杂信息
## 注意事项
1. 抽屉宽度默认 1080px可根据内容调整建议取值范围720-1200px
2. 标题栏固定在顶部,不随内容滚动,确保操作按钮始终可见
3. `children` 内容区域会自动应用内边距,`tabs` 内容需要自行控制样式
4. 操作按钮数量不宜过多,建议不超过 3 个
5. 使用 `tabs` 时,第一个标签页默认激活
6. 关闭抽屉时建议清空选中状态,避免下次打开时显示旧数据
7. 配合 InfoPanel 使用时InfoPanel 会自动处理内边距