zrlibs
2025-03-17 6e7fcc0ebecb4d9d1485937905b31a9864913950
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
<template>
  <div class="vue-project-layout">
    <div class="layout">
      <div class="layout-header">
        <div class="logo">
          <img :src="logo" />
        </div>
        <div class="user-dropdown">
          <Dropdown trigger="click" @on-click="onClick">
            <a href="javascript:void(0)">
              <Avatar icon="ios-person" :src="avatar" size="large" />
              <span class="username">{{ userName }}</span>
              <Icon type="md-arrow-dropdown" size="18"></Icon>
            </a>
            <template #list>
              <DropdownMenu>
                <DropdownItem name="profile">个人中心</DropdownItem>
                <DropdownItem name="logout">退出登录</DropdownItem>
              </DropdownMenu>
            </template>
          </Dropdown>
        </div>
        <Skin></Skin>
        <Locale></Locale>
      </div>
      <div class="layout-body">
        <div class="menu-list">
          <Menu
            :active-name="activeName"
            :open-names="openNames"
            accordion
            @on-select="onMenuClick"
            ref="refMenu"
          >
            <template v-for="list in menuList" :key="list.id">
              <Submenu v-if="list.isFolder" :name="list.id">
                <template #title>
                  <Icon :custom="list.icon" />
                  {{ list.title }}
                </template>
                <MenuItem
                  v-for="app in list.children"
                  :key="app.id"
                  :name="app.id"
                >
                  <Icon :custom="app.icon" />
                  {{ app.title }}</MenuItem
                >
              </Submenu>
              <MenuItem v-else :name="list.id">
                <Icon :custom="list.icon" />
                {{ list.title }}
              </MenuItem>
            </template>
          </Menu>
        </div>
        <div class="view">
          <RouterView v-slot="{ Component }">
            <template v-if="Component">
              <KeepAlive>
                <component :is="Component" :key="$route.fullPath" />
              </KeepAlive>
            </template>
          </RouterView>
        </div>
      </div>
    </div>
  </div>
</template>
 
<script>
import { ref } from "vue";
import Skin from "./skin.vue";
import Locale from "./locale.vue";
import menuList from "./menu.json";
import { showError } from "@/libs/util";
export default {
  name: "Layout",
  components: {
    Skin,
    Locale,
  },
  data() {
    return {
      menuList,
      activeName: "",
      openNames: [],
      logo: "data:image/png;base64,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",
      avatar: "http://115.29.185.26:5101/userphoto?login=sa",
      userName: "用户名",
    };
  },
  computed: {
    viewList() {
      let routes = [];
      this.menuList.forEach((menu) => {
        if (menu.isFolder) routes.push(...menu.children);
        else routes.push(menu);
      });
      return routes;
    },
  },
  methods: {
    onClick(name) {
      if (name == "logout") {
        this.$router.push({ name: "logout" });
      }
    },
    onMenuClick(id) {
      let route = this.viewList.find((r) => r.id == id);
      if (!route)
        this.showError(
          `未找到id=${id}所对应的路由,请检查菜单、路由的配置是否正确`
        );
 
      this.activeName = route.id;
      this.menuList.forEach((list) => {
        if (list.isFolder && list.children.find((l) => l.id == route.id))
          this.openNames = [list.id];
        else if (list.id == route.id) this.openNames = [];
      });
      this.$nextTick(() => {
        this.refMenu.updateOpened();
      });
 
      this.$router.push({
        name: route.name,
        query: {
          menuId: id,
        },
      });
    },
    showError(ex) {
      showError(this, ex);
    },
  },
  mounted() {
    let firstRoute = this.viewList[0];
    this.onMenuClick(firstRoute.id);
  },
  setup() {
    let refMenu = ref(null);
    return { refMenu };
  },
};
</script>
 
<style lang="less">
.vue-project-layout {
  width: 100%;
  height: 100%;
  overflow: hidden;
  .layout {
    width: 100%;
    height: 100%;
    display: flex;
    overflow: hidden;
    -webkit-box-orient: vertical;
    -webkit-box-direction: normal;
    flex-direction: column;
    -webkit-box-flex: 1;
    background: #f5f7f9;
    .layout-header {
      width: 100%;
      padding: 0;
      height: 64px;
      line-height: 64px;
      flex: 0 0 auto;
      .logo {
        height: 64px;
        display: inline-block;
        width: 240px;
        padding: 5px 20px;
        text-align: center;
        transition: width 0.2sease-out;
        img {
          max-width: 200px;
          max-height: 54px;
          vertical-align: sub;
        }
      }
      .user-dropdown {
        float: right;
        height: 64px;
        padding-right: 40px;
        line-height: 64px;
        .username {
          display: inline-block;
          margin-left: 5px;
          color: #fff;
        }
        .ivu-icon {
          color: #fff;
        }
      }
    }
    .layout-body {
      width: 100%;
      height: calc(100% - 64px);
      display: flex;
      flex: auto;
      .menu-list {
        flex-shrink: 0;
        flex-grow: 0;
        flex-basis: 240px;
        height: 100%;
        border-right: 1px solid #dcdee2;
        overflow-x: hidden;
        overflow-y: auto;
        .ivu-menu {
          height: 100%;
        }
 
        .ivu-menu-vertical.ivu-menu-light:after {
          display: none;
        }
      }
    }
  }
}
</style>