spring boot admin ui 整合element ui二次开发(二)

本文详细介绍了如何在SpringBoot Admin UI项目中引入Element UI,并实现了一个响应式的侧边栏菜单,包括引入步骤、SCSS调整和菜单组件的Vue代码。通过实例演示了如何整合并定制菜单功能,适合前端开发者进行二次开发。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

spring boot admin  ui 二次开发(二)

上次文章已经说明了如何启动进行spring boot ui的入门.本篇文章叙述如何整合element ui 以及添加一个菜单.

第一步:添加element ui

package.json中的devDependencies中添加

 

"element-ui": "^2.13.0"

控制台执行

cnpm install 

在index.js中添加引入element ui的代码

/**添加代码 */
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(ElementUI, {
  size: 'medium' // set element-ui default size
})

修改scss代码,避免样式冲突.

base.scss中修改

body {
  flex-grow: 1;
  display: flex;
  flex-direction: column;

  & > div[id=app] {
    flex-grow: 1;
    display: flex;
    flex-direction: column;
  }
}

至此 element ui引入完成.

二.菜单页面

在views文件夹下添加如下文件

源码如下: sidebar.vue

<template>
  <aside class="sidebar">
    <div v-sticks-below="['#navigation']">
      <router-link
        :to="{name: 'home/console'}"
        class="instance-summary--UP"
      >
        <div
          class="instance-summary__name"
        >
          xxx平台
        </div>
        <div
          class="instance-summary__id"
        />
      </router-link>
      <ul>
        <li
          v-for="group in enabledGroupedViews"
          :key="group.name"
          class="sidebar-group"
          :class="{'is-active' : isActiveGroup(group)}"
          @mouseenter="hasMultipleViews(group) && !isActiveGroup(group) && showFlyout($event)"
          @mouseleave="hasMultipleViews(group) && !isActiveGroup(group) && hideFlyout($event)"
        >
          <router-link
            :to="{ name: group.views[0].name, params: { } }"
            v-text="hasMultipleViews(group) ? group.name : group.views[0].label"
            active-class=""
            exact-active-class=""
            :class="{'is-active' : isActiveGroup(group) }"
          />
          <ul
            v-if="hasMultipleViews(group)"
            class="sidebar-group-items"
          >
            <li
              v-for="view in group.views"
              :key="view.name"
            >
              <router-link :to="{ name: view.name, params: { } }">
                <component :is="view.handle" />
              </router-link>
            </li>
          </ul>
        </li>
      </ul>
    </div>
  </aside>
</template>

<script>
  import sticksBelow from '@/directives/sticks-below';
  import {compareBy} from '@/utils/collections';

  export default {
    props: {
      views: {
        type: Array,
        default: () => []
      },
    },
    directives: {sticksBelow},
    data: () => ({
      isStuck: false
    }),
    computed: {
      enabledViews() {
        return [...this.views].filter(
          view => typeof view.isEnabled === 'undefined' || view.isEnabled()
        ).sort(compareBy(v => v.order));
      },
      enabledGroupedViews() {
        const groups = new Map();
        this.enabledViews.forEach(view => {
            const groupName = view.group || view.label;
            const group = groups.get(groupName) || {
              name: groupName,
              order: Number.MAX_SAFE_INTEGER,
              views: []
            };
            groups.set(groupName, {
              ...group,
              order: Math.min(group.order, view.order),
              views: [...group.views, view]
            })
          }
        );
        return Array.from(groups.values());
      }
    },
    methods: {
      isActiveGroup(group) {
        return group.views.includes(this.$route.meta.view);
      },
      hasMultipleViews(group) {
        return group.views.length > 1;
      },
      onScroll() {
        this.isStuck = this.$el.getBoundingClientRect().top <= 52;
      },
      showFlyout(event) {
        const groupEl = event.target;
        groupEl.classList.add('is-showing-flyout');
        const boundingRect = groupEl.getBoundingClientRect();

        const itemsEl = event.target.querySelector('.sidebar-group-items');
        itemsEl.style.top = `${boundingRect.top}px`;
        itemsEl.style.left = `${boundingRect.right + 1}px`;
      },
      hideFlyout(event) {
        const groupEl = event.target;
        groupEl.classList.remove('is-showing-flyout');
        const itemsEl = event.target.querySelector('.sidebar-group-items');
        itemsEl.style = undefined;
      }
    },
    mounted() {
      window.addEventListener('scroll', this.onScroll);
    },
    beforeDestroy() {
      window.removeEventListener('scroll', this.onScroll);
    },
  }
</script>

