snow 11 bulan lalu
induk
melakukan
582cfeb14b

+ 0 - 1
src/components/Invoice/src/style.scss

@@ -165,4 +165,3 @@
   background: red;
 }
 
-

+ 39 - 0
src/layout/components/menu/index.vue

@@ -0,0 +1,39 @@
+<script lang="ts" setup>
+import { shallowRef, watch } from "vue"
+import { useRoute } from "vue-router"
+import { useNav } from "../../hooks/nav"
+
+import Sidebar from "./sidebar.vue"
+import SidebarItems from "./sidebar-items.vue"
+
+const { isCollapse, toggleSideBar } = useNav()
+const parentKey = shallowRef("")
+const childKey = shallowRef("")
+const route = useRoute()
+
+watch(() => route,() => {
+  const [_, parent] = (route.path).split('/')
+  parentKey.value = `/${parent}`
+  childKey.value = route.path
+},{
+  deep: true,
+  immediate: true
+})
+
+</script>
+
+
+<template>
+  <ElDrawer modal-class="menu-drawer-mask" class="menu-drawer" :modelValue="isCollapse" direction="ltr"
+    :before-close="toggleSideBar" :with-header="false">
+    <div class="flex" style="height:calc(100vh - 70px)">
+      <div class="w-[200px] mr-[10px] h-full">
+        <Sidebar v-model="parentKey" />
+      </div>
+
+      <div class="flex-1 h-full">
+        <SidebarItems :parent-key="parentKey" v-model="childKey" />
+      </div>
+    </div>
+  </ElDrawer>
+</template>

+ 52 - 0
src/layout/components/menu/sidebar-items.vue

