刘恒 1 рік тому
батько
коміт
38f808e28b

BIN
src/assets/images/loginback.png


BIN
src/assets/images/loginback1.png


+ 185 - 84
src/components/LoginForm/index.vue

@@ -1,57 +1,61 @@
 <script setup lang="ts">
-import type { FormInstance, FormRules } from 'element-plus'
-import useUserStore from '@/store/modules/user'
-import { ref, useTemplateRef, onMounted } from 'vue'
+import type { FormInstance, FormRules } from "element-plus";
+import useUserStore from "@/store/modules/user";
+import { ref, useTemplateRef, onMounted,onUnmounted } from "vue";
 
 defineOptions({
-  name: 'LoginForm',
-})
+  name: "LoginForm",
+});
 
 const props = defineProps<{
-  userName?: string
-  passWord?: string
-  captcha?: string
-  system?: string
-  captchaId?: number
-}>()
+  userName?: string;
+  passWord?: string;
+  captcha?: string;
+  system?: string;
+  captchaId?: number;
+}>();
 
 const emits = defineEmits<{
-  onLogin: [userName: string]
-  onRegister: [userName: string]
-  onResetPassword: [userName: string]
-}>()
+  onLogin: [userName: string];
+  onRegister: [userName: string];
+  onResetPassword: [userName: string];
+}>();
 
-const userStore = useUserStore()
-const title = import.meta.env.VITE_APP_TITLE
-const baseurl = import.meta.env.VITE_APP_API_BASEURL
-const loading = ref(false)
-const remember = ref(false)
-const captchaSrc = ref("")//验证码图片
+const userStore = useUserStore();
+// const title = import.meta.env.VITE_APP_TITLE
+const baseurl = import.meta.env.VITE_APP_API_BASEURL;
+const loading = ref(false);
+const remember = ref(false);
+const captchaSrc = ref(""); //验证码图片
 // const system = ref([
 //   'PLATFORM',
 //   'JZG'
 // ])
 // 登录方式,default 账号密码登录,qrcode 扫码登录
-const type = ref('default')
-const formRef = useTemplateRef<FormInstance>('formRef')
+const type = ref("default");
+const formRef = useTemplateRef<FormInstance>("formRef");
 const form = ref({
-  userName: props.userName ?? localStorage.login_account ?? '',
-  passWord: '',
+  userName: props.userName ?? localStorage.login_account ?? "",
+  passWord: "",
   captcha: "",
   system: "PLATFORM",
   captchaId: 0,
-})
+  systemCode: "",
+});
 const rules = ref<FormRules>({
-  userName: [
-    { required: true, trigger: 'blur', message: '请输入用户名' },
-  ],
+  userName: [{ required: true, trigger: "blur", message: "请输入用户名" }],
+  systemCode: [{ required: true, trigger: "blur", message: "请输入租户编码" }],
   passWord: [
-    { required: true, trigger: 'blur', message: '请输入密码' },
-    { min: 6, max: 18, trigger: 'blur', message: '密码长度为6到18位' },
+    { required: true, trigger: "blur", message: "请输入密码" },
+    { min: 6, max: 18, trigger: "blur", message: "密码长度为6到18位" },
   ],
-})
+});
 onMounted(() => {
-  refreshCaptcha()
+  refreshCaptcha();
+  window.addEventListener('keydown', handleEnter)
+});
+onUnmounted(() => {
+  window.removeEventListener('keydown', handleEnter, false)
 })
 //获取验证码接口
 function refreshCaptcha() {
@@ -64,105 +68,202 @@ function refreshCaptcha() {
     randnum;
   form.value.captchaId = randnum;
 }
+function handleEnter (e:any) {
+  // console.log(e)
+  // console.log(e)
+  if (e.keyCode == 13 || e.keyCode == 108) {
+    //登录接口逻辑
+    handleLogin()
+  }
+}
 function handleLogin() {
+  // console.log(123)
   formRef.value?.validate((valid) => {
     if (valid) {
-      loading.value = true
-      userStore.login(form.value).then(() => {
-        if (remember) {
-          localStorage.setItem('login_account', form.value.userName)
-        }
-        else {
-          localStorage.removeItem('login_account')
-        }
-        emits('onLogin', form.value.userName)
-      }).finally(() => {
-        loading.value = false
-        refreshCaptcha();
-
-      })
+      loading.value = true;
+      userStore
+        .login(form.value)
+        .then(() => {
+          if (remember) {
+            localStorage.setItem("login_account", form.value.userName);
+          } else {
+            localStorage.removeItem("login_account");
+          }
+          emits("onLogin", form.value.userName);
+        })
+        .finally(() => {
+          loading.value = false;
+          refreshCaptcha();
+        });
     }
-  })
+  });
 }
 
-function testAccount(userName: string) {
-  form.value.userName = userName
-  form.value.passWord = '123456'
-  handleLogin()
-}
+// function testAccount(userName: string) {
+//   form.value.userName = userName
+//   form.value.passWord = '123456'
+//   handleLogin()
+// }
 </script>
