# 前端移动端适配指南 ## 一、现状评估 ### 1.1 项目技术栈 | 项目 | 当前状态 | |------|----------| | UI 框架 | Element Plus(自带 `el-row`/`el-col` 响应式栅格) | | CSS 框架 | **无**(无 Tailwind、无 Bootstrap) | | 响应式工具 | 手写媒体查询,仅 4/22 个 Vue 文件包含 `@media` | | 移动端检测 | `App.vue` 和 `RecommendForm.vue` 各自实现了 `window.innerWidth < 768` 逻辑,未复用 | | 断点体系 | **仅一个断点**:`max-width: 767px`(手机),仅 `App.vue` 有平板断点(768–1024px) | ### 1.2 适配完成度 | 等级 | 文件数 | 占比 | |------|:------:|:----:| | ✅ 已适配 | 4 | 18% | | ⚠️ 部分适配 | 3 | 14% | | ❌ 未适配 | 15 | 68% | **已适配**:`App.vue`、`RecommendForm.vue`、`ChatCopyButton.vue`、`ChatSuggestions.vue` **部分适配**:`ChatPage.vue`、`ChatSidebar.vue`、`ChatEmbed.vue` **未适配**:其余 15 个页面/组件 --- ## 二、问题清单(按严重程度排序) ### 🔴 严重 — 移动端完全不可用 | 文件 | 问题 | 影响 | |------|------|------| | `RegisterPage.vue` | `.register-card` 硬编码 `width: 400px`,无媒体查询 | <420px 屏幕水平溢出 | | `RecommendDetailView.vue` | `el-descriptions` 强制 3 列;4 列 plan 表格;标题栏 3 个按钮 | 布局严重错乱 | | `RecommendHistory.vue` | 筛选栏最小宽度 ~560px;表格总宽 ~920px | 完全溢出 | | `DashboardPage.vue` | KPI 卡片 `el-col :span="6"` 无 `:xs` 断点;快捷卡片 `:span="8"` | 4 列/3 列在手机上窄至 ~80px | | `PermissionsPage.vue` | `el-col :span="8"` 和 `:span="16"` 无响应式断点 | 角色列表/权限面板在手机上不可用 | | `DataSourcePage.vue` | 同步日志弹窗 `width="700px"` | 所有手机屏幕溢出 | ### 🟠 高 — 移动端严重降级 | 文件 | 问题 | |------|------| | `ChatFilters.vue` | flex 无 wrap,筛选栏溢出;`.filter-label` 设了 `white-space: nowrap` | | `RecommendResult.vue`(组件) | 7 列表格无横向滚动;替换弹窗 `width="600px"` | | `UsersPage.vue` | 筛选栏溢出(固定 160px × 2 + 按钮);表格 ~870px;弹窗 480px | | `StatsPage.vue` | `el-col :span="12"`/`:span="8"` 无响应式;筛选器固定宽度 | | `TemplatePage.vue` | 编辑弹窗 `width="50%"`(手机 ~180px);placeholder 行总宽 420px | | `KBManagePage.vue` | 筛选栏总宽 ~580px;状态弹窗 500px | ### 🟡 中 — 移动端可感知问题 | 文件 | 问题 | |------|------| | `ChatPage.vue` | 侧边栏固定 240px,无平板适配 | | `ChatEmbed.vue` | 纠错弹窗 `width="500px"`;消息列表/输入区 padding 不缩 | | `PromptPage.vue` | 创建弹窗 `width="70%"`(手机 ~252px,过窄) | | `NotificationPage.vue` | 弹窗 `width="50%"`(手机 ~180px,不可用) | | `DepartmentPage.vue` | 弹窗 `width="500px"` | | `LoginLogsPage.vue` | 筛选项固定宽度(150px/120px/280px) | | `ChatLogsPage.vue` | 筛选项固定宽度(200px/150px/280px) | ### 🟢 低 — 细节问题 | 文件 | 问题 | |------|------| | `LoginPage.vue` | 背景装饰 `.bg-decoration` 可能在极窄屏幕造成溢出 | | `ChatSidebar.vue` | 移动端 `max-height: 200px` 过小(仅 ~3 个会话);删除按钮仅 hover 可见,触屏不可发现 | --- ## 三、根因分析 ### 3.1 六大共性问题 1. **无响应式框架** — 全靠手写 media query,覆盖率极低 2. **inline style 主导** — 大量页面用 `style="width: 160px"` 等内联样式,无法通过媒体查询覆盖 3. **弹窗宽度硬编码** — `el-dialog` 统一用固定像素(480–700px)或固定百分比(50%–70%),无移动端 override 4. **表格无响应式策略** — 多列表格总宽 870–920px,无横向滚动包裹、无列隐藏、无卡片视图 5. **断点体系缺失** — 仅 `max-width: 767px` 一个断点,无平板/大屏手机/横屏适配 6. **移动端检测重复** — `App.vue` 和 `RecommendForm.vue` 各自实现 `isMobile` 逻辑 --- ## 四、适配方案 ### 4.1 断点体系(统一标准) ```css /* 手机竖屏 */ @media (max-width: 575px) { /* ... */ } /* 手机横屏 / 大屏手机 */ @media (min-width: 576px) and (max-width: 767px) { /* ... */ } /* 平板竖屏 */ @media (min-width: 768px) and (max-width: 1023px) { /* ... */ } /* 桌面 */ @media (min-width: 1024px) { /* ... */ } ``` 与 Element Plus 断点保持一致:`xs`(<768px)、`sm`(≥768px)、`md`(≥992px)、`lg`(≥1200px)。 ### 4.2 全局 CSS 变量(建议新建 `src/styles/responsive.css`) ```css :root { /* 间距 */ --space-xs: 4px; --space-sm: 8px; --space-md: 16px; --space-lg: 24px; --space-xl: 32px; /* 弹窗宽度 */ --dialog-width-sm: 90vw; --dialog-width-md: 80vw; --dialog-width-lg: 600px; /* 表格 */ --table-scroll-max-width: calc(100vw - 48px); } @media (min-width: 768px) { :root { --dialog-width-sm: 500px; --dialog-width-md: 600px; --dialog-width-lg: 700px; --table-scroll-max-width: 100%; } } ``` ### 4.3 共享 Composable(新建 `src/composables/useMobile.ts`) ```typescript import { ref, onMounted, onUnmounted } from 'vue' export function useMobile(breakpoint = 768) { const isMobile = ref(window.innerWidth < breakpoint) const isTablet = ref(window.innerWidth >= 768 && window.innerWidth < 1024) const update = () => { isMobile.value = window.innerWidth < breakpoint isTablet.value = window.innerWidth >= 768 && window.innerWidth < 1024 } onMounted(() => window.addEventListener('resize', update)) onUnmounted(() => window.removeEventListener('resize', update)) return { isMobile, isTablet } } ``` --- ## 五、逐页面修复方案 ### 5.1 注册页 `RegisterPage.vue` **问题**:卡片固定 400px 宽度 **修复**: ```css .register-card { width: 400px; } @media (max-width: 575px) { .register-card { width: 92vw; max-width: 400px; } } ``` `el-form` 的 `label-width` 改为响应式:`:label-width="isMobile ? '0px' : '80px'"`(手机用 top label)。 ### 5.2 推荐详情页 `RecommendDetailView.vue` **问题**:3 列描述、4 列表格、标题栏 3 按钮 **修复**: - `el-descriptions`: `:column="isMobile ? 1 : 3"` - 标题栏按钮:`flex-wrap: wrap` 或手机端折叠为下拉菜单 - plan 表格:外层加 `
`;手机端隐藏"推荐理由"列 ### 5.3 推荐历史页 `RecommendHistory.vue` **问题**:筛选栏溢出、表格过宽 **修复**: - 筛选栏:`flex-wrap: wrap`;筛选项用 `min-width: 120px; flex: 1` 替代固定宽度 - 表格:外层 `
`;手机端隐藏低优先级列(如"保单号"、"创建时间") - 或使用 Element Plus 的 `el-table` `scrollbar-always-on` + 设置列 `min-width` ### 5.4 仪表盘 `DashboardPage.vue` **问题**:KPI 4 列、快捷 3 列无响应式 **修复**: ```html ``` ### 5.5 权限页 `PermissionsPage.vue` **问题**:角色列表 8/权限 16 分割无响应式 **修复**: ```html ``` 手机端改为上下堆叠布局。 ### 5.6 数据源页 `DataSourcePage.vue` **问题**:同步日志弹窗 700px **修复**:改为 `width="var(--dialog-width-lg)"` 或 `width="min(700px, 90vw)"` ### 5.7 聊天筛选 `ChatFilters.vue` **问题**:flex 无 wrap,标签 nowrap **修复**: ```css .chat-filters { flex-wrap: wrap; } .filter-label { white-space: normal; /* 允许换行 */ } ``` ### 5.8 推荐结果组件 `RecommendResult.vue` **问题**:7 列表格无滚动 **修复**:表格包裹 `
` ```css .table-responsive { overflow-x: auto; -webkit-overflow-scrolling: touch; } ``` 替换弹窗改为 `width="min(600px, 90vw)"`。 ### 5.9 用户管理 `UsersPage.vue` **问题**:筛选栏溢出、表格过宽、弹窗固定 **修复**: - 筛选栏:`flex-wrap: wrap`;筛选项 `flex: 1; min-width: 140px` - 表格:`overflow-x: auto` 包裹;手机端隐藏部分列 - 弹窗:`width="min(480px, 90vw)"` ### 5.10 统计页 `StatsPage.vue` **问题**:`el-col` 无响应式、筛选器固定宽度 **修复**: ```html ``` 筛选器宽度改为 `width: 100%`(手机端)或 `flex: 1; min-width: 120px`。 ### 5.11 模板页 `TemplatePage.vue` **问题**:弹窗 50% 太窄;placeholder 行溢出 **修复**: - 弹窗:改为 `width="min(500px, 90vw)"` - placeholder 行:`flex-wrap: wrap`,每项 `min-width: 120px` ### 5.12 提示词页 `PromptPage.vue` **问题**:弹窗 70% 手机端过窄 **修复**:改为 `width="min(600px, 90vw)"` ### 5.13 通知页 `NotificationPage.vue` **问题**:弹窗 50% 不可用 **修复**:改为 `width="min(500px, 90vw)"` ### 5.14 部门页 `DepartmentPage.vue` **问题**:弹窗 500px **修复**:改为 `width="min(500px, 90vw)"` ### 5.15 知识库管理 `KBManagePage.vue` **问题**:筛选栏溢出、弹窗固定 **修复**: - 筛选栏:`flex-wrap: wrap`;筛选项 `flex: 1; min-width: 130px` - 弹窗:`width="min(500px, 90vw)"` ### 5.16 登录日志 `LoginLogsPage.vue` / 聊天日志 `ChatLogsPage.vue` **问题**:筛选项固定宽度 **修复**:筛选项改为 `width: 100%`(手机端)或 `flex: 1; min-width: 140px` ### 5.17 聊天嵌入 `ChatEmbed.vue` **问题**:纠错弹窗 500px、padding 不适配 **修复**: - 弹窗:`width="min(500px, 90vw)"` - `.message-list`:手机端 padding 缩小为 `8px` - `.input-area`:手机端 padding 缩小为 `8px 12px` ### 5.18 聊天侧边栏 `ChatSidebar.vue` **问题**:手机端 max-height 过小;删除按钮 hover 不可发现 **修复**: - `max-height` 从 `200px` 调整为 `240px` 或 `40vh` - 删除按钮:手机端改为 `opacity: 1`(始终可见),或增加长按触发 ### 5.19 登录页 `LoginPage.vue` **问题**:背景装饰可能溢出 **修复**:`.bg-decoration` 加 `display: none` 在手机端 ```css @media (max-width: 575px) { .bg-decoration { display: none; } } ``` --- ## 六、弹窗适配规则(全局) | 原写法 | 推荐写法 | 说明 | |--------|----------|------| | `width="700px"` | `width="min(700px, 90vw)"` | 大弹窗 | | `width="600px"` | `width="min(600px, 90vw)"` | 中弹窗 | | `width="500px"` | `width="min(500px, 90vw)"` | 小弹窗 | | `width="480px"` | `width="min(480px, 90vw)"` | 表单弹窗 | | `width="70%"` | `width="min(600px, 90vw)"` | 百分比在手机上过窄 | | `width="50%"` | `width="min(500px, 90vw)"` | 百分比在手机上不可用 | | `width="90%"` | ✅ 可以保留 | 已是响应式写法 | > **规则**:所有 `el-dialog` 的 `width` 使用 `min(固定值, 90vw)` 模式,确保手机端不超过 90% 视口宽度。 --- ## 七、表格适配规则(全局) ### 7.1 横向滚动(最简单) 所有 `el-table` 外层包裹: ```html
``` ```css .table-scroll-wrapper { overflow-x: auto; -webkit-overflow-scrolling: touch; } ``` ### 7.2 列优先级隐藏 ```css @media (max-width: 767px) { /* 隐藏低优先级列 — 通过 el-table 的 v-if 或 class 控制 */ .hide-on-mobile { display: none; } } ``` 或使用 Element Plus 的 `el-table-column` 的 `show-overflow-tooltip` + `min-width` 替代 `width`。 ### 7.3 推荐的列宽策略 | 场景 | 策略 | |------|------| | 2–3 列表格 | 无需特殊处理 | | 4–5 列表格 | `overflow-x: auto` 包裹 | | 6+ 列表格 | `overflow-x: auto` + 手机端隐藏低优先级列 | | 筛选栏 | `flex-wrap: wrap` + 筛选项 `flex: 1; min-width: 120px` | --- ## 八、筛选栏适配模板 所有筛选栏统一模式: ```css .filter-bar { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; } .filter-item { flex: 1; min-width: 120px; } @media (max-width: 575px) { .filter-bar { gap: 8px; } .filter-item { min-width: 100%; } } ``` --- ## 九、实施优先级 ### Phase 1 — 核心页面(用户直接使用) 1. `ChatPage.vue` + `ChatEmbed.vue` + `ChatSidebar.vue` + `ChatFilters.vue` 2. `LoginPage.vue` + `RegisterPage.vue` 3. `RecommendForm.vue` + `RecommendResult.vue` + `RecommendDetailView.vue` + `RecommendHistory.vue` ### Phase 2 — 管理后台 4. `DashboardPage.vue` 5. `UsersPage.vue` + `PermissionsPage.vue` 6. 其余 admin 页面(`PromptPage`、`TemplatePage`、`StatsPage` 等) ### Phase 3 — 全局优化 7. 创建 `src/composables/useMobile.ts`,替换所有 `isMobile` 重复逻辑 8. 创建 `src/styles/responsive.css`,统一 CSS 变量 9. 创建 `src/styles/table.css`,统一表格滚动样式 10. 创建 `src/styles/dialog.css`,统一弹窗响应式 --- ## 十、验证清单 每个页面适配后,用以下方式验证: - [ ] Chrome DevTools → 切换到 iPhone SE (375px) 查看 - [ ] Chrome DevTools → 切换到 iPhone 14 Pro (393px) 查看 - [ ] Chrome DevTools → 切换到 iPad (768px) 查看 - [ ] 检查无水平滚动条(除非是表格横向滚动) - [ ] 弹窗在手机端可正常显示和操作 - [ ] 筛选栏在手机端可正常换行 - [ ] 表格在手机端可横向滚动 - [ ] 触屏设备上无 hover-only 的交互死角