@@ -0,0 +1,52 @@
+<script lang="ts" setup>
+import { ref, watch } from "vue"
+import { usePermissionStoreHook } from "/@/store/modules/permission";
+import { useNav } from "../../hooks/nav";
+
+import { useRouter } from "vue-router"
+
+const props = defineProps<{ parentKey: string, modelValue: string }>()
+const emit = defineEmits(['update:modelValue'])
+
+const permissionStore = usePermissionStoreHook()
+const { isCollapse, toggleSideBar } = useNav()
+
+const children = ref<any[]>([])
+const router = useRouter()
+
+function handleClick(path: string) {
+  isCollapse.value && toggleSideBar()
+  emit('update:modelValue', path)
+  router.push(path)
+}
+
+function handleRate(evt: MouseEvent) {
+  evt.stopPropagation()
+}
+
+watch(() => props.parentKey, path => {
+  if (!path) return
+  const menu = permissionStore.wholeMenus.find((menu) => menu.path === path)
+  if (!menu || !menu.children) return
+  children.value = menu.children.map(({ meta, path }) => ({ key: path, label: meta.title, icon: meta.icon }))
+}, {
+  immediate: true
+})
+
+</script>
+
+
+<template>
+  <div class="w-full h-full bg-white p-[10px]" style="border-radius: 3px">
+    <div :class="`child-drawer-item p-[5px] w-[24%] color-[#535360] select-none cursor-pointer mb-[10px] ml-[5px] inline-flex justify-between items-center
+     ${child.key === modelValue ? 'active' : ''}`" style="font-size: 12px" v-for="child in children" :key="child.key" relative
+      @click="() => handleClick(child.key)">
+      <div class="flex items-center">
+        <IconifyIconOnline :icon="child.icon" />
+        <p class="ml-[5px]">{{ child.label }}</p>
+      </div>
+
+      <ElRate class="rate absolute right-0 top-[3px]" style="height:12px" max="1" @click="handleRate" />
+    </div>
+  </div>
+</template>

+ 35 - 0
src/layout/components/menu/sidebar.vue

@@ -0,0 +1,35 @@
+<script lang="ts" setup>
+import { ref, onMounted } from "vue"
+import { useVModel } from "@vueuse/core"
+import { usePermissionStoreHook } from "/@/store/modules/permission";
+
+const emit = defineEmits(['update:modelValue'])
+defineProps<{ modelValue: string }>()
+
+
+const permissionStore = usePermissionStoreHook()
+const parents = ref<any[]>([])
+
+function handleClick(key: string) {
+  emit('update:modelValue', key)
+}
+
+onMounted(() => {
+  const _parents = permissionStore.wholeMenus.map(({ path, meta }) => ({ key: path, label: meta.title, icon: meta.icon }))
+  parents.value = _parents
+})
+</script>
+
+
+<template>
+  <el-scrollbar max-height="calc(100vh - 20px)">
+    <div class="flex flex-col">
+      <div :class="`menu-drawer-item flex bg-white mb-2  p-[10px] font-bold flex justify-between select-none cursor-pointer
+        items-center ${parent.key === modelValue ? 'active' : ''}`" style="font-size:12px !important"
+        v-for="parent in parents" @click="() => handleClick(parent.key)" :key="parent.key">
+        <p>{{ parent.label }}</p>
+        <IconifyIconOffline icon="arrow-right-s-line" />
+      </div>
+    </div>
+  </el-scrollbar>
+</template>

+ 8 - 9
src/layout/index.vue

@@ -19,6 +19,7 @@ import { useSettingStoreHook } from "/@/store/modules/settings";
 import backTop from "/@/assets/svg/back_top.svg?component";
 
 import navbar from "./components/navbar.vue";
+import MenuDrawer from "./components/menu/index.vue";
 import appMain from "./components/appMain.vue";
 import setting from "./components/setting/index.vue";
 import Vertical from "./components/sidebar/vertical.vue";
@@ -204,18 +205,14 @@ const layoutHeader = defineComponent({
       class="app-mask"
       @click="useAppStoreHook().toggleSideBar()"
     />
-    <Vertical
-      v-show="
+    
+    <!-- CHANGED <Vertical v-show="
         !pureSetting.hiddenSideBar &&
         (layout.includes('vertical') || layout.includes('mix'))
       "
-    />
-    <div
-      :class="[
-        'main-container',
-        pureSetting.hiddenSideBar ? 'main-hidden' : ''
-      ]"
-    >
+    /> -->
+
+    <div :class="['main-container', pureSetting.hiddenSideBar ? 'main-hidden' : '']">
       <div v-if="set.fixedHeader">
         <layout-header />
         <!-- 主体内容 -->
@@ -232,6 +229,8 @@ const layoutHeader = defineComponent({
         <!-- 主体内容 -->
         <app-main :fixed-header="set.fixedHeader" />
       </el-scrollbar>
+
+      <MenuDrawer />
     </div>
     <!-- 系统设置 -->
     <setting />

+ 0 - 2
src/store/modules/user.ts

@@ -290,8 +290,6 @@ export const useUserStore = defineStore({
 
                   data.forEach(e => {
                     e.child?.forEach(s => {
-                      console.log(s.menu_route);
-
                       const item = {
                         menu_route: (s.menu_route.split('_collection'))[0],
                         action: s.action

+ 71 - 0
src/style/index.scss

@@ -151,3 +151,74 @@ html {
 body {
   font-family: robotothin,-apple-system,Helvetica Neue,Helvetica,Arial,PingFang SC,Hiragino Sans GB,STHeiti,Microsoft YaHei,Microsoft JhengHei,SimSun,sans-serif !important;
 }
+
+
+
+.menu-drawer {
+  min-width: 1000px;
+
+  .el-drawer__body{
+   padding: 10px !important;
+   background-color: #f2f4f7;
+  } 
+ }
+
+
+.menu-drawer-item {
+  transition: all .2s;
+
+  &:hover{
+    p {
+    transition: all .2s;
+      color: #4091f7!important;
+    }
+  }
+
+  &.active {
+    background: rgba(64,145,247,0.3) !important;
+
+    p {
+      transition: all .2s;
+      color: #4091f7!important;
+    }
+  }
+}
+
+
+.menu-drawer-mask{
+  top:48px !important
+}
+
+
+.child-drawer-item{
+  transition: all .2s;
+
+  .el-rate{
+    display: none;
+  }
+
+  &:hover{
+    background-color: #f2f4f7;
+
+    p {
+      transition: all .3s;
+      color: #4091f7!important;
+    }
+
+    .el-rate{
+      display: block;
+    }
+  }
+
+  &.active {
+    background-color: #f2f4f7 !important;
+    p {
+      transition: all .3s;
+      color: #4091f7!important;
+    }
+
+    .el-rate{
+      display: block;
+    }
+  }
+}

+ 32 - 9
src/style/sidebar.scss

@@ -23,11 +23,26 @@
     align-items: center;
   }
 
+  /*  CHANGED */ 
+  // .main-container {
+  //   height: 100vh;
+  //   min-height: 100%;
+  //   transition: margin-left 0.1s;
+  //   // margin-left: $sideBarWidth;
+  //   position: relative;
+  //   background: #f0f2f5;
+
+  //   .el-scrollbar__wrap {
+  //     overflow: auto;
+  //     height: 100%;
+  //   }
+  // }
+
   .main-container {
     height: 100vh;
     min-height: 100%;
     transition: margin-left 0.1s;
-    margin-left: $sideBarWidth;
+    margin-left: 0;
     position: relative;
     background: #f0f2f5;
 
@@ -37,12 +52,14 @@
     }
   }
 
+
+  /* CHANGED */ 
   .fixed-header {
     position: fixed;
     top: 0;
-    right: 0;
+    left: 0;
     z-index: 998;
-    width: calc(100% - 210px);
+    width: 100%;
     min-width: 1000px;
     transition: width 0.1s;
   }
@@ -580,11 +597,12 @@ body[layout="vertical"] {
   }
 
   .hideSidebar {
-    .fixed-header {
-      width: calc(100% - 54px);
-      min-width: 1000px !important;
-      transition: width 0.1s;
-    }
+    /*  CHANGED */ 
+    // .fixed-header {
+    //   width: calc(100% - 54px);
+    //   min-width: 1000px !important;
+    //   transition: width 0.1s;
+    // }
 
     .sidebar-container {
       width: 54px !important;
@@ -594,8 +612,13 @@ body[layout="vertical"] {
       }
     }
 
+    /* CHANGED */ 
+    // .main-container {
+    //   margin-left: 54px;
+    // }
+
     .main-container {
-      margin-left: 54px;
+      margin-left:0px !important;
     }
 
     .submenu-title-noDropdown {

+ 37 - 0
src/views/welcome/components/message-center.vue

@@ -0,0 +1,37 @@
+<script setup lang="ts">
+
+const items = new Array(4).fill([
+  {
+    text:'审批中心',
+    total: 3,
+    bgColor: '#0296ff',
+    tagColor: '#35b1ff'
+  }
+])
+
+</script>
+
+
+<template>
+  <div class="w-full h-full rounded-lg bg-[#fcf6f5] p-[10px] flex flex-col">
+    <div class="flex justify-between">
+      <p style="font-size:14px">消息中心</p>
+    </div>
+
+    <div class="flex">
+      <div class="flex items-center">
+        <div class="h-[65px] w-[65px] bg-blue rounded-100 border-2 border-[#fff]"></div>
+        <div class="ml-[10px]">
+          <p class="font-bold">你好 ! xxx</p>
+          <p class="w-[120px]" style="word-break: break-all">*************************!</p>
+        </div>
+      </div>
+      
+      <div class="flex flex-1 bg-red">
+        <div v-for="(item,index) in items" :key="index">
+        
+        </div>
+      </div>
+    </div>
+  </div>
+</template>

+ 96 - 0
src/views/welcome/index copy 2.vue

@@ -0,0 +1,96 @@
+<script setup lang="ts">
+// import { watch, h } from "vue";
+// import emptyGif from "/@/assets/welcome.gif?component";
+import emptyGif from "/@/assets/welcome.jpg?component";
+// import { useRoute } from "vue-router";
+// import { ElMessageBox } from "element-plus";
+// import { useCompany } from "/@/hooks/core/useCompany";
+// const route = useRoute();
+
+// const { currentCompany } = useCompany();
+
+// watch(
+//   () => route,
+//   () => {
+//     if (route.query.error !== "1") return;
+//     setTimeout(() => {
+//       if (!currentCompany.value.companyName) return;
+//       ElMessageBox({
+//         title: "公司角色异常",
+//         message: h("p", null, [
+//           h("span", null, "公司 "),
+//           h("strong", null, currentCompany.value.companyName),
+//           h("span", null, " 角色异常或该公司禁用,请检查账号或者角色设置")
+//         ]),
+//         boxType: "confirm"
+//       });
+//     }, 500);
+//   },
+//   {
+//     deep: true,
+//     immediate: true
+//   }
+// );
+</script>
+
+<template>
+  <div class="welcome">
+    <!-- <div class="welcome-title">欢迎登录,采销365结算</div> -->
+    <!-- <img :src="emptyGif" /> -->
+  </div>
+</template>
+
+<style module scoped>
+.size {
+  height: 335px;
+}
+</style>
+
+<style lang="scss" scoped>
+.dashboard-container {
+  // background-color: #f0f4fd;
+  padding: 0 0 0 0;
+}
+.emptyGif {
+  display: block;
+  width: 100%;
+  height: 100%;
+  margin: 0 auto;
+  padding: 0 0 0 0;
+}
+
+.welcome {
+  // background-color: #e3e3e3;
+
+  background: url("./welcome.jpg") no-repeat !important;
+
+  // background: url("./background/start.png") no-repeat;
+  background-size:cover !important;
+
+  min-height: calc(100vh - 48px);
+  width: 100%;
+  height: calc(100vh - 48px);
+  display: flex;
+  padding: 0 0 0 0;
+  // padding: 0 6% 0 0;
+  text-align: center;
+  // align-items: flex-start ;
+  // .welcome-title {
+  //   vertical-align: top;
+  //   padding: 0;
+  //   margin: 8% 0 0 18px;
+  //   color: #97a8be;
+  //   display: inline-block;
+  //   height: 130px;
+  //   line-height: 130px;
+  //   font-size: 50px;
+  // }
+  //center;
+  // img {
+  //   display: block;
+  //   flex: 1;
+  //   padding: 0 0 0 0;
+  //   margin: 0 0 0 0;
+  // }
+}
+</style>

+ 15 - 72
src/views/welcome/index.vue

@@ -1,42 +1,24 @@
 <script setup lang="ts">
-// import { watch, h } from "vue";
-// import emptyGif from "/@/assets/welcome.gif?component";
-import emptyGif from "/@/assets/welcome.jpg?component";
-// import { useRoute } from "vue-router";
-// import { ElMessageBox } from "element-plus";
-// import { useCompany } from "/@/hooks/core/useCompany";
-// const route = useRoute();
+import MessageCenter from "./components/message-center.vue"
 
-// const { currentCompany } = useCompany();
-
-// watch(
-//   () => route,
-//   () => {
-//     if (route.query.error !== "1") return;
-//     setTimeout(() => {
-//       if (!currentCompany.value.companyName) return;
-//       ElMessageBox({
-//         title: "公司角色异常",
-//         message: h("p", null, [
-//           h("span", null, "公司 "),
-//           h("strong", null, currentCompany.value.companyName),
-//           h("span", null, " 角色异常或该公司禁用,请检查账号或者角色设置")
-//         ]),
-//         boxType: "confirm"
-//       });
-//     }, 500);
-//   },
-//   {
-//     deep: true,
-//     immediate: true
-//   }
-// );
 </script>
 
 <template>
   <div class="welcome">
-    <!-- <div class="welcome-title">欢迎登录,采销365结算</div> -->
-    <!-- <img :src="emptyGif" /> -->
+    <div class="w-[1100px] h-full mr-[10px]">
+      <!-- 消息中心 -->
+      <div class="w-full h-[180px] mb-2">
+        <MessageCenter />
+      </div>
+      
+      <div class="w-full h-[180px] border-1 mb-2"></div>
+      <div class="w-full h-[180px] border-1 mb-2"></div>
+    </div>
+
+    <div class="flex-1 h-full">
+      <div class="w-full h-[180px] border-1 mb-2"></div>
+      <div class="w-full h-[340px] border-1 mb-2"></div>
+    </div>
   </div>
 </template>
 
@@ -47,50 +29,11 @@ import emptyGif from "/@/assets/welcome.jpg?component";
 </style>
 
 <style lang="scss" scoped>
-.dashboard-container {
-  // background-color: #f0f4fd;
-  padding: 0 0 0 0;
-}
-.emptyGif {
-  display: block;
-  width: 100%;
-  height: 100%;
-  margin: 0 auto;
-  padding: 0 0 0 0;
-}
-
 .welcome {
-  // background-color: #e3e3e3;
-
-  background: url("./welcome.jpg") no-repeat !important;
-
-  // background: url("./background/start.png") no-repeat;
-  background-size:cover !important;
-
   min-height: calc(100vh - 48px);
   width: 100%;
   height: calc(100vh - 48px);
   display: flex;
   padding: 0 0 0 0;
-  // padding: 0 6% 0 0;
-  text-align: center;
-  // align-items: flex-start ;
-  // .welcome-title {
-  //   vertical-align: top;
-  //   padding: 0;
-  //   margin: 8% 0 0 18px;
-  //   color: #97a8be;
-  //   display: inline-block;
-  //   height: 130px;
-  //   line-height: 130px;
-  //   font-size: 50px;
-  // }
-  //center;
-  // img {
-  //   display: block;
-  //   flex: 1;
-  //   padding: 0 0 0 0;
-  //   margin: 0 0 0 0;
-  // }
 }
 </style>