<style lang="scss" scoped>
  @import "~@/assets/css/utilities";

  .sidebar {
    height: 100%;
    width: 175px;
    background-color: $white-bis;
    border-right: 1px solid $grey-lighter;

    .instance-summary {
      padding: 1rem 0.5rem;
      color: $text;
      background-color: $grey;
      text-align: center;

      &:hover {
        background-color: rgba($grey, 0.90);
      }

      &__name {
        font-weight: $weight-semibold;
        font-size: $size-5;
        text-align: center;
      }

      &__id {
        font-size: $size-6;
      }

      &--UP {
        color: $primary-invert;
        background-color: $primary;
        &:hover {
          background-color: rgba($primary, 0.90);
        }
      }

      &--RESTRICTED {
        color: $warning-invert;
        background-color: $warning;
        &:hover {
          background-color: rgba($warning, 0.90);
        }
      }

      &--OUT_OF_SERVICE,
      &--DOWN {
        color: $danger-invert;
        background-color: $danger;
        &:hover {
          background-color: rgba($danger, 0.90);
        }
      }
    }

    a {
      border-radius: $radius-small;
      color: $text;
      display: block;
      padding: 0.5em 0.75em;

      &:hover {
        background-color: rgba(0, 0, 0, 0.04);
      }
    }

    .sidebar-group {
      .sidebar-group-items {
        display: none;
      }

      &.is-active {
        box-shadow: inset 4px 0 0 $primary;
        background-color: rgba(0, 0, 0, 0.04);

        > a {
          color: $text;
          font-weight: $weight-semibold;
        }

        .sidebar-group-items {
          display: block;
          padding-bottom: 0.25em;

          a {
            padding-left: 2em;

            &.is-active {
              background-color: $primary;
              color: $link-invert;
            }
          }
        }
      }

      &.is-showing-flyout {
        .sidebar-group-items {
          position: fixed;
          display: block;
          z-index: 999;
          background-color: $white;
          min-width: 150px;
          box-shadow: 0 2px 3px rgba($black, 0.1), 0 0 0 1px rgba($black, 0.1);
        }
      }
    }
  }
</style>

index.vue

<template>
  <div class="instances">
    <div class="instances__body">
      <div class="instances__sidebar">
        <home-sidebar
          :views="views"
        />
      </div>
      <div class="instances__view">
        <router-view />
      </div>
    </div>
  </div>
</template>

<script>
  import HomeSidebar from './sidebar';

  export default {
    components: {HomeSidebar},
    props: {
      views: {
        type: Array,
        default: () => []
      },
      error: {
        type: Error,
        default: null
      }
    },
    computed: {
    },
    install({viewRegistry}) {
      viewRegistry.addView({
        name: 'home',
        path: '/home',
        component: this,
        label: '监控',
        order: -1000,
        redirectView: 'home/console'
      });

    }
  }
</script>

<style lang="scss">
  .instances {
    display: flex;
    flex-grow: 1;
    flex-direction: column;

    &__body {
      display: flex;
      flex-grow: 1;
    }

    &__view,
    &__sidebar {
      position: relative;
    }

    &__sidebar {
      z-index: 20;
    }
    &__view {
      flex-grow: 1;
      flex-shrink: 1;
      z-index: 10;
      max-width: calc(100vw - 175px); /*sidebar-width*/
    }
  }
</style>

console/index.vue

<template>
  <section class="section">
    <!--    <div-->
    <!--        class="container"-->
    <!--    >-->
    <div v-if="error" class="message is-danger">
      <div class="message-body">
        <strong>
          <font-awesome-icon
            class="has-text-danger"
            icon="exclamation-triangle"
          />
          Fetching caches failed.
        </strong>
        <p v-text="error.message" />
      </div>
    </div>
    <el-card>
      <el-container>
        <el-header height="30px">
          今日统计数据
        </el-header>
        <el-main>
          <el-row :gutter="12">
            <el-col :span="4">
              <el-card shadow="always" class="card">
                <div class="center">
                  总调用次数
                </div>
                <div>
                  <span>{{
                    systemData.count == null ? 0 : systemData.count
                  }}</span>
                  次
                </div>
              </el-card>
            </el-col>
            <el-col :span="4">
              <el-card shadow="always" class="card">
                <div class="center">
                  调用平均耗时
                </div>
                <div>
                  <span> {{ systemData.costAvg }}</span> ms
                </div>
              </el-card>
            </el-col>

          </el-row>
        </el-main>
      </el-container>
    </el-card>
  </section>
</template>

<script>

  import subscribing from '@/mixins/subscribing';
  import {timer} from '@/utils/rxjs';

  export default {
  components: { },
  props: {},
  mixins: [subscribing],
  data: () => ({
    isLoading: false,
    error: null,
    caches: [],
    filter: '',
    systemData: {
      count: 111,
      costAvg: 111
    },
    oneDayData: {},
  }),
  computed: {},
  methods: {
    /** 定時刷新*/
    createSubscription() {
      const vm = this;
      return timer(0, 60000).subscribe({
        next: (data) => {
        },
        error: (error) => {
          console.warn('Fetching console data failed:', error);
        },
      });
    },
  },
  created() {
  },
  install({ viewRegistry }) {
  //用于路由注册 这是spring boot ui的路由注册方式
    viewRegistry.addView({
      name: 'home/console',
      parent: 'home',
      path: 'console',
      group: '接口监控',
      component: this,
      label: '监控',
      order: 970,
    });
  },
};
</script>

<style lang="scss" scoped>
.tool {
  margin-bottom: 20px;
}

.form-class {
  height: 800px;
  margin-bottom: 20px;
}

.input-class {
  .el-input__inner {
    width: 115%;
  }
}

.center {
  text-align: center;
}

.card {
  background-color: #f2f2f2;
  color: #888;

  div {
    text-align: center;
  }

  span {
    text-align: center;
    font-size: 35px;
  }
}

.el-one-day-col {
  margin-top: 20px;
  background-color: #fff;

  div {
    -webkit-line-clamp: 1;
    overflow: hidden;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    white-space: normal;
    cursor: pointer;
  }

  .card {
    margin-top: 10px;
  }
}
</style>

AdminServerUiAutoConfiguration.java 文件中添加 "/home/**"

修改文件记录

执行启动 SpringBootAdminServletApplication.java

npm run watch 

 

效果展示如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值