Browse Source

perf: optimization menus style

xiaoxian521 4 years ago
parent
commit
05b106203c

+ 18 - 13
package-lock.json

@@ -650,18 +650,18 @@
       "integrity": "sha1-INIt0Np9NYuyHBf5vehigVJkLHc="
     },
     "@vueuse/core": {
-      "version": "4.8.2",
-      "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-4.8.2.tgz",
-      "integrity": "sha512-d6SX9YSWC8svdCEZvlKH3zmstPqNS1h1RHgZUbkxAC/zoNIYP88Ivl1pF3SYm0Iksl6D4Zu/oImKXWCBW21r6g==",
+      "version": "4.9.0",
+      "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-4.9.0.tgz",
+      "integrity": "sha512-vkGB6T9IgsdvbEyEVLaNu+JlMXonqx/mUX5El1u252ZTOa9khsVIAWWEMfxFyXz245V2hJi+O+TZv6rwyHbOLg==",
       "requires": {
-        "@vueuse/shared": "4.8.2",
+        "@vueuse/shared": "4.9.0",
         "vue-demi": "^0.7.5"
       }
     },
     "@vueuse/shared": {
-      "version": "4.8.2",
-      "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-4.8.2.tgz",
-      "integrity": "sha512-Bjy15IHyqUpRbg9cRE9afFwD0gLtGI0tJW7fITWGCwYmSWpBoD+EnGBBGvnoP9pOtxkri9Wte/uKwcVnDos7QA==",
+      "version": "4.9.0",
+      "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-4.9.0.tgz",
+      "integrity": "sha512-u5bSe39llw2DjGerZjFK/jv04sF3G1BX5t4aRat1s+9hzm8mEB55uorqA3VxCgTFMNyc0sactZhj6YIzYdG0dg==",
       "requires": {
         "vue-demi": "^0.7.5"
       }
@@ -1478,6 +1478,11 @@
       "resolved": "https://registry.npm.taobao.org/lodash/download/lodash-4.17.21.tgz",
       "integrity": "sha1-Z5WRxWTDv/quhFTPCz3zcMPWkRw="
     },
