6.7 KiB
comet_change, role, canonical_spec, archived-with, status
| comet_change | role | canonical_spec | archived-with | status |
|---|---|---|---|---|
| admin-responsive-adaptation | technical-design | openspec | 2026-07-03-admin-responsive-adaptation | final |
管理后台三端响应式适配 — 技术设计
1. 架构概览
┌─────────────────────────────────────────────────────────────────┐
│ Admin Frontend │
├─────────────────────────────────────────────────────────────────┤
│ App.tsx │
│ └─ ConfigProvider (antd theme + locale) │
│ └─ BrowserRouter │
│ ├─ LoginPage │
│ └─ MainLayout │
│ ├─ Sider/Drawer (断点决定) │
│ ├─ Header (用户区域断点隐藏文字) │
│ └─ Content → <Outlet> │
│ ├─ Dashboard (统计卡片 + ECharts) │
│ ├─ RoomVisual (房态网格卡片) │
│ ├─ [14 个表格型页面] (Table + 搜索/操作工具栏) │
│ └─ ClassroomSchedule (HTML 排期大表) │
└─────────────────────────────────────────────────────────────────┘
2. 断点体系
使用 antd v6 内置 Grid.useBreakpoint() hook,映射三类设备行为:
| 端侧 | antd 断点 | 视口宽度 | 布局行为 |
|---|---|---|---|
| 手机 | xs |
< 576px | Drawer 抽屉菜单,padding 12px |
| 平板 | sm, md |
576-991px | 侧栏默认折叠,padding 16px |
| 桌面 | lg, xl, xxl |
≥ 992px | 侧栏可折叠(默认展开),padding 24px |
选择理由: 使用 antd 内置断点与 Row/Col 响应式 props 天然一致,避免维护两套断点逻辑。992px 与最初规划的 1024px 相差 32px,实际设备无感知。
3. 核心决策
3.1 MainLayout 响应式检测
当前: useState(window.innerWidth < 768) + resize 事件 → isMobile 布尔值
目标: Grid.useBreakpoint() → { xs, sm, md, lg, xl, xxl } 布尔值
const screens = Grid.useBreakpoint();
const isMobile = !screens.sm; // < 576px (仅 xs)
const isTablet = (screens.sm || screens.md) && !screens.lg; // 576-991px
const isDesktop = !!screens.lg; // ≥ 992px
影响范围:仅 MainLayout.tsx 一个文件,useEffect + resize 事件监听可移除。
3.2 CSS 策略:antd Props 优先
| 场景 | 优先方案 | 兜底方案 |
|---|---|---|
| 表格列过多 | scroll={{ x }} |
无(antd 自带滚动条) |
| 卡片网格 | Col 响应式断点 props |
index.css @media |
| 文字截断 | ellipsis: true |
text-overflow: ellipsis CSS |
| 弹窗宽度 | antd width prop |
index.css max-width 约束 |
| 工具栏换行 | flexWrap: 'wrap' + gap inline style |
— |
index.css 追加的 @media 规则(总计约 40 行):
(max-width: 575px): 表格字体 13px、弹窗 max-width 约束、Modal body max-height(min-width: 576px) and (max-width: 991px): 平板特有的间距微调- 通用:
.ant-table-wrapper { overflow-x: auto }确保所有表格容器可滚动
3.3 表格横向滚动
所有 <Table> 统一添加 scroll={{ x }}。具体值:
- 列少(≤6 列):
scroll={{ x: 'max-content' }}或省略(antd 自动处理) - 列中(7-10 列):
scroll={{ x: 800 }} - 列多(>10 列或含长文本列):
scroll={{ x: 1000 }}或更大
操作列(最后一列)使用 width 固定宽度,必要时添加 fixed: 'right' 在宽表场景下提升体验。
3.4 Dashboard 响应式网格
统计卡片 (4 张):
<Col xs={12} sm={12} md={6}> // 手机2列 平板2列 桌面4列
图表卡片 (2 张):
<Col xs={24} sm={12}> // 手机堆叠 平板及以上并排
顶部工具栏(标题 + DatePicker)在小屏下从 flex 横向排列改为 flexDirection: 'column' 堆叠。
3.5 ECharts 图表
通过 echarts-for-react 的内置 ResizeObserver 自动适配:
<ReactECharts
option={option}
style={{ width: '100%', height: isMobile ? 250 : 300 }}
opts={{ renderer: 'canvas' }}
/>
容器宽度由 antd Col 响应式断点控制,图表自动跟随。甘特图动态高度逻辑不变(Math.max(300, data.length * 40))。
3.6 弹窗适配
全局 CSS(index.css):
@media (max-width: 575px) {
.ant-modal { max-width: calc(100vw - 24px) !important; }
.ant-modal-body { max-height: 60vh; overflow-y: auto; }
}
组件级别: 各弹窗 width 在桌面端固定值(400-600px),移动端由全局 CSS 覆盖为 max-width 约束。
3.7 教室排期表
最复杂的适配场景 — HTML <table> 含 31+ 日期列 + sticky 首列:
- 外层
div保持overflowX: 'auto' - 首列(教室名)
position: sticky; left: 0保持已有 - 日期列
minWidth: 26不压窄 overflowX容器在平板/手机下自动出现横向滚动条
3.8 学生字段拆分
学生管理页将 { title: '学号/身份证', dataIndex: 'idNumber' } 一列拆为两列:
{ title: '学号', dataIndex: 'studentNumber', width: 120, ellipsis: true },
{ title: '身份证', dataIndex: 'idNumber', width: 180, ellipsis: true },
向后兼容:若后端暂未返回 studentNumber 字段,该列显示 -,不报错。
4. 实现顺序
Phase 1: 基础
1. index.css 三断点体系
2. MainLayout useBreakpoint 重构
Phase 2: 高优先级页面
3. Dashboard (4 张统计卡 + 3 张图)
4. 学生管理 (表格 + 字段拆分)
5. 入住管理 (表格 + 弹窗多)
Phase 3: 批量页面
6-17. 剩余 12 个表格型页面(模式统一,效率高)
Phase 4: 收尾
18. 教室排期表(特殊 HTML table)
19. 登录页(单卡片)
20. 全局验证
5. 验证计划
- 视觉检查: Chrome DevTools 响应式模式 → 375 / 768 / 992 / 1440 四个宽度
- 每个页面检查: 表格有无横向滚动 → 按钮是否错位/溢出 → 弹窗是否出屏 → 文字是否截断
- 编译检查:
npm run build确保 TypeScript 无报错