Files
ccdi/docs/plans/2026-03-04-project-detail-navigation-menu-design.md

7.9 KiB
Raw Blame History

项目详情页面导航菜单改造设计文档

概述

将项目详情页面detail.vue右侧的按钮组改为水平导航菜单使用 Element UI Menu 组件实现简洁链接风格。

当前问题

项目详情页面右侧的操作按钮(上传数据、参数配置、初核结果)占用空间较大,视觉层级不够清晰,交互方式不够统一。

解决方案

核心设计

  • 使用 Element UI 的 el-menu 组件(水平模式)
  • 菜单放在标题右侧,右对齐
  • "上传数据"和"参数配置"作为普通菜单项
  • "初核结果"保留下拉菜单结构,包含三个子项:结果总览、专项排查、流水明细查询
  • 采用简洁链接风格:透明背景 + 底部下划线激活效果

视觉风格

  • 默认状态:灰色文字(#606266透明背景
  • Hover 状态:浅灰背景(#f5f7fa深色文字#303133
  • 激活状态:蓝色文字(#1890ff+ 底部 2px 蓝色下划线
  • 下拉菜单:白色背景,激活项浅蓝背景(#e6f7ff

技术设计

1. 组件结构

detail.vue 模板改造

<div class="header-right">
  <el-menu
    :default-active="activeTab"
    mode="horizontal"
    @select="handleMenuSelect"
    class="nav-menu"
  >
    <el-menu-item index="upload">上传数据</el-menu-item>
    <el-menu-item index="config">参数配置</el-menu-item>
    <el-submenu index="result">
      <template slot="title">初核结果</template>
      <el-menu-item index="overview">结果总览</el-menu-item>
      <el-menu-item index="special">专项排查</el-menu-item>
      <el-menu-item index="detail">流水明细查询</el-menu-item>
    </el-submenu>
  </el-menu>
</div>

<!-- 动态组件渲染区域 -->
<component
  :is="currentComponent"
  :project-id="projectId"
  :project-info="projectInfo"
  @menu-change="handleMenuChange"
  @data-uploaded="handleDataUploaded"
  @name-selected="handleNameSelected"
  @generate-report="handleGenerateReport"
  @fetch-bank-info="handleFetchBankInfo"
/>

2. 数据结构

data() {
  return {
    activeTab: 'upload',           // 当前激活的菜单项索引
    currentComponent: 'UploadData', // 当前显示的组件名称
    // ... 其他现有数据
  }
}

3. 交互逻辑

methods: {
  /** 菜单选择事件 */
  handleMenuSelect(index) {
    this.activeTab = index;

    // 组件映射
    const componentMap = {
      'upload': 'UploadData',
      'config': 'ParamConfig',
      'overview': 'PreliminaryCheck',
      'special': 'SpecialCheck',
      'detail': 'DetailQuery'
    };

    this.currentComponent = componentMap[index] || 'UploadData';
  },

  // ... 其他现有方法
}

4. 组件导入

import UploadData from "./components/detail/UploadData";
import ParamConfig from "./components/detail/ParamConfig";
import PreliminaryCheck from "./components/detail/PreliminaryCheck";
import SpecialCheck from "./components/detail/SpecialCheck";
import DetailQuery from "./components/detail/DetailQuery";

export default {
  name: "ProjectDetail",
  components: {
    UploadData,
    ParamConfig,
    PreliminaryCheck,
    SpecialCheck,
    DetailQuery,
  },
  // ...
}

样式设计

1. 导航菜单样式

.header-right {
  .nav-menu {
    // 移除默认背景色和边框
    background-color: transparent;
    border-bottom: none;

    // 菜单项基础样式
    .el-menu-item,
    .el-submenu__title {
      font-size: 14px;
      color: #606266;
      padding: 0 16px;
      height: 40px;
      line-height: 40px;
      border-bottom: 2px solid transparent;

      &:hover {
        background-color: #f5f7fa;
        color: #303133;
      }
    }

    // 激活状态:底部下划线 + 蓝色文字
    .el-menu-item.is-active {
      color: #1890ff;
      border-bottom: 2px solid #1890ff;
      background-color: transparent;
    }

    // 下拉菜单激活状态
    .el-submenu.is-active > .el-submenu__title {
      color: #1890ff;
      border-bottom: 2px solid #1890ff;
    }

    // 下拉菜单图标
    .el-submenu__icon-arrow {
      margin-left: 4px;
    }
  }
}

2. 下拉菜单弹窗样式

::v-deep .el-menu--popup {
  min-width: 140px;

  .el-menu-item {
    font-size: 14px;

    &:hover {
      background-color: #f5f7fa;
    }

    &.is-active {
      color: #1890ff;
      background-color: #e6f7ff;
    }
  }
}

3. 响应式适配

@media (max-width: 768px) {
  .detail-header {
    flex-direction: column;
    align-items: flex-start;

    .header-right {
      width: 100%;
      margin-top: 12px;

      .nav-menu {
        width: 100%;
        display: flex;
        justify-content: flex-start;

        .el-menu-item,
        .el-submenu {
          flex: 1;
          text-align: center;
          padding: 0 8px;
          font-size: 13px;
        }
      }
    }
  }
}

组件规范

Props 接口

所有子组件应接收相同的 props

props: {
  projectId: {
    type: [String, Number],
    default: null,
  },
  projectInfo: {
    type: Object,
    default: () => ({
      projectName: "",
      updateTime: "",
      projectStatus: "0",
    }),
  },
},

Events 接口

this.$emit('data-uploaded', { type: 'xxx' });
this.$emit('generate-report');
this.$emit('fetch-bank-info');
this.$emit('menu-change', { key, route });
this.$emit('name-selected', nameList);

实施步骤

第一步:修改 detail.vue 文件

  1. 替换 header-right 中的按钮为 el-menu 组件
  2. 添加 activeTab 和 currentComponent 数据字段
  3. 实现 handleMenuSelect 方法
  4. 添加动态组件渲染区域
  5. 导入所有子组件

第二步:添加样式

  1. 添加导航菜单的自定义样式
  2. 添加下拉菜单样式
  3. 添加响应式样式

第三步:创建占位组件

为未实现的功能创建占位组件:

  • ParamConfig.vue
  • PreliminaryCheck.vue
  • SpecialCheck.vue
  • DetailQuery.vue

第四步:测试验证

  • 功能测试:菜单切换、下拉菜单交互
  • 视觉测试:样式符合设计要求
  • 响应式测试:移动端布局正常

技术栈

  • Element UI Menu 组件(el-menu, el-menu-item, el-submenu
  • Vue 动态组件(<component :is="...">
  • Scoped CSS 样式覆盖
  • Vue 2.6.12
  • Element UI 2.15.14

预期效果

视觉效果

  • 菜单项横向排列在标题右侧,右对齐
  • 简洁链接风格,无背景色和边框
  • 激活项显示蓝色文字和底部下划线
  • 下拉菜单样式统一

交互效果

  • 点击菜单项切换组件URL 不变
  • 下拉菜单点击外部区域可关闭
  • 组件切换流畅,数据正确传递
  • 响应式布局在移动端自适应

代码改动量估算

  • detail.vue 文件改动:约 80-100 行(模板 + 脚本 + 样式)
  • 占位组件创建4 个文件,每个约 20 行
  • 总代码量:约 150-180 行

风险与注意事项

  1. 组件文件不存在ParamConfig、PreliminaryCheck 等组件需要创建占位组件
  2. 样式覆盖Element UI 默认样式覆盖需要使用 ::v-deep/deep/
  3. 事件传递:确保所有子组件的事件正确向上传递
  4. 路由监听:移除原有路由相关的逻辑,改为组件状态管理

后续优化建议

  1. 添加菜单切换动画效果
  2. 为占位组件实现完整功能
  3. 添加面包屑导航支持
  4. 支持菜单项权限控制
  5. 添加快捷键支持Ctrl+Tab 切换)

测试清单

  • 点击"上传数据"菜单,显示 UploadData 组件
  • 点击"参数配置"菜单,显示占位组件或 ParamConfig 组件
  • 点击"初核结果"菜单,展开下拉菜单
  • 点击下拉菜单子项,切换到对应组件
  • 激活菜单项显示底部下划线
  • Hover 菜单项显示浅灰背景
  • 下拉菜单点击外部区域关闭
  • 组件切换时 projectId 和 projectInfo 正确传递
  • 移动端菜单响应式布局正常
  • 现有功能不受影响(返回按钮、项目信息显示等)