+    "lodash-es": {
+      "version": "4.17.21",
+      "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
+      "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
+    },
     "lodash.camelcase": {
       "version": "4.3.0",
       "resolved": "https://registry.npm.taobao.org/lodash.camelcase/download/lodash.camelcase-4.3.0.tgz",
@@ -2079,9 +2084,9 @@
       "dev": true
     },
     "vite": {
-      "version": "2.2.1",
-      "resolved": "https://registry.npmjs.org/vite/-/vite-2.2.1.tgz",
-      "integrity": "sha512-KIqK90EoJJpuqE86Y9DSkZjFNGgsyZX/4I1xENIitLRd3hgRtOlIGCJYrNnBD9/eqipz0OroAiIj9/R1JcOdFA==",
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/vite/-/vite-2.2.2.tgz",
+      "integrity": "sha512-Y0IMdu+YuKsisJPk6NaEwEQC7FFfLQSN97ZTE4gvrELrk8dGjTFslhNCG8wkdzMSLCzfOdpCMT8cPXAhqzkPfg==",
       "dev": true,
       "requires": {
         "esbuild": "^0.9.3",
@@ -2266,9 +2271,9 @@
       "integrity": "sha1-rId6p2qcRTaMl5Rx5GG1INOObPU="
     },
     "vxe-table": {
-      "version": "4.0.12",
-      "resolved": "https://registry.npmjs.org/vxe-table/-/vxe-table-4.0.12.tgz",
-      "integrity": "sha512-S//Q2BCTe8dojA+mi6cGX7ONO/2ZrVLPyld0UqclcYf4rMHjYZkGb/CXj475XzBgN4DmXxw8KVsWVMNzGXKnzg=="
+      "version": "4.0.14",
+      "resolved": "https://registry.npmjs.org/vxe-table/-/vxe-table-4.0.14.tgz",
+      "integrity": "sha512-0fwddIk7X+NPneZuucvy6BbTmZ9oRfTxP02ZfWOu5c4KegVSFTIxMWlGkDOhtwf67HcA6gh9UwWkyoPiKhvvCQ=="
     },
     "wangeditor": {
       "version": "4.6.14",

+ 4 - 3
package.json

@@ -13,7 +13,7 @@
     "@amap/amap-jsapi-loader": "^1.0.1",
     "@logicflow/core": "^0.3.4",
     "@logicflow/extension": "^0.3.4",
-    "@vueuse/core": "^4.8.2",
+    "@vueuse/core": "^4.9.0",
     "await-to-js": "^2.1.1",
     "axios": "^0.21.1",
     "cropperjs": "^1.5.11",
@@ -22,6 +22,7 @@
     "echarts": "^5.1.0",
     "element-plus": "^1.0.2-beta.40",
     "font-awesome": "^4.7.0",
+    "lodash-es": "^4.17.21",
     "mitt": "^2.1.0",
     "mockjs": "^1.1.0",
     "nprogress": "^0.2.0",
@@ -35,7 +36,7 @@
     "vue-types": "^3.0.2",
     "vuedraggable": "^4.0.1",
     "vuex": "^4.0.0",
-    "vxe-table": "^4.0.12",
+    "vxe-table": "^4.0.14",
     "wangeditor": "^4.0.3",
     "xe-ajax": "^4.0.5",
     "xe-utils": "^3.1.12",
@@ -56,7 +57,7 @@
     "sass": "^1.32.8",
     "sass-loader": "^11.0.1",
     "typescript": "^4.2.4",
-    "vite": "^2.2.1",
+    "vite": "^2.2.2",
     "vite-plugin-mock": "^2.5.0",
     "vite-plugin-style-import": "^0.9.2"
   }

+ 3 - 3
src/layout/components/sidebar/index.vue

@@ -3,10 +3,10 @@
     <el-menu
       :default-active="activeMenu"
       :collapse="isCollapse"
-      background-color="#304156"
-      text-color="#bfcbd9"
+      background-color="#1b2a47"
+      text-color="#7a80b4"
       :unique-opened="false"
-      active-text-color="#409EFF"
+      active-text-color="#fff"
       :collapse-transition="false"
       mode="vertical"
       @select="menuSelect"

+ 20 - 2
src/plugins/i18n/config.ts

@@ -7,8 +7,9 @@ export const menusConfig = {
   zh: {
     message: {
       hshome: "首页",
-      hsuserManagement: "用户管理",
+      hssysManagement: "系统管理",
       hsBaseinfo: "基础信息",
+      hsDict: "字典管理",
       hseditor: "编辑器",
       hserror: "错误页面",
       hsfourZeroFour: "404",
@@ -29,8 +30,9 @@ export const menusConfig = {
   en: {
     message: {
       hshome: "Home",
-      hsuserManagement: "User Manage",
+      hssysManagement: "System Manage",
       hsBaseinfo: "Base Info",
+      hsDict: "Dict Manage",
       hseditor: "Editor",
       hserror: "Error Page",
       hsfourZeroFour: "404",
@@ -63,6 +65,9 @@ export const buttonConfig = {
       hsadd: "新增",
       hsmark: "标记/取消",
       hssave: "保存",
+      hssearch: "搜索",
+      hsexpendAll: "全部展开",
+      hscollapseAll: "全部折叠",
     },
   },
   en: {
@@ -76,10 +81,23 @@ export const buttonConfig = {
       hsadd: "Add",
       hsmark: "Mark/Cancel",
       hssave: "Save",
+      hssearch: "Search",
+      hsexpendAll: "Expand All",
+      hscollapseAll: "Collapse All",
     },
   },
 };
 
+// 配置
+// export const xxxx = {
+//   zh: {
+//     message: {},
+//   },
+//   en: {
+//     message: {},
+//   },
+// };
+
 const localesList = [menusConfig, buttonConfig];
 
 export const localesConfigs = {

+ 1 - 0
src/plugins/vxe-table/index.ts

@@ -49,6 +49,7 @@ import {
 
 // 全局默认参数
 VXETable.setup({
+  size: "medium",
   version: 0,
   zIndex: 100,
   table: {

+ 19 - 8
src/router/index.ts

@@ -212,26 +212,37 @@ const routes: Array<RouteRecordRaw> = [
     },
   },
   {
-    path: "/user",
-    name: "user",
+    path: "/system",
+    name: "system",
     component: Layout,
-    redirect: "/user/base",
+    redirect: "/system/base",
     children: [
       {
-        path: "/user/base",
+        path: "/system/base",
         component: () =>
-          import(/* webpackChunkName: "user" */ "../views/user.vue"),
+          import(/* webpackChunkName: "system" */ "../views/system/user.vue"),
         meta: {
-          // icon: 'el-icon-user',
+          // icon: '',
           title: "message.hsBaseinfo",
           showLink: false,
           savedPosition: true,
         },
       },
+      {
+        path: "/system/dict",
+        component: () =>
+          import(/* webpackChunkName: "system" */ "../views/system/dict.vue"),
+        meta: {
+          // icon: '',
+          title: "message.hsDict",
+          showLink: false,
+          savedPosition: true,
+        },
+      },
     ],
     meta: {
-      icon: "el-icon-user",
-      title: "message.hsuserManagement",
+      icon: "el-icon-setting",
+      title: "message.hssysManagement",
       showLink: true,
       savedPosition: true,
     },

+ 18 - 18
src/style/sidebar.scss

@@ -1,8 +1,7 @@
 #app {
-
   .main-container {
     min-height: 100%;
-    transition: margin-left .28s;
+    transition: margin-left 0.28s;
     margin-left: $sideBarWidth;
     position: relative;
   }
@@ -22,7 +21,8 @@
 
     // reset element-plus css
     .horizontal-collapse-transition {
-      transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out;
+      transition: 0s width ease-in-out, 0s padding-left ease-in-out,
+        0s padding-right ease-in-out;
     }
 
     .scrollbar-wrapper {
@@ -56,6 +56,7 @@
     .el-menu {
       border: none;
       height: 100%;
+      // background-color: $menuBg !important;
       // width: 100% !important;
     }
 
@@ -67,11 +68,12 @@
       }
     }
 
-    .is-active>.el-submenu__title {
+    .is-active > .el-submenu__title,
+    .is-active > .el-submenu__title i {
       color: $subMenuActiveText !important;
     }
 
-    & .nest-menu .el-submenu>.el-submenu__title,
+    & .nest-menu .el-submenu > .el-submenu__title,
     & .el-submenu .el-menu-item {
       min-width: $sideBarWidth !important;
       background-color: $subMenuBg !important;
@@ -83,7 +85,6 @@
   }
 
   .hideSidebar {
-   
     .sidebar-container {
       width: 54px !important;
     }
@@ -98,14 +99,12 @@
 
       .el-tooltip {
         padding: 0 !important;
-        
       }
     }
 
     .el-submenu {
       overflow: hidden;
-      &>.el-submenu__title {
-
+      & > .el-submenu__title {
         .el-submenu__icon-arrow {
           display: none;
         }
@@ -115,8 +114,8 @@
     .el-menu--collapse {
       margin-left: -5px; //需优化的地方
       .el-submenu {
-        &>.el-submenu__title {
-          &>span {
+        & > .el-submenu__title {
+          & > span {
             height: 0;
             width: 0;
             overflow: hidden;
@@ -139,7 +138,7 @@
     }
 
     .sidebar-container {
-      transition: transform .28s;
+      transition: transform 0.28s;
       width: $sideBarWidth !important;
     }
 
@@ -153,7 +152,6 @@
   }
 
   .withoutAnimation {
-
     .main-container,
     .sidebar-container {
       transition: none;
@@ -163,13 +161,13 @@
 
 // when menu collapsed
 .el-menu--vertical {
-  &>.el-menu {
+  & > .el-menu {
     i {
       margin-right: 16px;
     }
   }
 
-  .nest-menu .el-submenu>.el-submenu__title,
+  .nest-menu .el-submenu > .el-submenu__title,
   .el-menu-item {
     &:hover {
       // you can use $subMenuHover
@@ -178,7 +176,7 @@
   }
 
   // the scroll bar appears when the subMenu is too long
-  >.el-menu--popup {
+  > .el-menu--popup {
     max-height: 100vh;
     overflow-y: auto;
 
@@ -195,7 +193,9 @@
       border-radius: 20px;
     }
   }
-  
 }
 
-.el-scrollbar__wrap { overflow: auto; height: 100%; }
+.el-scrollbar__wrap {
+  overflow: auto;
+  height: 100%;
+}

+ 9 - 4
src/style/variables.scss

@@ -1,11 +1,16 @@
 // sidebar
-$menuText: #bfcbd9;
-$menuActiveText: #409eff;
+$menuText: #7a80b4;
+$menuActiveText: #7a80b4;
 $subMenuActiveText: #f4f4f5;
-$menuBg: #304156;
-$menuHover: #263445;
 
+//菜单背景
+$menuBg: #1b2a47;
+// 鼠标覆盖菜单时的背景
+$menuHover: #2a395b;
+
+// 子菜单背景
 $subMenuBg: #1f2d3d;
+// 鼠标覆盖子菜单时的背景
 $subMenuHover: #001528;
 
 $sideBarWidth: 210px;

+ 210 - 0
src/views/system/dict.vue

@@ -0,0 +1,210 @@
+<template>
+  <div class="dict-container">
+    <vxe-toolbar>
+      <template #buttons>
+        <vxe-input
+          v-model="demo1.filterName"
+          :placeholder="$t('message.hssearch')"
+          @keyup="searchEvent"
+        ></vxe-input>
+      </template>
+      <template #tools>
+        <vxe-button icon="el-icon-circle-plus-outline" status="primary">{{$t('message.hsadd')}}</vxe-button>
+        <vxe-button
+          icon="el-icon-folder-opened"
+          status="primary"
+          @click="$refs.xTree.setAllTreeExpand(true)"
+        >{{$t('message.hsexpendAll')}}</vxe-button>
+        <vxe-button
+          icon="el-icon-folder"
+          status="primary"
+          @click="$refs.xTree.clearTreeExpand()"
+        >{{$t('message.hscollapseAll')}}</vxe-button>
+      </template>
+    </vxe-toolbar>
+
+    <vxe-table
+      ref="xTree"
+      border
+      resizable
+      :tree-config="{children: 'children', iconOpen: 'fa fa-minus-square-o', iconClose: 'fa fa-plus-square-o'}"
+      :data="demo1.tableData"
+    >
+      <vxe-table-column tree-node field="name" title="字典名称"></vxe-table-column>
+      <vxe-table-column field="model" title="字典类型"></vxe-table-column>
+      <vxe-table-column title="操作" width="330">
+        <template #default="{ row }">
+          <vxe-button type="text" icon="el-icon-edit" @click="demo1.value8 = true">编辑</vxe-button>
+          <vxe-button type="text" icon="el-icon-circle-plus-outline">新增子类型</vxe-button>
+          <vxe-button v-show="row.model" type="text" icon="el-icon-setting">字典配置</vxe-button>
+          <vxe-button type="text" icon="el-icon-delete" @click="confirmEvent">删除</vxe-button>
+        </template>
+      </vxe-table-column>
+    </vxe-table>
+
+    <vxe-modal
+      v-model="demo1.value8"
+      title="记忆功能的窗口"
+      width="440"
+      height="230"
+      show-zoom
+      resize
+      remember
+    >
+      <template #default>
+        <vxe-form>
+          <vxe-form-item span="24">
+            <template #default>
+              <vxe-form
+                :data="demo1.formData3"
+                :rules="demo1.formRules3"
+                title-align="right"
+                title-width="80"
+              >
+                <vxe-form-item
+                  title="字典名称"
+                  field="name"
+                  span="24"
+                  :item-render="{name: 'input', attrs: {placeholder: '请输入字典名称'}}"
+                ></vxe-form-item>
+                <vxe-form-item
+                  title="字典类型"
+                  field="nickname"
+                  span="24"
+                  :item-render="{name: 'input', attrs: {placeholder: '请输入字典类型'}}"
+                ></vxe-form-item>
+                <vxe-form-item align="right" span="24">
+                  <template #default>
+                    <vxe-button @click="demo1.value8 = false">取消</vxe-button>
+                    <vxe-button status="primary" @click="onEdit">保存</vxe-button>
+                  </template>
+                </vxe-form-item>
+              </vxe-form>
+            </template>
+          </vxe-form-item>
+        </vxe-form>
+      </template>
+    </vxe-modal>
+  </div>
+</template>
+<script  lang="ts">
+import { reactive, ref, nextTick } from "vue";
+import XEUtils from "xe-utils";
+import { cloneDeep } from "lodash-es";
+import { templateRef } from "@vueuse/core";
+import { VxeTablePropTypes, VxeTableInstance, VXETable } from "vxe-table";
+
+export default {
+  setup() {
+    const demo1 = reactive({
+      filterName: "",
+      tableData: [
+        {
+          id: 1,
+          name: "状态",
+          model: "",
+          children: [
+            {
+              id: "1-1",
+              name: "服务状态",
+              model: "serviceStatus"
+            },
+            {
+              id: "1-2",
+              name: "在线状态",
+              model: "onlienStatus"
+            }
+          ]
+        },
+        { id: 2, name: "操作系统", model: "operatingSystem" }
+      ]
+    });
+
+    let originData = cloneDeep(demo1.tableData);
+
+    const xTree = templateRef<HTMLElement | null>("xTree", null);
+    // const  = ref({} as VxeTableInstance);
+
+    const formatDate = (value: any) => {
+      return XEUtils.toDateString(value, "yyyy-MM-dd HH:mm:ss.S");
+    };
+
+    const handleSearch = () => {
+      const filterName = XEUtils.toValueString(demo1.filterName).trim();
+
+      if (filterName) {
+        const options = { children: "children" };
+        const searchProps = ["name"];
+
+        demo1.tableData = XEUtils.searchTree(
+          originData,
+          item =>
+            searchProps.some(
+              key => XEUtils.toValueString(item[key]).indexOf(filterName) > -1
+            ),
+          options
+        );
+
+        // 搜索之后默认展开所有子节点
+        nextTick(() => {
+          const $table = xTree.value;
+          $table.setAllTreeExpand(true);
+        });
+      } else {
+        demo1.tableData = originData;
+      }
+    };
+
+    // 创建一个防防抖函数,调用频率间隔 100 毫秒
+    const searchEvent = XEUtils.debounce(
+      function() {
+        handleSearch();
+      },
+      100,
+      { leading: false, trailing: true }
+    );
+
+    const confirmEvent = async () => {
+      const type = await VXETable.modal.confirm("您确定要删除吗?");
+      (await type) === "confirm" &&
+        VXETable.modal.message({
+          content: "测试数据,不可删除",
+          status: "error"
+        });
+    };
+
+    function onEdit() {
+      demo1.value8 = false;
+      VXETable.modal.message({
+        content: "测试数据,不可编辑",
+        status: "error"
+      });
+    }
+
+    return {
+      demo1,
+      formatDate,
+      searchEvent,
+      confirmEvent,
+      onEdit
+    };
+  }
+};
+</script>
+<style lang="scss" scoped>
+.dict-container {
+  margin: 10px;
+}
+.vxe-input + .vxe-button,
+.vxe-input + .vxe-button--dropdown,
+.vxe-button + .vxe-button,
+.vxe-button + .vxe-button--dropdown {
+  margin-left: 0;
+}
+.vxe-button.type--button:not(.is--round) {
+  border-radius: 0;
+}
+.vxe-button.size--medium.type--button {
+  margin-right: 0.07em;
+}
+</style>

+ 0 - 0
src/views/user.vue → src/views/system/user.vue