# 前端移动端适配指南
## 一、现状评估
### 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 的交互死角