+<style lang="scss" scoped>
+:deep(.el-form-item--large) {
+  margin-bottom: 30px;
+}
+
+:deep(.el-input__prefix) {
+  color: #3275ff;
+}
+
+.title {
+  position: relative;
+  margin-bottom: 56px;
+  font-size: 36px;
+  color: #333;
 
+  span {
+    position: relative;
+    z-index: 9999;
+    letter-spacing: 5px;
+  }
+
+  .tag {
+    position: absolute;
+    bottom: 0;
+    width: 76px;
+    height: 8px;
+    background: linear-gradient(90deg, #4fcaff 0%, #2b62ff 100%);
+  }
+}
+
+.loginCSS {
+  padding: 2px;
+  font-size: 20px;
+  background: linear-gradient(91deg, #4fcaff 0%, #2b62ff 100%);
+}
+</style>
 <template>
-  <ElForm ref="formRef" :model="form" :rules="rules" class="min-h-500px w-full flex-col-stretch-center p-12"
-    size="large">
-    <div class="mb-6">
+  <ElForm
+    ref="formRef"
+    :model="form"
+    :rules="rules"
+    class="min-h-500px w-full flex-col-stretch-center"
+    style="padding: 81px 75px"
+    size="large"
+  >
+    <!-- <div class="mb-6">
       <HTabList v-model="type" :options="[
         { label: '账号密码登录', value: 'default' },
         { label: '扫码登录', value: 'qrcode' },
       ]" />
-    </div>
+    </div> -->
     <template v-if="type === 'default'">
-      <h3 class="mb-8 text-xl color-[var(--el-text-color-primary)] font-bold">
+      <!-- <h3 class="mb-8 text-xl color-[var(--el-text-color-primary)] font-bold">
         欢迎使用 {{ title }} ! 👋🏻
-      </h3>
+      </h3> -->
+      <div class="title strong">
+        <span>登录</span>
+        <div class="tag"></div>
+      </div>
       <div>
+        <ElFormItem prop="systemCode">
+          <ElInput
+            v-model="form.systemCode"
+            placeholder="输入租户编码"
+            type="text"
+            tabindex="1"
+          >
+            <template #prefix>
+              <el-icon><Postcard /></el-icon>
+            </template>
+          </ElInput>
+        </ElFormItem>
         <ElFormItem prop="userName">
-          <ElInput v-model="form.userName" placeholder="用户名" type="text" tabindex="1">
+          <ElInput
+            v-model="form.userName"
+            placeholder="手机号或工号"
+            type="text"
+            tabindex="1"
+          >
             <template #prefix>
-              <SvgIcon name="i-ri:user-3-fill" />
+              <el-icon><User /></el-icon>
             </template>
           </ElInput>
         </ElFormItem>
         <ElFormItem prop="passWord">
-          <ElInput v-model="form.passWord" type="password" placeholder="密码" tabindex="2" show-password
-            @keyup.enter="handleLogin">
+          <ElInput
+            v-model="form.passWord"
+            type="password"
+            placeholder="登录密码"
+            tabindex="2"
+            show-password
+            @keyup.enter="handleLogin"
+          >
             <template #prefix>
-              <SvgIcon name="i-ri:lock-2-fill" />
+              <el-icon><Lock /></el-icon>
             </template>
           </ElInput>
         </ElFormItem>
 
-        <ElFormItem prop="captcha">
+        <ElFormItem prop="captcha" style="margin-bottom: 0">
           <ElCol :md="14" :sm="14" :xs="14">
-            <ElInput v-model="form.captcha" placeholder="验证码" type="text" tabindex="3">
+            <ElInput
+              v-model="form.captcha"
+              placeholder="验证码"
+              type="text"
+              tabindex="3"
+            >
               <template #prefix>
-                <SvgIcon name="i-ri:user-3-fill" />
+                <el-icon><CircleCheck /></el-icon>
               </template>
             </ElInput>
           </ElCol>
           <ElCol :md="10" :sm="10" :xs="10" flex>
-            <img style="width: 100%; height: 32px; margin-left: 20px;" class="pointer" :src="captchaSrc"
-              @click="refreshCaptcha" />
+            <img
+              style="width: 100%; height: 32px; margin-left: 20px"
+              class="pointer"
+              :src="captchaSrc"
+              @click="refreshCaptcha"
+            />
           </ElCol>
         </ElFormItem>
       </div>
-      <div class="mb-4 flex-center-between">
-        <ElCheckbox v-model="remember">
-          记住密码
-        </ElCheckbox>
-        <ElLink type="primary" :underline="false" @click="emits('onResetPassword', form.userName)">
-          忘记密码了?
+      <div class="mb-17 flex-center-between">
+        <ElCheckbox v-model="remember"> 记住密码 </ElCheckbox>
+        <ElLink
+          type="primary"
+          :underline="false"
+          @click="emits('onResetPassword', form.userName)"
+        >
+          忘记密码
         </ElLink>
       </div>
-      <ElButton :loading="loading" type="primary" size="large" style="width: 100%;" @click.prevent="handleLogin">
+      <ElButton
+        class="loginCSS"
+        :loading="loading"
+        type="primary"
+        @keydown.enter="handleEnter"
+        style="width: 100%"
+        @click.prevent="handleLogin"
+      >
         登录
       </ElButton>
-      <div class="mt-4 flex-center gap-2 text-sm color-[var(--el-text-color-secondary)]">
+      <!-- <div class="mt-4 flex-center gap-2 text-sm color-[var(--el-text-color-secondary)]">
         还没有帐号?
         <ElLink type="primary" :underline="false" @click="emits('onRegister', form.userName)">
           创建新帐号
         </ElLink>
-      </div>
+      </div> -->
     </template>
     <template v-else-if="type === 'qrcode'">
       <div class="flex-col-center">
-        <el-image src="https://s2.loli.net/2024/04/26/GsahtuIZ9XOg5jr.png" class="h-[250px] w-[250px]" />
-        <div class="mt-2 op-50">
-          请使用微信扫码登录
-        </div>
+        <el-image
+          src="https://s2.loli.net/2024/04/26/GsahtuIZ9XOg5jr.png"
+          class="h-[250px] w-[250px]"
+        />
+        <div class="mt-2 op-50">请使用微信扫码登录</div>
       </div>
     </template>
-    <div class="mt-4 text-center -mb-4">
+    <!-- <div class="mt-4 text-center -mb-4">
       <ElDivider>演示账号一键登录</ElDivider>
       <ElButton type="primary" size="small" plain @click="testAccount('admin')">
         admin
@@ -170,6 +271,6 @@ function testAccount(userName: string) {
       <ElButton size="small" plain @click="testAccount('test')">
         test
       </ElButton>
-    </div>
+    </div> -->
   </ElForm>
 </template>

+ 39 - 0
src/components/PaginationWrapper/index.vue

@@ -0,0 +1,39 @@
+<template>
+  <div class="pad-1">
+    <el-pagination :current-page="currentPage" :page-size="pageSize" :page-sizes="[20, 40, 60, 80]" :total="total"
+      :size="size" @size-change="handleSizeChange" @current-change="handlePageChange"
+      layout="total, sizes, prev, pager, next" :disabled="disabled" :background="background" />
+  </div>
+
+</template>
+
+<script setup lang="ts">
+import { ref, defineProps, defineEmits } from 'vue';
+import { ElPagination } from 'element-plus';
+import type { ComponentSize } from 'element-plus'
+interface Props {
+  pageNum: number;
+  pageSize: number;
+  total: number;
+
+}
+const background = ref(false)
+const disabled = ref(false)
+const size = ref<ComponentSize>('small')
+const props = defineProps<Props>();
+const emit = defineEmits(['pageChange','sizeChange']);
+
+const currentPage = ref(props.pageNum);
+const pageSize = ref(props.pageSize);
+const total = props.total;
+const handlePageChange = (newPage: number) => {
+  currentPage.value = newPage;
+  emit('pageChange', newPage);
+};
+const handleSizeChange = (val: number) => {
+  pageSize.value = val;
+  emit('sizeChange', val);
+
+};
+
+</script>

+ 6 - 2
src/main.ts

@@ -1,5 +1,4 @@
 import FloatingVue from 'floating-vue'
-
 import Message from 'vue-m-message'
 import App from './App.vue'
 
@@ -7,7 +6,7 @@ import router from './router'
 import pinia from './store'
 
 import ui from './ui-provider'
-
+import * as ElementPlusIconsVue from '@element-plus/icons-vue'
 import '@/utils/system.copyright'
 import 'floating-vue/dist/style.css'
 import 'vue-m-message/dist/style.css'
@@ -29,6 +28,11 @@ import 'virtual:uno.css'
 import '@/assets/styles/globals.css'
 
 const app = createApp(App)
+for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
+  app.component(key, component)
+}
+// 添加 Element Plus
+
 app.use(FloatingVue, {
   distance: 12,
 })

+ 1 - 0
src/store/modules/menu.ts

@@ -142,6 +142,7 @@ const useMenuStore = defineStore(
     function hasPermission(permissions: string[], menu: Menu.recordMainRaw | Menu.recordRaw) {
       let isAuth = false
       if (menu.meta?.auth) {
+        if(permissions)
         isAuth = permissions.some((auth) => {
           console.log(auth)
           if (typeof menu.meta?.auth === 'string') {

+ 1 - 0
src/types/components.d.ts

@@ -29,6 +29,7 @@ declare module 'vue' {
     NotAllowed: typeof import('./../components/NotAllowed/index.vue')['default']
     PageHeader: typeof import('./../components/PageHeader/index.vue')['default']
     PageMain: typeof import('./../components/PageMain/index.vue')['default']
+    PaginationWrapper: typeof import('./../components/PaginationWrapper/index.vue')['default']
     PcasCascader: typeof import('./../components/PcasCascader/index.vue')['default']
     RegisterForm: typeof import('./../components/RegisterForm/index.vue')['default']
     ResetPasswordForm: typeof import('./../components/ResetPasswordForm/index.vue')['default']

+ 148 - 134
src/views/login.vue

@@ -1,149 +1,163 @@
 <route lang="yaml">
-meta:
-  title: 登录
-  constant: true
-  layout: false
-</route>
-
-<script setup lang="ts">
-import { ref } from 'vue'
-import { useRoute, useRouter } from 'vue-router'
-import useUserStore from '@/store/modules/settings'
-defineOptions({
-  name: 'Login',
-})
-
-const route = useRoute()
-const router = useRouter()
-const settingsStore = useUserStore()
-
-const redirect = ref(route.query.redirect?.toString() ?? settingsStore.settings.home.fullPath)
-const account = ref<string>()
-// // 表单类型
-const formType = ref<'login' | 'register' | 'resetPassword'>('login')
-</script>
-
-<template>
-  <div class="bg-banner" />
-  <div class="login-box">
-    <div class="login-banner">
-      <img
-        src="@/assets/images/logo.png"
-        class="absolute left-4 top-4 h-30px rounded ring ring-stone-2 dark-ring-stone-8"
-      >
-      <img src="@/assets/images/login-banner.png" class="banner">
+  meta:
+    title: 登录
+    constant: true
+    layout: false
+  </route>
+  
+  <script setup lang="ts">
+  import { ref } from 'vue'
+  import { useRoute, useRouter } from 'vue-router'
+  import useUserStore from '@/store/modules/settings'
+  defineOptions({
+    name: 'Login',
+  })
+  
+  const route = useRoute()
+  const router = useRouter()
+  const settingsStore = useUserStore()
+  
+  const redirect = ref(route.query.redirect?.toString() ?? settingsStore.settings.home.fullPath)
+  const account = ref<string>()
+  // // 表单类型
+  const formType = ref<'login' | 'register' | 'resetPassword'>('login')
+  </script>
+  
+  <template>
+    <div class="bg-banner" />
+    <img class="bgback" src=".././assets/images/loginback1.png" alt="">
+  
+    <div class="login-box">
+      <!-- <div class="login-banner">
+        <img
+          src="@/assets/images/logo.png"
+          class="absolute left-4 top-4 h-30px rounded ring ring-stone-2 dark-ring-stone-8"
+        >
+        <img src="@/assets/images/login-banner.png" class="banner">
+      </div> -->
+  
+      <div class="login-form flex-col-center">
+        <Transition name="fade" mode="out-in">
+          <LoginForm
+            v-if="formType === 'login'" :account @on-login="router.push(redirect)"
+            @on-register="(account) => { formType = 'register'; account = account }"
+            @on-reset-password="(account) => { formType = 'resetPassword'; account = account }"
+          />
+          <RegisterForm
+            v-else-if="formType === 'register'" :account
+            @on-register="(account) => { formType = 'login'; account = account }" @on-login="formType = 'login'"
+          />
+          <ResetPasswordForm
+            v-else-if="formType === 'resetPassword'" :account
+            @on-reset-password="(account) => { formType = 'login'; account = account }" @on-login="formType = 'login'"
+          />
+        </Transition>
+      </div>
     </div>
-    <div class="login-form flex-col-center">
-      <Transition name="fade" mode="out-in">
-        <LoginForm
-          v-if="formType === 'login'" :account @on-login="router.push(redirect)"
-          @on-register="(account) => { formType = 'register'; account = account }"
-          @on-reset-password="(account) => { formType = 'resetPassword'; account = account }"
-        />
-        <RegisterForm
-          v-else-if="formType === 'register'" :account
-          @on-register="(account) => { formType = 'login'; account = account }" @on-login="formType = 'login'"
-        />
-        <ResetPasswordForm
-          v-else-if="formType === 'resetPassword'" :account
-          @on-reset-password="(account) => { formType = 'login'; account = account }" @on-login="formType = 'login'"
-        />
-      </Transition>
-    </div>
-  </div>
-</template>
-
-<style scoped>
-.bg-banner {
-  position: fixed;
-  z-index: 0;
-  width: 100%;
-  height: 100%;
-  background: radial-gradient(circle at center, var(--g-container-bg), var(--g-bg));
-}
-
-[data-mode="mobile"] {
-  .login-box {
-    position: relative;
-    flex-direction: column;
-    justify-content: start;
+  </template>
+  
+  <style lang="scss" scoped>
+  .bg-banner {
+    position: fixed;
+    z-index: 0;
     width: 100%;
-
-    .login-banner {
+    height: 100%;
+    background: radial-gradient(circle at center, var(--g-container-bg), var(--g-bg));
+    background-image: url(".././assets/images/loginback.png");
+    background-size: cover;
+  }
+  
+  .bgback {
+    position: fixed;
+    top: 58%;
+    left: 35%;
+    z-index: 0;
+    transform: translateX(-50%) translateY(-50%);
+  }
+  
+  [data-mode="mobile"] {
+    .login-box {
+      position: relative;
+      flex-direction: column;
+      justify-content: start;
       width: 100%;
-      padding: 20px 0;
-
+  
+      .login-banner {
+        width: 100%;
+        padding: 20px 0;
+  
+        .banner {
+          position: relative;
+          top: inherit;
+          right: inherit;
+          display: inherit;
+          width: 100%;
+          max-width: 375px;
+          margin: 0 auto;
+          transform: translateY(0);
+        }
+      }
+  
+      .login-form {
+        width: 100%;
+      }
+    }
+  
+    .copyright {
+      position: relative;
+    }
+  }
+  
+  .login-box {
+    position: absolute;
+    display: flex;
+    overflow: hidden;
+    background-color: var(--g-container-bg);
+  
+    [data-mode="pc"] & {
+      top: 50%;
+      left: 70%;
+      border-radius: 10px;
+      box-shadow: var(--el-box-shadow);
+      transform: translateX(-50%) translateY(-50%);
+    }
+  
+    .login-banner {
+      position: relative;
+      width: 450px;
+      overflow: hidden;
+      background-color: var(--g-bg);
+  
       .banner {
-        position: relative;
-        top: inherit;
-        right: inherit;
-        display: inherit;
+        position: absolute;
+        top: 50%;
         width: 100%;
-        max-width: 375px;
-        margin: 0 auto;
-        transform: translateY(0);
+        transform: translateY(-50%);
       }
     }
-
+  
     .login-form {
-      width: 100%;
+      width: 500px;
+      transition: height 0.15s ease;
     }
   }
-
+  
   .copyright {
-    position: relative;
-  }
-}
-
-.login-box {
-  position: absolute;
-  display: flex;
-  overflow: hidden;
-  background-color: var(--g-container-bg);
-
-  [data-mode="pc"] & {
-    top: 50%;
-    left: 50%;
-    border-radius: 10px;
-    box-shadow: var(--el-box-shadow);
-    transform: translateX(-50%) translateY(-50%);
+    position: absolute;
+    bottom: 0;
+    width: 100%;
+    padding: 20px;
+    margin: 0;
   }
-
-  .login-banner {
-    position: relative;
-    width: 450px;
-    overflow: hidden;
-    background-color: var(--g-bg);
-
-    .banner {
-      position: absolute;
-      top: 50%;
-      width: 100%;
-      transform: translateY(-50%);
-    }
+  
+  .fade-enter-active,
+  .fade-leave-active {
+    transition: opacity 0.15s ease;
   }
-
-  .login-form {
-    width: 500px;
-    transition: height 0.15s ease;
+  
+  .fade-enter-from,
+  .fade-leave-to {
+    opacity: 0;
   }
-}
-
-.copyright {
-  position: absolute;
-  bottom: 0;
-  width: 100%;
-  padding: 20px;
-  margin: 0;
-}
-
-.fade-enter-active,
-.fade-leave-active {
-  transition: opacity 0.15s ease;
-}
-
-.fade-enter-from,
-.fade-leave-to {
-  opacity: 0;
-}
-</style>
+  </style>
+  

+ 228 - 66
src/views/personnel/memberManagement.vue

@@ -1,48 +1,80 @@
 <template>
   <div class="member">
-    <el-form label-position="left" label-width="auto">
-      <el-row :gutter="16">
-        <el-col :span="6">
-          <el-form-item label="成员信息">
-            <el-input
-              v-model="formAccessibility.firstName"
-              placeholder="输入姓名,手机号,工号查询"
-            />
-          </el-form-item>
-        </el-col>
-        <el-col :span="6">
-          <el-form-item label="状态">
-            <el-select
-              v-model="value"
-              placeholder="成员状态"
-              style="width: 240px"
-            >
-              <el-option
-                v-for="item in options"
-                :key="item.value"
-                :label="item.label"
-                :value="item.value"
+    <div class="member-tree">
+      <el-input
+        v-model="filterText"
+        style="width: 240px"
+        placeholder="姓名,手机号,工号查询"
+        :prefix-icon="Search"
+      />
+
+      <el-tree
+        ref="treeRef"
+        style="max-width: 600px"
+        class="filter-tree"
+        :data="data"
+        :props="defaultProps"
+        default-expand-all
+        :filter-node-method="filterNode"
+        :expand-on-click-node="false"
+      >
+        <template #default="{ node, data }">
+          <span class="custom-tree-node">
+            <span>{{ node.label }}</span>
+            <span>
+              <el-dropdown>
+                <span class="el-dropdown-link">
+                  <el-icon @click="append(data)"><More /></el-icon>
+                </span>
+                <template #dropdown>
+                  <el-dropdown-menu>
+                    <el-dropdown-item>添加子机构</el-dropdown-item>
+                    <el-dropdown-item>编辑</el-dropdown-item>
+                    <el-dropdown-item>删除</el-dropdown-item>
+                  </el-dropdown-menu>
+                </template>
+              </el-dropdown>
+            </span>
+          </span>
+        </template>
+      </el-tree>
+    </div>
+    <div class="member-main">
+      <!-- <el-form label-position="left" label-width="auto">
+        <el-row :gutter="16">
+          <el-col :span="6">
+            <el-form-item label="成员信息">
+              <el-input
+                v-model="formAccessibility.firstName"
+                placeholder="输入姓名,手机号,工号查询"
               />
-            </el-select>
-          </el-form-item>
-        </el-col>
-        <el-col :span="4">
-          <el-form-item label="">
-            <el-button type="primary">查询</el-button>
-            <el-button type="primary" plain @click="reset">重置</el-button>
-          </el-form-item>
-        </el-col>
-        <!-- <el-col :span="24">
-          <el-form-item label="">
-            <el-button type="primary" @click="add(ruleFormRef)">
-              <el-icon><Plus /></el-icon>添加成员</el-button
-            >
-         
-          </el-form-item>
-        </el-col> -->
-      </el-row>
-    </el-form>
-   
+            </el-form-item>
+          </el-col>
+          <el-col :span="6">
+            <el-form-item label="状态">
+              <el-select
+                v-model="value"
+                placeholder="成员状态"
+                style="width: 240px"
+              >
+                <el-option
+                  v-for="item in options"
+                  :key="item.value"
+                  :label="item.label"
+                  :value="item.value"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="4">
+            <el-form-item label="">
+              <el-button type="primary">查询</el-button>
+              <el-button type="primary" plain @click="reset">重置</el-button>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form> -->
+
       <Table
         :tableData="tableData"
         :columns="columns"
@@ -52,30 +84,39 @@
         @getList="getList"
       >
         <template v-slot:table-title-btn>
-          <el-button type="primary" @click="add(ruleFormRef)">
+          <div>
+            <p>状态</p>
+            <p>展示全部成员</p>
+          </div>
+          <div>
+            <el-button type="primary" @click="add(ruleFormRef)">
               <el-icon><Plus /></el-icon>添加成员</el-button
             >
-          <el-dropdown placement="bottom-start">
-            <el-button> 批量操作<el-icon class="el-icon--right">
-                <arrow-down />
-              </el-icon>
-            </el-button>
-            <template #dropdown>
-              <el-dropdown-menu>
-                <el-dropdown-item>批量删除</el-dropdown-item>
-                <el-dropdown-item>批量禁用</el-dropdown-item>
-                <el-dropdown-item>批量启用</el-dropdown-item>
-              </el-dropdown-menu>
-            </template>
-          </el-dropdown>
+            <el-dropdown placement="bottom-start">
+              <el-button>
+                批量操作<el-icon class="el-icon--right">
+                  <arrow-down />
+                </el-icon>
+              </el-button>
+              <template #dropdown>
+                <el-dropdown-menu>
+                  <el-dropdown-item>批量删除</el-dropdown-item>
+                  <el-dropdown-item>批量禁用</el-dropdown-item>
+                  <el-dropdown-item>批量启用</el-dropdown-item>
+                </el-dropdown-menu>
+              </template>
+            </el-dropdown>
+            <el-button type="primary" @click="add(ruleFormRef)">
+              设置负责人</el-button
+            >
+          </div>
         </template>
         <template v-slot:operation="scope">
-          <el-button type="primary" link @click="editor(scope)"> 编辑 </el-button>
+          <el-button type="primary" link @click="editor(scope)">
+            编辑
+          </el-button>
           <el-dropdown placement="bottom-start">
-            <span class="el-dropdown-link">
-              更 多
-            
-            </span>
+            <span class="el-dropdown-link"> 更 多 </span>
             <template #dropdown>
               <el-dropdown-menu>
                 <el-dropdown-item>删除</el-dropdown-item>
@@ -89,7 +130,8 @@
           {{ scope.slotData.label }}
         </template>
       </Table>
-   
+    </div>
+
     <el-dialog v-model="dialogVisible" title="基本信息" width="800" draggable>
       <el-form
         label-position="top"
@@ -157,11 +199,85 @@
 </template>
 
 <script setup lang="ts">
-import { ref, reactive } from "vue";
+import { ref, reactive, watch } from "vue";
 import type { ComponentSize, FormInstance, FormRules } from "element-plus";
-import { Plus,ArrowDown } from "@element-plus/icons-vue";
+import { Plus, Search } from "@element-plus/icons-vue";
 
+import type Node from "element-plus/es/components/tree/src/model/node";
 // import universalTable from "../"
+import { ElTree } from "element-plus";
+
+interface Tree {
+  [key: string]: any;
+}
+
+const filterText = ref("");
+const treeRef = ref<InstanceType<typeof ElTree>>();
+
+const defaultProps = {
+  children: "children",
+  label: "label",
+};
+
+watch(filterText, (val) => {
+  treeRef.value!.filter(val);
+});
+
+const filterNode = (value: string, data: Tree) => {
+  if (!value) return true;
+  return data.label.includes(value);
+};
+const data: Tree[] = [
+  {
+    id: 1,
+    label: "Level one 1",
+    children: [
+      {
+        id: 4,
+        label: "Level two 1-1",
+        children: [
+          {
+            id: 9,
+            label: "Level three 1-1-1",
+          },
+          {
+            id: 10,
+            label: "Level three 1-1-2",
+          },
+        ],
+      },
+    ],
+  },
+  {
+    id: 2,
+    label: "Level one 2",
+    children: [
+      {
+        id: 5,
+        label: "Level two 2-1",
+      },
+      {
+        id: 6,
+        label: "Level two 2-2",
+      },
+    ],
+  },
+  {
+    id: 3,
+    label: "Level one 3",
+    children: [
+      {
+        id: 7,
+        label: "Level two 3-1",
+      },
+      {
+        id: 8,
+        label: "Level two 3-2",
+      },
+    ],
+  },
+];
+
 const formAccessibility = reactive({
   fullName: "",
   firstName: "",
@@ -258,6 +374,7 @@ const columns = [
   { prop: "size", label: "工号" },
   { prop: "role", label: "角色" },
   { prop: "status", label: "状态" },
+  // { prop: "operation", label: "操作",fixed:true },
 
   // {
   //     prop: "operation", label: "operation", width: "280",
@@ -295,19 +412,56 @@ const operationMany = (item: any) => {
   // pageInfo.pageSize=item.pageSize
 };
 
+const append = (data: Tree) => {
+  console.log(data);
+  // const newChild = { id: id++, label: 'testtest', children: [] }
+  if (!data.children) {
+    data.children = [];
+  }
+  // data.children.push(newChild)
+  // dataSource.value = [...dataSource.value]
+};
 
+const remove = (node: Node, data: Tree) => {
+  const parent = node.parent;
+  const children: Tree[] = parent.data.children || parent.data;
+  const index = children.findIndex((d) => d.id === data.id);
+  children.splice(index, 1);
+  // dataSource.value = [...dataSource.value]
+};
 const reset = (item: any) => {
   // ElMessage({})
 };
-
 </script>
 <style lang="scss" scoped>
+:deep(.table-title-btn){
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  >div{
+    display: flex;
+  }
+}
 .member {
   background: #fff;
   width: 100%;
   // height: 100%;
-  padding: 20px;
+  // padding: 20px;
   box-sizing: border-box;
+  display: flex;
+  .member-tree {
+    flex: none;
+    width: 20%;
+    padding: 20px;
+    box-sizing: border-box;
+    border-right: 1px solid #ccc;
+  }
+  .member-main {
+    flex: none;
+    width: 80%;
+    padding: 20px;
+    box-sizing: border-box;
+  }
 }
 :deep(.el-dropdown-link) {
   cursor: pointer;
@@ -316,4 +470,12 @@ const reset = (item: any) => {
   align-items: center;
   margin-left: 15px;
 }
+.custom-tree-node {
+  flex: 1;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  font-size: 14px;
+  padding-right: 8px;
+}
 </style>

+ 73 - 32
themes/index.ts

@@ -1,44 +1,85 @@
 import { hex2rgba } from '@unocss/preset-mini/utils'
-
+//默认主题
+// export const lightTheme = {
+//   'color-scheme': 'light',
+//   // 内置 UI
+//   '--ui-primary': hex2rgba('#0f0f0f')!.join(' '),
+//   '--ui-text': hex2rgba('#fcfcfc')!.join(' '),
+//   // 主体
+//   '--g-bg': '#f2f2f2',
+//   '--g-container-bg': '#fff',
+//   '--g-border-color': '#f2f2f2',
+//   // 头部
+//   '--g-header-bg': '#fff',
+//   '--g-header-color': '#0f0f0f',
+//   '--g-header-menu-color': '#0f0f0f',
+//   '--g-header-menu-hover-bg': '#dde1e3',
+//   '--g-header-menu-hover-color': '#0f0f0f',
+//   '--g-header-menu-active-bg': '#334067',
+//   '--g-header-menu-active-color': '#fff',
+//   // 主导航
+//   '--g-main-sidebar-bg': '#222b45',
+//   '--g-main-sidebar-menu-color': '#0f0f0f',
+//   '--g-main-sidebar-menu-hover-bg': '#dde1e3',
+//   '--g-main-sidebar-menu-hover-color': '#0f0f0f',
+//   '--g-main-sidebar-menu-active-bg': '#334067',
+//   '--g-main-sidebar-menu-active-color': '#fff',
+//   // 次导航
+//   '--g-sub-sidebar-bg': '#fff',
+//   '--g-sub-sidebar-logo-bg': '#0f0f0f',
+//   '--g-sub-sidebar-logo-color': '#fff',
+//   '--g-sub-sidebar-menu-color': '#0f0f0f',
+//   '--g-sub-sidebar-menu-hover-bg': '#dde1e3',
+//   '--g-sub-sidebar-menu-hover-color': '#0f0f0f',
+//   '--g-sub-sidebar-menu-active-bg': '#409eff',
+//   '--g-sub-sidebar-menu-active-color': '#fff',
+//   // 标签栏
+//   '--g-tabbar-dividers-bg': '#a3a3a3',
+//   '--g-tabbar-tab-color': '#a3a3a3',
+//   '--g-tabbar-tab-hover-bg': '#e5e5e5',
+//   '--g-tabbar-tab-hover-color': '#0f0f0f',
+//   '--g-tabbar-tab-active-color': '#0f0f0f',
+// }
+//自定义主题
 export const lightTheme = {
   'color-scheme': 'light',
   // 内置 UI
-  '--ui-primary': hex2rgba('#0f0f0f')!.join(' '),
-  '--ui-text': hex2rgba('#fcfcfc')!.join(' '),
+  '--ui-primary': hex2rgba('#0376F9')!.join(' '),
+  '--ui-text': hex2rgba('#333333')!.join(' '),
   // 主体
-  '--g-bg': '#f2f2f2',
-  '--g-container-bg': '#fff',
-  '--g-border-color': '#f2f2f2',
+  '--g-bg': '#F5F8FF',
+  '--g-container-bg': '#FFFFFF',
+  '--g-border-color': '#E0E0E0',
   // 头部
-  '--g-header-bg': '#fff',
-  '--g-header-color': '#0f0f0f',
-  '--g-header-menu-color': '#0f0f0f',
-  '--g-header-menu-hover-bg': '#dde1e3',
-  '--g-header-menu-hover-color': '#0f0f0f',
-  '--g-header-menu-active-bg': '#334067',
-  '--g-header-menu-active-color': '#fff',
+  '--g-header-bg': '#0376F9',
+  '--g-header-color': '#ffffff',
+  '--g-header-menu-color': '#ffffff',
+  '--g-header-menu-hover-bg': '#E6F0FF',
+  '--g-header-menu-hover-color': '#333333',
+  '--g-header-menu-active-bg': '#ffffff',
+  '--g-header-menu-active-color': '#0376F9',
   // 主导航
-  '--g-main-sidebar-bg': '#222b45',
-  '--g-main-sidebar-menu-color': '#0f0f0f',
-  '--g-main-sidebar-menu-hover-bg': '#dde1e3',
-  '--g-main-sidebar-menu-hover-color': '#0f0f0f',
-  '--g-main-sidebar-menu-active-bg': '#334067',
-  '--g-main-sidebar-menu-active-color': '#fff',
+  '--g-main-sidebar-bg': '#0376F9',
+  '--g-main-sidebar-menu-color': '#FFFFFF',
+  '--g-main-sidebar-menu-hover-bg': '#0258C7',
+  '--g-main-sidebar-menu-hover-color': '#FFFFFF',
+  '--g-main-sidebar-menu-active-bg': '#FFFFFF',
+  '--g-main-sidebar-menu-active-color': '#0376F9',
   // 次导航
-  '--g-sub-sidebar-bg': '#fff',
-  '--g-sub-sidebar-logo-bg': '#0f0f0f',
-  '--g-sub-sidebar-logo-color': '#fff',
-  '--g-sub-sidebar-menu-color': '#0f0f0f',
-  '--g-sub-sidebar-menu-hover-bg': '#dde1e3',
-  '--g-sub-sidebar-menu-hover-color': '#0f0f0f',
-  '--g-sub-sidebar-menu-active-bg': '#409eff',
-  '--g-sub-sidebar-menu-active-color': '#fff',
+  '--g-sub-sidebar-bg': '#262930',
+  '--g-sub-sidebar-logo-bg': '#0376F9',
+  '--g-sub-sidebar-logo-color': '#FFFFFF',
+  '--g-sub-sidebar-menu-color': 'rgba(255,255,255,0.65)',
+  '--g-sub-sidebar-menu-hover-bg': '#E6F0FF',
+  '--g-sub-sidebar-menu-hover-color': '#0376F9',
+  '--g-sub-sidebar-menu-active-bg': '#0376F9',
+  '--g-sub-sidebar-menu-active-color': '#FFFFFF',
   // 标签栏
-  '--g-tabbar-dividers-bg': '#a3a3a3',
-  '--g-tabbar-tab-color': '#a3a3a3',
-  '--g-tabbar-tab-hover-bg': '#e5e5e5',
-  '--g-tabbar-tab-hover-color': '#0f0f0f',
-  '--g-tabbar-tab-active-color': '#0f0f0f',
+  '--g-tabbar-dividers-bg': '#E0E0E0',
+  '--g-tabbar-tab-color': '#666666',
+  '--g-tabbar-tab-hover-bg': '#E6F0FF',
+  '--g-tabbar-tab-hover-color': '#0376F9',
+  '--g-tabbar-tab-active-color': '#0376F9',
 }
 
 export const darkTheme = {