zzw
5 小时以前 145fd1abd1e77e142982da48064b98f1e436dc6c
feat: show menu path in header
2个文件已修改
33 ■■■■■ 已修改文件
emergency-repair-web/src/components/AppHeader.vue 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
emergency-repair-web/src/layout/AppLayout.vue 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
emergency-repair-web/src/components/AppHeader.vue
@@ -4,6 +4,7 @@
      <repair-logo></repair-logo>
      <span>临抢修管理系统</span>
      <em>网络版</em>
      <span v-if="menuPathText" class="menu-path" :title="menuPathText">{{ menuPathText }}</span>
    </div>
    <div class="header-right">
      <span><i class="el-icon-user-solid"></i> {{ realName }}</span>
@@ -18,7 +19,13 @@
export default {
  name: 'AppHeader',
  components: { RepairLogo },
  props: {
    menuPath: { type: Array, default: () => [] }
  },
  computed: {
    menuPathText() {
      return this.menuPath.join(' / ')
    },
    realName() {
      return sessionStorage.getItem('realName') || '系统管理员'
    }
@@ -36,6 +43,7 @@
<style scoped>
.app-header {
  gap: 20px;
  display: flex;
  align-items: center;
  justify-content: space-between;
@@ -46,10 +54,12 @@
  box-shadow: 0 1px 4px rgba(18, 41, 63, 0.24);
  flex-shrink: 0;
}
.brand { display: flex; align-items: center; gap: 9px; font-size: 18px; font-weight: 600; }
.brand { display: flex; flex: 1; align-items: center; min-width: 0; gap: 9px; font-size: 18px; font-weight: 600; }
.brand .repair-logo { color: #7fc4ff; font-size: 25px; transform: translateY(2px); }
.brand em { padding: 1px 6px; border: 1px solid rgba(255,255,255,.35); border-radius: 3px; font-size: 11px; font-style: normal; font-weight: 400; opacity: .85; }
.header-right { display: flex; align-items: center; gap: 14px; font-size: 14px; }
.brand > .repair-logo, .brand > span:not(.menu-path), .brand > em { flex: 0 0 auto; }
.menu-path { flex: 0 1 auto; min-width: 0; padding-left: 14px; border-left: 1px solid rgba(255,255,255,.28); overflow: hidden; color: #d8e9f7; font-size: 13px; font-weight: 400; text-overflow: ellipsis; white-space: nowrap; }
.header-right { display: flex; flex: 0 0 auto; align-items: center; gap: 14px; font-size: 14px; }
.header-right .el-button { color: #d8e9f7; }
.header-right .el-button:hover { color: #fff; }
</style>
emergency-repair-web/src/layout/AppLayout.vue
@@ -1,6 +1,6 @@
<template>
  <el-container class="layout">
    <app-header></app-header>
    <app-header :menu-path="activeMenuPath"></app-header>
    <el-container class="layout-body">
      <el-aside width="228px" class="layout-aside">
        <div class="aside-caption">业务导航</div>
@@ -10,7 +10,6 @@
      </el-aside>
      <el-main class="layout-main">
        <div class="mdi-tabbar">
          <div class="mdi-caption"><i class="el-icon-document-copy"></i><span>工作区</span></div>
          <div ref="tabScroll" class="mdi-tabs-scroll">
            <div class="mdi-tabs">
              <div
@@ -95,6 +94,11 @@
    canCloseOthers() {
      const keepCount = this.activeDoc && this.activeDoc.pinned ? 1 : 2
      return this.openDocs.length > keepCount
    },
    activeMenuPath() {
      const path = this.findMenuPath(this.menus, this.$route.path)
      if (path.length) return path
      return this.$route.meta.title ? [this.$route.meta.title] : []
    }
  },
  watch: {
@@ -145,6 +149,15 @@
      if (!this.openDocs.some(doc => doc.pinned)) {
        this.openDocs.unshift({ ...HOME_DOC })
      }
    },
    findMenuPath(items, targetPath, trail = []) {
      for (const item of items || []) {
        const nextTrail = [...trail, item.name]
        if (item.url === targetPath) return nextTrail
        const childPath = this.findMenuPath(item.children, targetPath, nextTrail)
        if (childPath.length) return childPath
      }
      return []
    },
    resolveTitle(route) {
      if (route.path.startsWith('/reports/')) {
@@ -247,8 +260,6 @@
  word-break: break-word;
}
.mdi-tabbar { display: flex; flex: 0 0 40px; align-items: stretch; height: 40px; padding-top: 5px; border-bottom: 1px solid #cfdae5; background: #e3eaf1; }
.mdi-caption { display: flex; flex: 0 0 auto; align-items: center; gap: 6px; padding: 0 12px; border-right: 1px solid rgba(125, 147, 169, .22); color: #64788d; font-size: 12px; }
.mdi-caption i { color: #2c7fb8; font-size: 15px; }
.mdi-tabs-scroll { flex: 1; min-width: 0; overflow-x: auto; overflow-y: hidden; }
.mdi-tabs { display: inline-flex; align-items: flex-end; min-width: 100%; height: 100%; padding: 0 4px; }
.mdi-tab { display: inline-flex; flex: 0 0 auto; align-items: center; gap: 6px; max-width: 220px; height: 34px; margin-right: 2px; padding: 0 9px; border: 1px solid transparent; border-bottom: 0; border-radius: 4px 4px 0 0; color: #5c6f82; background: rgba(255, 255, 255, .42); cursor: pointer; font-size: 13px; user-select: none; }