baodan/docs/前端移动端适配指南.md

13 KiB
Raw Blame History

前端移动端适配指南

一、现状评估

1.1 项目技术栈

项目 当前状态
UI 框架 Element Plus自带 el-row/el-col 响应式栅格)
CSS 框架 (无 Tailwind、无 Bootstrap
响应式工具 手写媒体查询,仅 4/22 个 Vue 文件包含 @media
移动端检测 App.vueRecommendForm.vue 各自实现了 window.innerWidth < 768 逻辑,未复用
断点体系 仅一个断点max-width: 767px(手机),仅 App.vue 有平板断点7681024px

1.2 适配完成度

等级 文件数 占比
已适配 4 18%
⚠️ 部分适配 3 14%
未适配 15 68%

已适配App.vueRecommendForm.vueChatCopyButton.vueChatSuggestions.vue 部分适配ChatPage.vueChatSidebar.vueChatEmbed.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%"(手机 ~180pxplaceholder 行总宽 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 统一用固定像素480700px或固定百分比50%70%),无移动端 override
  4. 表格无响应式策略 — 多列表格总宽 870920px无横向滚动包裹、无列隐藏、无卡片视图
  5. 断点体系缺失 — 仅 max-width: 767px 一个断点,无平板/大屏手机/横屏适配
  6. 移动端检测重复App.vueRecommendForm.vue 各自实现 isMobile 逻辑

四、适配方案

4.1 断点体系(统一标准)

/* 手机竖屏 */
@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

: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

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 宽度 修复

.register-card {
  width: 400px;
}
@media (max-width: 575px) {
  .register-card {
    width: 92vw;
    max-width: 400px;
  }
}

el-formlabel-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 表格:外层加 <div style="overflow-x: auto">;手机端隐藏"推荐理由"列

5.3 推荐历史页 RecommendHistory.vue

问题:筛选栏溢出、表格过宽 修复

  • 筛选栏:flex-wrap: wrap;筛选项用 min-width: 120px; flex: 1 替代固定宽度
  • 表格:外层 <div style="overflow-x: auto">;手机端隐藏低优先级列(如"保单号"、"创建时间"
  • 或使用 Element Plus 的 el-table scrollbar-always-on + 设置列 min-width

5.4 仪表盘 DashboardPage.vue

问题KPI 4 列、快捷 3 列无响应式 修复

<!-- KPI 卡片 -->
<el-col :xs="12" :sm="12" :md="6" v-for="item in kpiCards">

<!-- 快捷卡片 -->
<el-col :xs="12" :sm="8" :md="8" v-for="item in shortcutCards">

5.5 权限页 PermissionsPage.vue

问题:角色列表 8/权限 16 分割无响应式 修复

<el-col :xs="24" :sm="8">  <!-- 角色列表 -->
<el-col :xs="24" :sm="16"> <!-- 权限面板 -->

手机端改为上下堆叠布局。

5.6 数据源页 DataSourcePage.vue

问题:同步日志弹窗 700px 修复:改为 width="var(--dialog-width-lg)"width="min(700px, 90vw)"

5.7 聊天筛选 ChatFilters.vue

问题flex 无 wrap标签 nowrap 修复

.chat-filters {
  flex-wrap: wrap;
}
.filter-label {
  white-space: normal; /* 允许换行 */
}

5.8 推荐结果组件 RecommendResult.vue

问题7 列表格无滚动 修复:表格包裹 <div class="table-responsive">

.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 无响应式、筛选器固定宽度 修复

<el-col :xs="24" :sm="12" :md="8">

筛选器宽度改为 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-height200px 调整为 240px40vh
  • 删除按钮:手机端改为 opacity: 1(始终可见),或增加长按触发

5.19 登录页 LoginPage.vue

问题:背景装饰可能溢出 修复.bg-decorationdisplay: none 在手机端

@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-dialogwidth 使用 min(固定值, 90vw) 模式,确保手机端不超过 90% 视口宽度。


七、表格适配规则(全局)

7.1 横向滚动(最简单)

所有 el-table 外层包裹:

<div class="table-scroll-wrapper">
  <el-table ...>
    <!-- columns -->
  </el-table>
</div>
.table-scroll-wrapper {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

7.2 列优先级隐藏

@media (max-width: 767px) {
  /* 隐藏低优先级列 — 通过 el-table 的 v-if 或 class 控制 */
  .hide-on-mobile {
    display: none;
  }
}

或使用 Element Plus 的 el-table-columnshow-overflow-tooltip + min-width 替代 width

7.3 推荐的列宽策略

场景 策略
23 列表格 无需特殊处理
45 列表格 overflow-x: auto 包裹
6+ 列表格 overflow-x: auto + 手机端隐藏低优先级列
筛选栏 flex-wrap: wrap + 筛选项 flex: 1; min-width: 120px

八、筛选栏适配模板

所有筛选栏统一模式:

.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 — 管理后台

  1. DashboardPage.vue
  2. UsersPage.vue + PermissionsPage.vue
  3. 其余 admin 页面(PromptPageTemplatePageStatsPage 等)

Phase 3 — 全局优化

  1. 创建 src/composables/useMobile.ts,替换所有 isMobile 重复逻辑
  2. 创建 src/styles/responsive.css,统一 CSS 变量
  3. 创建 src/styles/table.css,统一表格滚动样式
  4. 创建 src/styles/dialog.css,统一弹窗响应式

十、验证清单

每个页面适配后,用以下方式验证:

  • Chrome DevTools → 切换到 iPhone SE (375px) 查看
  • Chrome DevTools → 切换到 iPhone 14 Pro (393px) 查看
  • Chrome DevTools → 切换到 iPad (768px) 查看
  • 检查无水平滚动条(除非是表格横向滚动)
  • 弹窗在手机端可正常显示和操作
  • 筛选栏在手机端可正常换行
  • 表格在手机端可横向滚动
  • 触屏设备上无 hover-only 的交互死角