Browse Source

add top-nav-menu

Sendya 6 years ago
parent
commit
4c46e75725

+ 61 - 0
src/components/chart/Liquid.vue

@@ -0,0 +1,61 @@
+<template>
+  <div>
+    <v-chart :forceFit="true" :height="height" :width="width" :data="data" :scale="scale" :padding="0">
+      <v-tooltip />
+      <v-interval
+        :shape="['liquid-fill-gauge']"
+        position="transfer*value"
+        color=""
+        :v-style="{
+          lineWidth: 10,
+          opacity: 0.75
+        }"
+        :tooltip="[
+          'transfer*value',
+          (transfer, value) => {
+            return {
+              name: transfer,
+              value,
+            };
+          },
+        ]"
+      ></v-interval>
+      <v-guide
+        v-for="(row, index) in data"
+        :key="index"
+        type="text"
+        :top="true"
+        :position="{
+          gender: row.transfer,
+          value: 45
+        }"
+        :content="row.value + '%'"
+        :v-style="{
+          fontSize: 100,
+          textAlign: 'center',
+          opacity: 0.75,
+        }"
+      />
+    </v-chart>
+  </div>
+</template>
+
+<script>
+  export default {
+    name: "Liquid",
+    props: {
+      height: {
+        type: Number,
+        default: 0
+      },
+      width: {
+        type: Number,
+        default: 0
+      }
+    }
+  }
+</script>
+
+<style scoped>
+
+</style>

+ 7 - 2
src/components/layouts/PageView.vue

@@ -1,5 +1,5 @@
 <template>
-  <page-layout :desc="description" :title="getTitle" :link-list="linkList">
+  <page-layout :desc="description" :title="getTitle" :link-list="linkList" :search="search" :tabs="tabs">
     <div slot="extra" class="extra-img">
       <img :src="extraImage"/>
     </div>
@@ -23,7 +23,9 @@
         title: '',
         description: '',
         linkList: [],
-        extraImage: ''
+        extraImage: '',
+        search: false,
+        tabs: {}
       }
     },
     mounted () {
@@ -45,10 +47,13 @@
         this.title = this.$route.meta.title
         // 因为套用了一层 route-view 所以要取 ref 对象下的子节点的第一个对象
         const content = this.$refs.content && this.$refs.content.$children[0]
+
         if (content) {
           this.description = content.description
           this.linkList = content.linkList
           this.extraImage = content.extraImage
+          this.search = content.search == true ? true : false
+          this.tabs = content.tabs
         }
       }
     }

+ 3 - 7
src/components/menu/SideMenu.vue

@@ -5,12 +5,7 @@
     :collapsible="collapsible"
     v-model="collapsed" 
     :trigger="null">
-    <div class="logo">
-      <router-link :to="{name:'dashboard'}">
-        <img src="~@/assets/logo.svg" alt="logo">
-        <h1>Ant Design Pro</h1>
-      </router-link>
-    </div>
+    <logo />
     <s-menu
       :collapsed="collapsed"
       :menu="menus"
@@ -24,12 +19,13 @@
 
 <script>
   import ALayoutSider from "ant-design-vue/es/layout/Sider"
+  import Logo from '../tools/Logo'
   import SMenu from './index'
   import { mapState } from 'vuex'
 
   export default {
     name: "SideMenu",
-    components: { ALayoutSider, SMenu },
+    components: { ALayoutSider, Logo, SMenu },
     props: {
       mode: {
         type: String,

+ 7 - 4
src/components/menu/index.js

@@ -128,10 +128,14 @@ export default {
       } else {
         this.selectedKeys = [ routes.pop().path ]
       }
+
       let openKeys = []
-      routes.forEach((item) => {
-        openKeys.push(item.path)
-      })
+      if (this.mode === 'inline') {
+        routes.forEach((item) => {
+          openKeys.push(item.path)
+        })
+      }
+
       this.collapsed ? this.cachedOpenKeys = openKeys : this.openKeys = openKeys
     }
   },
@@ -142,7 +146,6 @@ export default {
         props: {
           theme: this.$props.theme,
           mode: this.$props.mode,
-          inlineCollapsed: false,
           openKeys: this.openKeys,
           selectedKeys: this.selectedKeys
         },

+ 45 - 64
src/components/page/GlobalHeader.vue

@@ -1,6 +1,6 @@
 <template>
   <a-layout-header style="padding: 0px;">
-    <div class="header">
+    <div v-if="mode === 'sidemenu'" class="header">
       <a-icon
         v-if="device==='mobile'"
         class="trigger"
@@ -12,57 +12,52 @@
         :type="collapsed ? 'menu-unfold' : 'menu-fold'"
         @click.native="toggle"/>
 
-      <div class="user-wrapper">
-        <span class="action">
-          <a-icon type="question-circle-o"></a-icon>
-        </span>
-        <header-notice class="action"/>
-        <a-dropdown>
-          <span class="action ant-dropdown-link user-dropdown-menu">
-            <a-avatar class="avatar" size="small" :src="avatar()"/>
-            <span>{{ nickname() }}</span>
-          </span>
-          <a-menu slot="overlay" class="user-dropdown-menu-wrapper">
-            <a-menu-item key="0">
-              <router-link :to="{ name: 'center' }">
-                <a-icon type="user"/>
-                <span>个人中心</span>
-              </router-link>
-            </a-menu-item>
-            <a-menu-item key="1">
-              <router-link :to="{ name: 'settings' }">
-                <a-icon type="setting"/>
-                <span>账户设置</span>
-              </router-link>
-            </a-menu-item>
-            <a-menu-item key="2" disabled>
-              <a-icon type="setting"/>
-              <span>测试</span>
-            </a-menu-item>
-            <a-menu-divider/>
-            <a-menu-item key="3">
-              <a href="javascript:;" @click="handleLogout">
-                <a-icon type="logout"/>
-                <span>退出登录</span>
-              </a>
-            </a-menu-item>
-          </a-menu>
-        </a-dropdown>
+      <user-menu></user-menu>
+    </div>
+    <div v-else :class="['top-nav-header-index', theme]">
+      <div class="header-index-wide">
+        <div class="header-index-left">
+          <logo class="top-nav-header" />
+          <s-menu
+            mode="horizontal"
+            :menu="menus"
+            :theme="theme"
+          ></s-menu>
+        </div>
+        <user-menu class="header-index-right">
+
+        </user-menu>
       </div>
     </div>
+
   </a-layout-header>
 </template>
 
 <script>
-  import HeaderNotice from './HeaderNotice'
-  import {mapActions, mapGetters} from 'vuex'
+  import UserMenu from '../tools/UserMenu'
+  import SMenu from '../menu/'
+  import Logo from '../tools/Logo'
+
+  import { mapState } from 'vuex'
 
   export default {
     name: "LayoutHeader",
     components: {
-      HeaderNotice
+      UserMenu,
+      SMenu,
+      Logo
     },
     props: {
+      mode: {
+        type: String,
+        // sidemenu, topmenu
+        default: 'sidemenu'
+      },
+      theme: {
+        type: String,
+        required: false,
+        default: 'dark'
+      },
       collapsed: {
         type: Boolean,
         required: false,
@@ -75,34 +70,20 @@
       }
     },
     data() {
-      return {}
+      return {
+        menus: [],
+      }
     },
     created() {
-
+      this.menus = this.mainMenu.find((item) => item.path === '/').children
+    },
+    computed: {
+      ...mapState({
+        mainMenu: state => state.permission.addRouters,
+      }),
     },
     methods: {
-      ...mapActions(["Logout"]),
-      ...mapGetters(["nickname", "avatar"]),
-      handleLogout() {
-        const that = this
 
-        this.$confirm({
-          title: '提示',
-          content: '真的要注销登录吗 ?',
-          onOk() {
-            return that.Logout({}).then(() => {
-              window.location.reload()
-            }).catch(err => {
-              that.$message.error({
-                title: '错误',
-                description: err.message
-              })
-            })
-          },
-          onCancel() {
-          },
-        });
-      },
       toggle() {
         this.$emit('toggle')
       }
@@ -110,6 +91,6 @@
   }
 </script>
 
-<style scoped>
+<style lang="scss" scoped>
 
 </style>

+ 124 - 30
src/components/page/GlobalLayout.vue

@@ -1,34 +1,36 @@
 <template>
   <a-layout class="layout" :class="device">
 
-    <a-drawer
-      v-if="device === 'mobile'"
-      :wrapClassName="'drawer-sider ' + theme"
-      placement="left"
-      @close="() => this.collapsed = false"
-      :closable="false"
-      :visible="collapsed"
-    >
+    <template v-if="layoutMode === 'sidemenu'">
+      <a-drawer
+        v-if="device === 'mobile'"
+        :wrapClassName="'drawer-sider ' + theme"
+        placement="left"
+        @close="() => this.collapsed = false"
+        :closable="false"
+        :visible="collapsed"
+      >
+        <side-menu
+          mode="inline"
+          :menus="menus"
+          @menuSelect="menuSelect"
+          :theme="theme"
+          :collapsed="false"
+          :collapsible="true"></side-menu>
+      </a-drawer>
+
       <side-menu
-        mode="inline"
+        v-else
         :menus="menus"
-        @menuSelect="menuSelect"
         :theme="theme"
-        :collapsed="false"
+        :mode="menuMode"
+        :collapsed="collapsed"
         :collapsible="true"></side-menu>
-    </a-drawer>
-
-    <side-menu
-      v-else
-      :menus="menus"
-      :theme="theme"
-      :mode="menuMode"
-      :collapsed="collapsed"
-      :collapsible="true"></side-menu>
+    </template>
 
-    <a-layout>
+    <a-layout :class="[layoutMode]">
       <!-- layout header -->
-      <global-header :collapsed="collapsed" :device="device" @toggle="toggle"/>
+      <global-header :mode="layoutMode" :theme="theme" :collapsed="collapsed" :device="device" @toggle="toggle"/>
 
       <!-- layout content -->
       <a-layout-content :style="{ margin: '24px 24px 0', height: '100%' }">
@@ -73,6 +75,7 @@
     computed: {
       ...mapState({
         mainMenu: state => state.permission.addRouters,
+        layoutMode: state => state.app.layout,
         sidebarOpened: state => state.app.sidebar.opened,
         theme: state => state.app.theme,
         device: state => state.app.device,
@@ -100,11 +103,7 @@
 <style lang="scss">
   body {
     // 打开滚动条固定显示
-    overflow-y: auto;
-
-    &.userLayout {
-      overflow-y: auto;
-    }
+    overflow-y: scroll;
 
     &.colorWeak {
       filter: invert(80%);
@@ -142,8 +141,7 @@
       cursor: pointer;
       transition: color .3s;
       &:hover {
-        color: #1890ff;
-        background: #e6f7ff;
+        background: rgba(0, 0, 0, 0.025);
       }
     }
 
@@ -153,6 +151,9 @@
       background: #fff;
       box-shadow: 0 1px 4px rgba(0, 21, 41, .08);
       position: relative;
+    }
+
+    .header, .top-nav-header-index {
 
       .user-wrapper {
         float: right;
@@ -166,7 +167,7 @@
           height: 100%;
 
           &:hover {
-            background: #e6f7ff;
+            background: rgba(0, 0, 0, 0.025);
           }
 
           .avatar {
@@ -176,22 +177,115 @@
             vertical-align: middle;
           }
 
+
           .icon {
             font-size: 16px;
             padding: 4px;
           }
         }
       }
+
+      &.dark {
+        .user-wrapper {
+
+          .action {
+            color: rgba(255, 255, 255, 0.85);
+
+            &:hover {
+              background: rgba(255, 255, 255, 0.16);
+            }
+          }
+        }
+      }
     }
 
+    .top-nav-header-index {
+      box-shadow: 0 1px 4px rgba(0,21,41,.08);
+      position: relative;
+      transition: background .3s,width .2s;
+
+      .header-index-wide {
+        max-width: 1200px;
+        margin: auto;
+        padding-left: 0;
+        display: flex;
+        height: 64px;
+
+        .ant-menu.ant-menu-horizontal {
+          border: none;
+          height: 64px;
+          line-height: 64px;
+        }
+
+        .header-index-left {
+          flex: 1 1;
+          display: flex;
+
+          .logo.top-nav-header {
+            width: 165px;
+            height: 64px;
+            position: relative;
+            line-height: 64px;
+            transition: all .3s;
+            overflow: hidden;
+
+            img {
+              display: inline-block;
+              vertical-align: middle;
+              height: 32px;
+            }
+
+            h1 {
+              color: #fff;
+              display: inline-block;
+              vertical-align: top;
+              font-size: 16px;
+              margin: 0 0 0 12px;
+              font-weight: 400;
+            }
+          }
+        }
+
+        .header-index-right {
+          float: right;
+          height: 64px;
+          overflow: hidden;
+        }
+      }
+
+      &.light {
+        background-color: #fff;
+
+        .header-index-wide {
+          .header-index-left {
+            .logo {
+              h1 {
+                color: #002140;
+              }
+            }
+          }
+        }
+      }
+    }
+
+
     // 内容区
     .layout-content {
       margin: 24px 24px 0px;
       height: 100%;
+      height: 64px;
+      padding: 0 12px 0 0;
     }
 
   }
 
+  .topmenu {
+    .page-header-index-wide {
+      max-width: 1200px;
+      margin: 0 auto;
+    }
+  }
+
   // drawer-sider 自定义
   .ant-drawer.drawer-sider {
     .sider {

+ 32 - 27
src/components/page/PageHeader.vue

@@ -1,37 +1,41 @@
 <template>
   <div class="page-header">
-
-    <a-breadcrumb class="breadcrumb">
-      <a-breadcrumb-item v-for="(item, index) in breadList" :key="index">
-        <router-link v-if="item.name != name" :to="{ path: item.path }">
-          {{ item.meta.title }}
-        </router-link>
-        <span v-else>{{ item.meta.title }}</span>
-      </a-breadcrumb-item>
-    </a-breadcrumb>
-
-    <div class="detail">
-      <div class="main" v-if="!$route.meta.hiddenHeaderContent">
-        <div class="row">
-          <img v-if="logo" :src="logo" class="logo"/>
-          <h1 v-if="title" class="title">{{ title }}</h1>
-          <div class="action">
-            <slot name="action"></slot>
-          </div>
-        </div>
-        <div class="row">
-          <div v-if="avatar" class="avatar">
-            <a-avatar :src="avatar"/>
+    <div class="page-header-index-wide">
+      <a-breadcrumb class="breadcrumb">
+        <a-breadcrumb-item v-for="(item, index) in breadList" :key="index">
+          <router-link v-if="item.name != name" :to="{ path: item.path }">
+            {{ item.meta.title }}
+          </router-link>
+          <span v-else>{{ item.meta.title }}</span>
+        </a-breadcrumb-item>
+      </a-breadcrumb>
+
+      <div class="detail">
+        <div class="main" v-if="!$route.meta.hiddenHeaderContent">
+          <div class="row">
+            <img v-if="logo" :src="logo" class="logo"/>
+            <h1 v-if="title" class="title">{{ title }}</h1>
+            <div class="action">
+              <slot name="action"></slot>
+            </div>
           </div>
-          <div v-if="this.$slots.content" class="headerContent">
-            <slot name="content"></slot>
+          <div class="row">
+            <div v-if="avatar" class="avatar">
+              <a-avatar :src="avatar"/>
+            </div>
+            <div v-if="this.$slots.content" class="headerContent">
+              <slot name="content"></slot>
+            </div>
+            <div v-if="this.$slots.extra" class="extra">
+              <slot name="extra"></slot>
+            </div>
           </div>
-          <div v-if="this.$slots.extra" class="extra">
-            <slot name="extra"></slot>
+          <div>
+            <slot name="pageMenu"></slot>
           </div>
         </div>
-      </div>
 
+      </div>
     </div>
   </div>
 </template>
@@ -97,6 +101,7 @@
 </script>
 
 <style lang="scss" scoped>
+
   .page-header {
     background: #fff;
     padding: 16px 32px 0;

+ 31 - 1
src/components/page/PageLayout.vue

@@ -16,9 +16,22 @@
         </div>
       </div>
       <slot slot="extra" name="extra"></slot>
+      <div slot="pageMenu">
+        <div class="page-menu-search" v-if="search">
+          <a-input-search style="width: 80%; max-width: 522px;" placeholder="请输入..." size="large" enterButton="搜索" />
+        </div>
+        <div class="page-menu-tabs" v-if="tabs && tabs.items">
+          <!-- @change="callback" :activeKey="activeKey" -->
+          <a-tabs :tabBarStyle="{margin: 0}" @change="tabs.callback" :activeKey="tabs.active()">
+            <a-tab-pane v-for="item in tabs.items" :tab="item.title" :key="item.key"></a-tab-pane>
+          </a-tabs>
+        </div>
+      </div>
     </page-header>
     <div class="content">
-      <slot></slot>
+      <div :class="['page-header-index-wide']">
+        <slot></slot>
+      </div>
     </div>
   </div>
 </template>
@@ -56,8 +69,18 @@
       extraImage: {
         type: String,
         default: null
+      },
+      search: {
+        type: Boolean,
+        default: false
+      },
+      tabs: {
+        type: Object,
+        default: () => {}
       }
     },
+    methods: {
+    }
   }
 </script>
 
@@ -91,4 +114,11 @@
       }
     }
   }
+  .page-menu-search {
+    text-align: center;
+    margin-bottom: 16px;
+  }
+  .page-menu-tabs {
+    margin-top: 48px;
+  }
 </style>

+ 58 - 0
src/components/page/SHeaderNotice.vue

@@ -0,0 +1,58 @@
+<template>
+  <a-popover trigger="click" placement="bottomRight" :overlayStyle="{ width: '300px' }">
+    <template slot="content">
+      <a-spin :spinning="loadding">
+        <a-tabs>
+          <a-tab-pane v-for="(tab, k) in tabs" :tab="tab.title" :key="k">
+
+          </a-tab-pane>
+        </a-tabs>
+      </a-spin>
+    </template>
+    <span @click="fetchNotice" class="header-notice">
+      <a-badge count="12">
+        <a-icon style="font-size: 16px; padding: 4px" type="bell" />
+      </a-badge>
+    </span>
+  </a-popover>
+</template>
+
+<script>
+  export default {
+    name: "HeaderNotice",
+    props: {
+      tabs: {
+        type: Array,
+        default: null,
+        required: true
+      }
+    },
+    data () {
+      return {
+        loadding: false
+      }
+    },
+    methods: {
+      fetchNotice () {
+        if (this.loadding) {
+          this.loadding = false
+          return
+        }
+        this.loadding = true
+        setTimeout(() => {
+          this.loadding = false
+        }, 2000)
+      }
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+  .header-notice{
+    display: inline-block;
+    transition: all 0.3s;
+    span {
+      vertical-align: initial;
+    }
+  }
+</style>

+ 38 - 3
src/components/setting/SettingDrawer.vue

@@ -18,7 +18,7 @@
               <template slot="title">
                 暗色菜单风格
               </template>
-              <div class="setting-drawer-index-item" @click="changeMenuTheme('dark')">
+              <div class="setting-drawer-index-item" @click="handleMenuTheme('dark')">
                 <img src="https://gw.alipayobjects.com/zos/rmsportal/LCkqqYNmvBEbokSDscrm.svg" alt="dark">
                 <div class="setting-drawer-index-selectIcon" v-if="navTheme === 'dark'">
                   <a-icon type="check"/>
@@ -30,7 +30,7 @@
               <template slot="title">
                 亮色菜单风格
               </template>
-              <div class="setting-drawer-index-item" @click="changeMenuTheme('light')">
+              <div class="setting-drawer-index-item" @click="handleMenuTheme('light')">
                 <img src="https://gw.alipayobjects.com/zos/rmsportal/jpRkZQMyYRryryPNtyIC.svg" alt="light">
                 <div class="setting-drawer-index-selectIcon" v-if="navTheme !== 'dark'">
                   <a-icon type="check"/>
@@ -55,8 +55,39 @@
 
           </div>
         </div>
+        <a-divider />
+
+        <div :style="{ marginBottom: '24px' }">
+          <h3 class="setting-drawer-index-title">导航模式</h3>
+
+          <div class="setting-drawer-index-blockChecbox">
+            <a-tooltip>
+              <template slot="title">
+                侧边栏导航
+              </template>
+              <div class="setting-drawer-index-item" @click="handleLayout('sidemenu')">
+                <img src="https://gw.alipayobjects.com/zos/rmsportal/JopDzEhOqwOjeNTXkoje.svg" alt="sidemenu">
+                <div class="setting-drawer-index-selectIcon" v-if="layoutMode === 'sidemenu'">
+                  <a-icon type="check"/>
+                </div>
+              </div>
+            </a-tooltip>
 
+            <a-tooltip>
+              <template slot="title">
+                顶部栏导航
+              </template>
+              <div class="setting-drawer-index-item" @click="handleLayout('topmenu')">
+                <img src="https://gw.alipayobjects.com/zos/rmsportal/KDNDBbriJhLwuqMoxcAr.svg" alt="topmenu">
+                <div class="setting-drawer-index-selectIcon" v-if="layoutMode !== 'sidemenu'">
+                  <a-icon type="check"/>
+                </div>
+              </div>
+            </a-tooltip>
+          </div>
+        </div>
         <a-divider />
+
         <div :style="{ marginBottom: '24px' }">
           <h3 class="setting-drawer-index-title">其他设置</h3>
           <div>
@@ -109,6 +140,7 @@
     computed: {
       ...mapState({
         navTheme: state => state.app.theme,
+        layoutMode: state => state.app.layout,
         primaryColor: state => state.app.color,
         colorWeak: state => state.app.weak,
       })
@@ -143,9 +175,12 @@
         this.$store.dispatch('ToggleWeak', checked)
         updateColorWeak(checked)
       },
-      changeMenuTheme (theme) {
+      handleMenuTheme (theme) {
         this.$store.dispatch('ToggleTheme', theme)
       },
+      handleLayout (mode) {
+        this.$store.dispatch('ToggleLayoutMode', mode)
+      },
       changeColor (color) {
         if (this.primaryColor !== color) {
           this.$store.dispatch('ToggleColor', color)

+ 7 - 1
src/components/page/HeaderNotice.vue → src/components/tools/HeaderNotice.vue

@@ -1,5 +1,5 @@
 <template>
-  <a-popover trigger="click" placement="bottomRight" :overlayStyle="{ width: '300px' }">
+  <a-popover trigger="click" placement="bottomRight" :autoAdjustOverflow="false" overlayClassName="header-notice-wrapper" :overlayStyle="{ width: '300px', top: '50px' }">
     <template slot="content">
       <a-spin :spinning="loadding">
         <a-tabs>
@@ -62,10 +62,16 @@
   }
 </script>
 
+<style lang="css">
+  .header-notice-wrapper {
+    top: 50px !important;
+  }
+</style>
 <style lang="scss" scoped>
   .header-notice{
     display: inline-block;
     transition: all 0.3s;
+
     span {
       vertical-align: initial;
     }

+ 14 - 0
src/components/tools/Logo.vue

@@ -0,0 +1,14 @@
+<template>
+  <div class="logo">
+    <router-link :to="{name:'dashboard'}">
+      <img src="~@/assets/logo.svg" alt="logo">
+      <h1>Ant Design Pro</h1>
+    </router-link>
+  </div>
+</template>
+
+<script>
+  export default {
+    name: "Logo"
+  }
+</script>

+ 1 - 1
src/components/tools/TwoStepCaptcha.vue

@@ -26,7 +26,7 @@
           fieldDecoratorId="stepCode"
           :fieldDecoratorOptions="{rules: [{ required: true, message: '请输入 6 位动态码!', pattern: /^\d{6}$/, len: 6 }]}"
         >
-          <a-input :style="{ textAlign: 'center' }" placeholder="000000" />
+          <a-input :style="{ textAlign: 'center' }" @keyup.enter.native="handleStepOk" placeholder="000000" />
         </a-form-item>
         <p style="text-align: center">
           <a @click="onForgeStepCode">遗失手机?</a>

+ 79 - 0
src/components/tools/UserMenu.vue

@@ -0,0 +1,79 @@
+<template>
+  <div class="user-wrapper">
+    <span class="action">
+      <a-icon type="question-circle-o"></a-icon>
+    </span>
+    <header-notice class="action"/>
+    <a-dropdown>
+      <span class="action ant-dropdown-link user-dropdown-menu">
+        <a-avatar class="avatar" size="small" :src="avatar()"/>
+        <span>{{ nickname() }}</span>
+      </span>
+      <a-menu slot="overlay" class="user-dropdown-menu-wrapper">
+        <a-menu-item key="0">
+          <router-link :to="{ name: 'center' }">
+            <a-icon type="user"/>
+            <span>个人中心</span>
+          </router-link>
+        </a-menu-item>
+        <a-menu-item key="1">
+          <router-link :to="{ name: 'settings' }">
+            <a-icon type="setting"/>
+            <span>账户设置</span>
+          </router-link>
+        </a-menu-item>
+        <a-menu-item key="2" disabled>
+          <a-icon type="setting"/>
+          <span>测试</span>
+        </a-menu-item>
+        <a-menu-divider/>
+        <a-menu-item key="3">
+          <a href="javascript:;" @click="handleLogout">
+            <a-icon type="logout"/>
+            <span>退出登录</span>
+          </a>
+        </a-menu-item>
+      </a-menu>
+    </a-dropdown>
+  </div>
+</template>
+
+<script>
+  import HeaderNotice from './HeaderNotice'
+  import { mapActions, mapGetters } from 'vuex'
+
+  export default {
+    name: "UserMenu",
+    components: {
+      HeaderNotice
+    },
+    methods: {
+      ...mapActions(["Logout"]),
+      ...mapGetters(["nickname", "avatar"]),
+      handleLogout() {
+        const that = this
+
+        this.$confirm({
+          title: '提示',
+          content: '真的要注销登录吗 ?',
+          onOk() {
+            return that.Logout({}).then(() => {
+              window.location.reload()
+            }).catch(err => {
+              that.$message.error({
+                title: '错误',
+                description: err.message
+              })
+            })
+          },
+          onCancel() {
+          },
+        });
+      },
+    }
+  }
+</script>
+
+<style scoped>
+
+</style>

+ 1 - 0
src/defaultConfig.js

@@ -11,6 +11,7 @@
 export default {
   primaryColor: '#1890FF', // primary color of ant design
   navTheme: 'dark', // theme for nav menu
+  layout: 'sidemenu',
   colorWeak: false,
   // vue-ls options
   storageOptions: {

+ 2 - 1
src/main.js

@@ -13,7 +13,7 @@ import 'ant-design-vue/dist/antd.less';  // or 'ant-design-vue/dist/antd.less'
 import '@/permission' // permission control
 import '@/utils/filter' // base filter
 
-import { ACCESS_TOKEN, DEFAULT_COLOR, DEFAULT_THEME, DEFAULT_COLOR_WEAK, SIDEBAR_TYPE } from "@/store/mutation-types"
+import { ACCESS_TOKEN, DEFAULT_COLOR, DEFAULT_THEME, DEFAULT_LAYOUT_MODE, DEFAULT_COLOR_WEAK, SIDEBAR_TYPE } from "@/store/mutation-types"
 import config from '@/defaultConfig'
 
 Vue.config.productionTip = false
@@ -29,6 +29,7 @@ new Vue({
   mounted () {
     store.commit('SET_SIDEBAR_TYPE', Vue.ls.get(SIDEBAR_TYPE, false))
     store.commit('TOGGLE_THEME', Vue.ls.get(DEFAULT_THEME, config.navTheme))
+    store.commit('TOGGLE_LAYOUT_MODE', Vue.ls.get(DEFAULT_LAYOUT_MODE, config.layout))
     store.commit('TOGGLE_WEAK', Vue.ls.get(DEFAULT_COLOR_WEAK, config.colorWeak))
     store.commit('TOGGLE_COLOR', Vue.ls.get(DEFAULT_COLOR, config.primaryColor))
     store.commit('SET_TOKEN', Vue.ls.get(ACCESS_TOKEN))

+ 9 - 1
src/store/modules/app.js

@@ -1,5 +1,5 @@
 import Vue from 'vue'
-import { SIDEBAR_TYPE, DEFAULT_THEME, DEFAULT_COLOR, DEFAULT_COLOR_WEAK } from "@/store/mutation-types"
+import { SIDEBAR_TYPE, DEFAULT_THEME, DEFAULT_LAYOUT_MODE, DEFAULT_COLOR, DEFAULT_COLOR_WEAK } from "@/store/mutation-types"
 
 const app = {
   state: {
@@ -9,6 +9,7 @@ const app = {
     },
     device: 'desktop',
     theme: '',
+    layout: '',
     color: null,
     weak: false
   },
@@ -30,6 +31,10 @@ const app = {
       Vue.ls.set(DEFAULT_THEME, theme)
       state.theme = theme
     },
+    TOGGLE_LAYOUT_MODE: (state, layout) => {
+      Vue.ls.set(DEFAULT_LAYOUT_MODE, layout)
+      state.layout = layout
+    },
     TOGGLE_COLOR: (state, color) => {
       Vue.ls.set(DEFAULT_COLOR, color)
       state.color = color
@@ -52,6 +57,9 @@ const app = {
     ToggleTheme({ commit }, theme) {
       commit('TOGGLE_THEME', theme)
     },
+    ToggleLayoutMode({ commit }, mode) {
+      commit('TOGGLE_LAYOUT_MODE', mode)
+    },
     ToggleColor({ commit }, color) {
       commit('TOGGLE_COLOR', color)
     },

+ 1 - 0
src/store/mutation-types.js

@@ -1,5 +1,6 @@
 export const ACCESS_TOKEN = 'Access-Token'
 export const SIDEBAR_TYPE = 'SIDEBAR_TYPE'
 export const DEFAULT_THEME = 'DEFAULT_THEME'
+export const DEFAULT_LAYOUT_MODE = 'DEFAULT_LAYOUT_MODE'
 export const DEFAULT_COLOR = 'DEFAULT_COLOR'
 export const DEFAULT_COLOR_WEAK = 'DEFAULT_COLOR_WEAK'

+ 1 - 1
src/utils/request.js

@@ -8,7 +8,7 @@ import { ACCESS_TOKEN } from "@/store/mutation-types"
 // 创建 axios 实例
 const service = axios.create({
   baseURL: '/api', // api base_url
-  timeout: 5000 // 请求超时时间
+  timeout: 6000 // 请求超时时间
 })
 
 const err = (error) => {

+ 1 - 1
src/views/account/center/Index.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="page-header-wrapper-grid-content-main">
+  <div class="page-header-index-wide page-header-wrapper-grid-content-main">
 
     <a-row :gutter="24">
       <a-col :md="24" :lg="7">

+ 45 - 43
src/views/account/settings/Index.vue

@@ -1,49 +1,51 @@
 <template>
-  <a-card :bordered="false" :bodyStyle="{ padding: '16px 0', height: '100%' }" :style="{ height: '100%' }">
-    <div class="account-settings-info-main" :class="device">
-      <div class="account-settings-info-left">
-        <a-menu
-          :mode="device == 'mobile' ? 'horizontal' : 'inline'"
-          :style="{ border: '0', width: device == 'mobile' ? '560px' : 'auto'}"
-          :defaultSelectedKeys="defaultSelectedKeys"
-          type="inner"
-          @openChange="onOpenChange"
-        >
-          <a-menu-item key="/account/settings/base">
-            <router-link :to="{ name: 'BaseSettings' }">
-              基本设置
-            </router-link>
-          </a-menu-item>
-          <a-menu-item key="/account/settings/security">
-            <router-link :to="{ name: 'SecuritySettings' }">
-              安全设置
-            </router-link>
-          </a-menu-item>
-          <a-menu-item key="/account/settings/custom">
-            <router-link :to="{ name: 'CustomSettings' }">
-              个性化
-            </router-link>
-          </a-menu-item>
-          <a-menu-item key="/account/settings/binding">
-            <router-link :to="{ name: 'BindingSettings' }">
-              账户绑定
-            </router-link>
-          </a-menu-item>
-          <a-menu-item key="/account/settings/notification">
-            <router-link :to="{ name: 'NotificationSettings' }">
-              新消息通知
-            </router-link>
-          </a-menu-item>
-        </a-menu>
-      </div>
-      <div class="account-settings-info-right">
-        <div class="account-settings-info-title">
-          <span>{{ $route.meta.title }}</span>
+  <div class="page-header-index-wide">
+    <a-card :bordered="false" :bodyStyle="{ padding: '16px 0', height: '100%' }" :style="{ height: '100%' }">
+      <div class="account-settings-info-main" :class="device">
+        <div class="account-settings-info-left">
+          <a-menu
+            :mode="device == 'mobile' ? 'horizontal' : 'inline'"
+            :style="{ border: '0', width: device == 'mobile' ? '560px' : 'auto'}"
+            :defaultSelectedKeys="defaultSelectedKeys"
+            type="inner"
+            @openChange="onOpenChange"
+          >
+            <a-menu-item key="/account/settings/base">
+              <router-link :to="{ name: 'BaseSettings' }">
+                基本设置
+              </router-link>
+            </a-menu-item>
+            <a-menu-item key="/account/settings/security">
+              <router-link :to="{ name: 'SecuritySettings' }">
+                安全设置
+              </router-link>
+            </a-menu-item>
+            <a-menu-item key="/account/settings/custom">
+              <router-link :to="{ name: 'CustomSettings' }">
+                个性化
+              </router-link>
+            </a-menu-item>
+            <a-menu-item key="/account/settings/binding">
+              <router-link :to="{ name: 'BindingSettings' }">
+                账户绑定
+              </router-link>
+            </a-menu-item>
+            <a-menu-item key="/account/settings/notification">
+              <router-link :to="{ name: 'NotificationSettings' }">
+                新消息通知
+              </router-link>
+            </a-menu-item>
+          </a-menu>
+        </div>
+        <div class="account-settings-info-right">
+          <div class="account-settings-info-title">
+            <span>{{ $route.meta.title }}</span>
+          </div>
+          <route-view></route-view>
         </div>
-        <route-view></route-view>
       </div>
-    </div>
-  </a-card>
+    </a-card>
+  </div>
 </template>
 
 <script>

+ 1 - 1
src/views/dashboard/Analysis.vue

@@ -1,5 +1,5 @@
 <template>
-  <div>
+  <div class="page-header-index-wide">
     <a-row :gutter="24">
       <a-col :sm="24" :md="12" :xl="6" :style="{ marginBottom: '24px' }">
         <chart-card :loading="loading" title="总销售额" total="¥126,560">

+ 51 - 43
src/views/list/search/SearchLayout.vue

@@ -1,56 +1,64 @@
 <template>
-  <div>
-    <div class="search-head">
-      <div class="search-input">
-        <a-input-search style="width: 80%; max-width: 522px;" placeholder="请输入..." size="large" enterButton="搜索" />
-      </div>
-      <div style="padding: 0 24px">
-        <a-tabs :tabBarStyle="{margin: 0}" @change="callback" :activeKey="activeKey">
-          <a-tab-pane tab="文章" key="1"></a-tab-pane>
-          <a-tab-pane tab="项目" key="2"></a-tab-pane>
-          <a-tab-pane tab="应用" key="3"></a-tab-pane>
-        </a-tabs>
-      </div>
-    </div>
-    <div class="search-content">
-      <router-view />
-    </div>
+  <div class="search-content">
+    <router-view />
   </div>
 </template>
 
 <script>
   export default {
     name: "SearchLayout",
-    computed: {
-      activeKey () {
-        switch (this.$route.path) {
-          case '/list/search/article':
-            return '1'
-          case '/list/search/project':
-            return '2'
-          case '/list/search/application':
-            return '3'
-          default:
-            return '1'
-        }
+    data () {
+      return {
+        tabs: {
+          items: [
+            {
+              key: '1',
+              title: '文章'
+            },
+            {
+              key: '2',
+              title: '项目'
+            },
+            {
+              key: '3',
+              title: '应用'
+            },
+          ],
+          active: () => {
+            switch (this.$route.path) {
+              case '/list/search/article':
+                return '1'
+              case '/list/search/project':
+                return '2'
+              case '/list/search/application':
+                return '3'
+              default:
+                return '1'
+            }
+          },
+          callback: (key) => {
+            switch (key) {
+              case '1':
+                this.$router.push('/list/search/article')
+                break
+              case '2':
+                this.$router.push('/list/search/project')
+                break
+              case '3':
+                this.$router.push('/list/search/application')
+                break
+              default:
+                this.$router.push('/workplace')
+            }
+          }
+        },
+        search: true
       }
+    },
+    computed: {
+
     },
     methods: {
-      callback (key) {
-        switch (key) {
-          case '1':
-            this.$router.push('/list/search/article')
-            break
-          case '2':
-            this.$router.push('/list/search/project')
-            break
-          case '3':
-            this.$router.push('/list/search/application')
-            break
-          default:
-            this.$router.push('/workplace')
-        }
-      }
     }
   }
 </script>

+ 1 - 1
yarn.lock

@@ -1901,7 +1901,7 @@ ansi-styles@^3.2.1:
   dependencies:
     color-convert "^1.9.0"
 
-ant-design-vue@^1.1.6:
+ant-design-vue@^1.1.7:
   version "1.1.7"
   resolved "https://registry.yarnpkg.com/ant-design-vue/-/ant-design-vue-1.1.7.tgz#19a9e1d53070cba93225c80145829898b003580b"
   integrity sha512-3lhP0rAY4v3ZwzBFqSJaBJ6Wmo1E6Z4kQ2m4+ph1OuN4DAW2oDw2KZZrZcqT9GscYUgdn1A7dCiV6MO+aJU5tw==