@dongkboy 1 éve
szülő
commit
ffd1fa6a38

+ 3 - 2
.env.development

@@ -1,9 +1,10 @@
 # 应用配置面板
 VITE_APP_SETTING = true
 # 页面标题
-VITE_APP_TITLE = 掌柜科技-dev
+VITE_APP_TITLE = 掌柜运营平台
 # 接口请求地址,会设置到 axios 的 baseURL 参数上
-VITE_APP_API_BASEURL = https://test.baoxianzhanggui.com/web-api/
+# VITE_APP_API_BASEURL = https://test.baoxianzhanggui.com/web-api/ #默认地址
+VITE_APP_API_BASEURL = http://192.168.5.48:8081/  #田智
 
 # 调试工具,可设置 eruda 或 vconsole,如果不需要开启则留空
 VITE_APP_DEBUG_TOOL =

+ 7 - 7
src/api/index.ts

@@ -21,7 +21,7 @@ axiosInstance.interceptors.request.use(
     // 设置请求头
     if (request.headers) {
       if (userStore.isLogin) {
-        request.headers.Token = userStore.token
+        request.headers.Authorization = userStore.token
       }
     }
     // 是否将 POST 请求参数进行字符串化处理
@@ -42,13 +42,13 @@ axiosInstance.interceptors.response.use(
      * 规则是当 status 为 1 时表示请求成功,为 0 时表示接口需要登录或者登录状态失效,需要重新登录
      * 请求出错时 error 会返回错误信息
      */
-    if (response.data.code === 200) {
-      if (response.data.error !== '') {
+    if (response.data.code === 500) {
+      if (response.data.msg !== '') {
         // 错误提示
-        Message.error(response.data.error, {
+        Message.error(response.data.msg, {
           zIndex: 2000,
         })
-        return Promise.reject(response.data)
+        return Promise.resolve(response.data)
       }
     }
     else {
@@ -58,9 +58,9 @@ axiosInstance.interceptors.response.use(
           type: 'error',
           duration: 2000,
         })
-        useUserStore().logout()
+        // useUserStore().logout()
       }
-      useUserStore().logout()
+      // useUserStore().logout()
     }
     return Promise.resolve(response.data)
   },

+ 7 - 8
src/api/modules/user.ts

@@ -1,7 +1,10 @@
 import { ApiInstance } from '../type'
 interface LoginData {
-  account: string
-  password: string
+  userName: string
+  passWord: string
+  captcha: string
+  system: string
+  captchaId: number
 }
 interface PasswordEditData {
   password: string
@@ -10,15 +13,11 @@ interface PasswordEditData {
 
 const userApi = (axiosInstance: ApiInstance) => ({
   // 登录
-  login: (data: LoginData) => axiosInstance.post('user/login', data, {
-    baseURL: '/mock/',
-  }),
-  //
-  ceshi: () => axiosInstance.get('user/ceshi', {
+  login: (data: LoginData) => axiosInstance.post('auth/login', data, {
+
   }),
   // 获取权限
   permission: () => axiosInstance.get('user/permission', {
-    baseURL: '/mock/',
   }),
 
   // 修改密码

+ 80 - 0
src/assets/styles/globals.css

@@ -151,3 +151,83 @@ textarea {
 .transition-all {
   border-radius: 8px;
 }
+
+.height100 {
+  height: 100%;
+}
+
+.u-f-column {
+  flex-direction: column;
+}
+
+.flex {
+  display: flex;
+}
+
+.f-wrap {
+  flex-wrap: wrap;
+}
+
+.j-s {
+  justify-content: space-between;
+}
+
+.j-c {
+  justify-content: center;
+}
+
+.j-start {
+  justify-content: flex-start;
+}
+
+.j-end {
+  justify-content: flex-end;
+}
+
+.a-c {
+  align-items: center;
+}
+
+.a-start {
+  align-items: flex-start;
+}
+
+.a-end {
+  align-items: flex-end;
+}
+
+.f-c {
+  flex-direction: column;
+}
+
+.mrgin-1 {
+  margin: 10px;
+}
+
+.mrgin-2 {
+  margin: 20px;
+}
+
+.m-top-5 {
+  margin-top: 5px;
+}
+
+.m-top-10 {
+  margin-top: 10px;
+}
+
+.m-btn-10 {
+  margin-bottom: 10px;
+}
+
+.m-btn-15 {
+  margin-bottom: 15px;
+}
+
+.vh100 {
+  min-height: calc(100vh - 200px);
+}
+
+.strong {
+  font-weight: bold;
+}

+ 74 - 33
src/components/LoginForm/index.vue

@@ -1,105 +1,146 @@
 <script setup lang="ts">
 import type { FormInstance, FormRules } from 'element-plus'
 import useUserStore from '@/store/modules/user'
-import { ref, useTemplateRef } from 'vue'
+import { ref, useTemplateRef, onMounted } from 'vue'
 
 defineOptions({
   name: 'LoginForm',
 })
 
 const props = defineProps<{
-  account?: string
+  userName?: string
+  passWord?: string
+  captcha?: string
+  system?: string
+  captchaId?: number
 }>()
 
 const emits = defineEmits<{
-  onLogin: [account: string]
-  onRegister: [account: string]
-  onResetPassword: [account: 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 system = ref([
+//   'PLATFORM',
+//   'JZG'
+// ])
 // 登录方式,default 账号密码登录,qrcode 扫码登录
 const type = ref('default')
 const formRef = useTemplateRef<FormInstance>('formRef')
 const form = ref({
-  account: props.account ?? localStorage.login_account ?? '',
-  password: '',
-  remember: !!localStorage.login_account,
+  userName: props.userName ?? localStorage.login_account ?? '',
+  passWord: '',
+  captcha: "",
+  system: "PLATFORM",
+  captchaId: 0,
 })
 const rules = ref<FormRules>({
-  account: [
+  userName: [
     { required: true, trigger: 'blur', message: '请输入用户名' },
   ],
-  password: [
+  passWord: [
     { required: true, trigger: 'blur', message: '请输入密码' },
     { min: 6, max: 18, trigger: 'blur', message: '密码长度为6到18位' },
   ],
 })
+onMounted(() => {
+  refreshCaptcha()
+})
+//获取验证码接口
+function refreshCaptcha() {
+  let randnum = Math.floor(Math.random() * (1000000 - 1 + 1)) + 1;
+  captchaSrc.value =
+    baseurl +
+    "auth/captchaById?t=" +
+    new Date().getTime() +
+    "&captchaId=" +
+    randnum;
+  form.value.captchaId = randnum;
+}
 function handleLogin() {
   formRef.value?.validate((valid) => {
     if (valid) {
       loading.value = true
       userStore.login(form.value).then(() => {
-        if (form.value.remember) {
-          localStorage.setItem('login_account', form.value.account)
+        if (remember) {
+          localStorage.setItem('login_account', form.value.userName)
         }
         else {
           localStorage.removeItem('login_account')
         }
-        emits('onLogin', form.value.account)
+        emits('onLogin', form.value.userName)
       }).finally(() => {
         loading.value = false
+        refreshCaptcha();
+
       })
     }
   })
 }
 
-function testAccount(account: string) {
-  form.value.account = account
-  form.value.password = '123456'
+function testAccount(userName: string) {
+  form.value.userName = userName
+  form.value.passWord = '123456'
   handleLogin()
 }
 </script>
 
 <template>
-  <ElForm ref="formRef" :model="form" :rules="rules" class="min-h-500px w-full flex-col-stretch-center p-12">
+  <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">
-      <HTabList
-        v-model="type" :options="[
-          { label: '账号密码登录', value: 'default' },
-          { label: '扫码登录', value: 'qrcode' },
-        ]"
-      />
+      <HTabList v-model="type" :options="[
+        { label: '账号密码登录', value: 'default' },
+        { label: '扫码登录', value: 'qrcode' },
+      ]" />
     </div>
     <template v-if="type === 'default'">
       <h3 class="mb-8 text-xl color-[var(--el-text-color-primary)] font-bold">
         欢迎使用 {{ title }} ! 👋🏻
       </h3>
       <div>
-        <ElFormItem prop="account">
-          <ElInput v-model="form.account" size="large" placeholder="用户名" type="text" tabindex="1">
+        <ElFormItem prop="userName">
+          <ElInput v-model="form.userName" placeholder="用户名" type="text" tabindex="1">
             <template #prefix>
               <SvgIcon name="i-ri:user-3-fill" />
             </template>
           </ElInput>
         </ElFormItem>
-        <ElFormItem prop="password">
-          <ElInput v-model="form.password" type="password" size="large" placeholder="密码" tabindex="2" show-password @keyup.enter="handleLogin">
+        <ElFormItem prop="passWord">
+          <ElInput v-model="form.passWord" type="password" placeholder="密码" tabindex="2" show-password
+            @keyup.enter="handleLogin">
             <template #prefix>
               <SvgIcon name="i-ri:lock-2-fill" />
             </template>
           </ElInput>
         </ElFormItem>
+
+        <ElFormItem prop="captcha">
+          <ElCol :md="14" :sm="14" :xs="14">
+            <ElInput v-model="form.captcha" placeholder="验证码" type="text" tabindex="3">
+              <template #prefix>
+                <SvgIcon name="i-ri:user-3-fill" />
+              </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" />
+          </ElCol>
+        </ElFormItem>
       </div>
       <div class="mb-4 flex-center-between">
-        <ElCheckbox v-model="form.remember">
-          记住我
+        <ElCheckbox v-model="remember">
+          记住密码
         </ElCheckbox>
-        <ElLink type="primary" :underline="false" @click="emits('onResetPassword', form.account)">
+        <ElLink type="primary" :underline="false" @click="emits('onResetPassword', form.userName)">
           忘记密码了?
         </ElLink>
       </div>
@@ -108,7 +149,7 @@ function testAccount(account: string) {
       </ElButton>
       <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.account)">
+        <ElLink type="primary" :underline="false" @click="emits('onRegister', form.userName)">
           创建新帐号
         </ElLink>
       </div>

+ 9 - 9
src/components/ResetPasswordForm/index.vue

@@ -7,24 +7,24 @@ defineOptions({
 })
 
 const props = defineProps<{
-  account?: string
+  userName?: string
 }>()
 
 const emits = defineEmits<{
-  onLogin: [account: string]
-  onResetPassword: [account: string]
+  onLogin: [userName: string]
+  onResetPassword: [userName: string]
 }>()
 
 const loading = ref(false)
 
 const formRef = useTemplateRef<FormInstance>('formRef')
 const form = ref({
-  account: props.account ?? localStorage.login_account ?? '',
+  userName: props.userName ?? localStorage.login_account ?? '',
   captcha: '',
   newPassword: '',
 })
 const rules = ref<FormRules>({
-  account: [
+  userName: [
     { required: true, trigger: 'blur', message: '请输入用户名' },
   ],
   captcha: [
@@ -43,7 +43,7 @@ function handleReset() {
   formRef.value?.validate((valid) => {
     if (valid) {
       // 这里编写业务代码
-      emits('onResetPassword', form.value.account)
+      emits('onResetPassword', form.value.userName)
     }
   })
 }
@@ -55,8 +55,8 @@ function handleReset() {
       忘记密码了? 🔒
     </h3>
     <div>
-      <ElFormItem prop="account">
-        <ElInput v-model="form.account" size="large" placeholder="用户名" type="text" tabindex="1">
+      <ElFormItem prop="userName">
+        <ElInput v-model="form.userName" size="large" placeholder="用户名" type="text" tabindex="1">
           <template #prefix>
             <SvgIcon name="i-ri:user-3-fill" />
           </template>
@@ -84,7 +84,7 @@ function handleReset() {
       确认
     </ElButton>
     <div class="mt-4 flex-center gap-2 text-sm color-[var(--el-text-color-secondary)]">
-      <ElLink type="primary" :underline="false" @click="emits('onLogin', form.account)">
+      <ElLink type="primary" :underline="false" @click="emits('onLogin', form.userName)">
         去登录
       </ElLink>
     </div>

+ 19 - 0
src/router/modules/basicSettings.ts

@@ -0,0 +1,19 @@
+import type { RouteRecordRaw } from 'vue-router'
+
+const Layout = () => import('@/layouts/index.vue')
+
+const routes: RouteRecordRaw = {
+  path: '/basicSettings/platformUser',
+  component: Layout,
+  redirect: '/basicSettings/platformUser/accountManagement',
+  name: 'BasicSettingsplatformUser',
+  meta: {
+    title: '平台用户',
+
+  },
+  children: [
+
+  ],
+}
+
+export default routes

+ 0 - 1
src/router/modules/multilevel.menu.example.ts

@@ -25,7 +25,6 @@ const routes: RouteRecordRaw = {
       component: () => import('@/views/example/ceshi.vue'),
       meta: {
         title: '权限测试',
-        auth: ['news.browse', 'permission.create'],
       },
     },
   ],

+ 27 - 0
src/router/modules/organization.ts

@@ -0,0 +1,27 @@
+import type { RouteRecordRaw } from 'vue-router'
+
+const Layout = () => import('@/layouts/index.vue')
+
+const routes: RouteRecordRaw = {
+  path: '/organizationManagement',
+  component: Layout,
+  redirect: '/organizationManagement/organization',
+  name: 'OrganizationManagement',
+  meta: {
+    title: '机构管理',
+
+  },
+  children: [
+    {
+      path: 'organization',
+      name: 'Organization',
+      component: () => import('@/views/organizationManagement/organization.vue'),
+      meta: {
+        title: '机构管理',
+      },
+    },
+
+  ],
+}
+
+export default routes

+ 33 - 0
src/router/modules/personnel.ts

@@ -0,0 +1,33 @@
+import type { RouteRecordRaw } from 'vue-router'
+
+const Layout = () => import('@/layouts/index.vue')
+
+const routes: RouteRecordRaw = {
+  path: '/personnel',
+  component: Layout,
+  redirect: '/personnel/member',
+  name: 'Personnel',
+  meta: {
+    title: '成员管理',
+  },
+  children: [
+    {
+      path: 'member',
+      name: 'personnelMember',
+      component: () => import('@/views/personnel/memberManagement.vue'),
+      meta: {
+        title: '成员管理',
+      },
+    },
+    {
+      path: 'role',
+      name: 'personnelRole',
+      component: () => import('@/views/personnel/roleManagement.vue'),
+      meta: {
+        title: '角色管理',
+      },
+    },
+  ],
+}
+
+export default routes

+ 0 - 0
src/router/modules/tenantManagement.ts


+ 49 - 2
src/router/routes.ts

@@ -4,6 +4,8 @@ import useSettingsStore from '@/store/modules/settings'
 import generatedRoutes from 'virtual:generated-pages'
 import { setupLayouts } from 'virtual:meta-layouts'
 import MultilevelMenuExample from './modules/multilevel.menu.example'
+import organizationManagement from './modules/organization'
+import personnel from './modules/personnel'
 
 // 固定路由(默认路由)
 const constantRoutes: RouteRecordRaw[] = [
@@ -66,17 +68,62 @@ const asyncRoutes: Route.recordMainRaw[] = [
     },
     children: [
       MultilevelMenuExample,
+
     ],
   },
   {
     meta: {
-      title: '演示1',
+      title: '组织架构',
       icon: 'i-uim:box',
     },
     children: [
-      MultilevelMenuExample,
+      organizationManagement,
+      personnel
+    ],
+  },
+  {
+    meta: {
+      title: '租户管理',
+      icon: 'i-uim:box',
+    },
+    children: [
+      organizationManagement
+
     ],
   },
+  {
+    meta: {
+      title: '租户运营',
+      icon: 'i-uim:box',
+    },
+    children: [
+    ],
+  },
+  {
+    meta: {
+      title: '数据中心',
+      icon: 'i-uim:box',
+    },
+    children: [
+    ],
+  },
+  {
+    meta: {
+      title: '增值服务',
+      icon: 'i-uim:box',
+    },
+    children: [
+    ],
+  },
+  {
+    meta: {
+      title: '基础设置',
+      icon: 'i-uim:box',
+    },
+    children: [
+    ],
+  },
+
 ]
 
 const constantRoutesByFilesystem = generatedRoutes.filter((item) => {

+ 20 - 18
src/store/modules/user.ts

@@ -4,7 +4,6 @@ import useRouteStore from './route'
 import useSettingsStore from './settings'
 import useTabbarStore from './tabbar'
 import api from '@/api'
-
 const useUserStore = defineStore(
   // 唯一ID
   'user',
@@ -14,10 +13,11 @@ const useUserStore = defineStore(
     const menuStore = useMenuStore()
     const tabbarStore = useTabbarStore()
 
-    const account = ref(localStorage.account ?? '')
+    const userName = ref(localStorage.userName ?? '')
     const token = ref(localStorage.token ?? '')
     const avatar = ref(localStorage.avatar ?? '')
     const permissions = ref<string[]>([])
+
     const isLogin = computed(() => {
       if (token.value) {
         return true
@@ -25,27 +25,29 @@ const useUserStore = defineStore(
       return false
     })
 
-    // 登录
     async function login(data: {
-      account: string
-      password: string
+      userName: string
+      passWord: string
+      captcha: string
+      system: string
+      captchaId: number
     }) {
-      const res = await api.userApi.login(data)
-      localStorage.setItem('account', res.data.account)
-      localStorage.setItem('token', res.data.token)
-      localStorage.setItem('avatar', res.data.avatar)
-      account.value = res.data.account
-      token.value = res.data.token
-      avatar.value = res.data.avatar
+        const res = await api.userApi.login(data)
+        console.log(res)
+        localStorage.setItem('userName', data.userName)
+        localStorage.setItem('token', res.data)
+        userName.value = data.userName
+        token.value = res.data
+        avatar.value = 'https://fantastic-admin.hurui.me/logo.png'
     }
     // 登出
     async function logout(redirect = router.currentRoute.value.fullPath) {
-      localStorage.removeItem('account')
+      localStorage.removeItem('userName')
       localStorage.removeItem('token')
       localStorage.removeItem('avatar')
-      account.value = ''
+      userName.value = ''
       token.value = ''
-      avatar.value = ''
+      // avatar.value = ''
       permissions.value = []
       routeStore.removeRoutes()
       menuStore.setActived(0)
@@ -59,8 +61,8 @@ const useUserStore = defineStore(
     }
     // 获取权限
     async function getPermissions() {
-      const res = await api.userApi.permission()
-      permissions.value = res.data.permissions
+      // const res = await api.userApi.permission()
+      // permissions.value = res.data.permissions
     }
     // 修改密码
     async function editPassword(data: {
@@ -71,7 +73,7 @@ const useUserStore = defineStore(
     }
 
     return {
-      account,
+      userName,
       token,
       avatar,
       permissions,

+ 37 - 25
src/views/example/index.vue

@@ -1,38 +1,50 @@
 <script setup lang='ts'>
-import  Message  from 'vue-m-message'
-function item() {
-  Message.warning('这是一个警告提示');
-
-}
-const dialogVisible=ref<boolean>(false)
 </script>
 
 <!-- 模板区域 -->
 <template>
   <div>
+    <!-- <PageHeader title="内容块" content="PageMain" /> -->
     <PageMain>
-      <el-button plain @click="dialogVisible = true">
-    Click to open the Dialog
-  </el-button>
+
+    </PageMain>
+    <PageMain title="你可以设置一个自定义的标题">
+      这里放页面内容
     </PageMain>
     <PageMain>
-      <h1 @click="item">1</h1>
+      <template #title>
+        <div style="display: flex; align-items: center; justify-content: space-between;">
+          通过 slot 设置标题
+          <ElButton size="small">
+            还可以放置自定义按钮
+          </ElButton>
+        </div>
+      </template>
+      这里放页面内容
+    </PageMain>
+      <ElRow :gutter="20" style="margin: -10px 10px;">
+      <ElCol :md="8">
+        <PageMain style="margin: 10px 0;">
+          还可以结合 ElRow 使用
+        </PageMain>
+      </ElCol>
+      <ElCol :md="8">
+        <PageMain style="margin: 10px 0;">
+          这里放页面内容
+        </PageMain>
+      </ElCol>
+      <ElCol :md="8">
+        <PageMain style="margin: 10px 0;">
+          这里放页面内容
+        </PageMain>
+      </ElCol>
+    </ElRow>
+
+    <PageMain title="带展开功能" collaspe height="200px">
+      <h1>Fantastic-admin</h1>
+      <img src="../../assets/images/logo.png">
+      <p>这是一款开箱即用的中后台框架,同时它也经历过数十个真实项目的技术沉淀,确保框架在开发中可落地、可使用、可维护</p>
     </PageMain>
-    <el-dialog
-    v-model="dialogVisible"
-    title="Tips"
-    width="500"
-  >
-    <span>This is a message</span>
-    <template #footer>
-      <div class="dialog-footer">
-        <el-button @click="dialogVisible = false">Cancel</el-button>
-        <el-button type="primary" @click="dialogVisible = false">
-          Confirm
-        </el-button>
-      </div>
-    </template>
-  </el-dialog>
   </div>
 </template>
 

+ 1 - 2
src/views/login.vue

@@ -19,7 +19,7 @@ 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>
 
@@ -51,7 +51,6 @@ const formType = ref<'login' | 'register' | 'resetPassword'>('login')
       </Transition>
     </div>
   </div>
-  <Copyright />
 </template>
 
 <style scoped>

+ 12 - 0
src/views/organizationManagement/organization.vue

@@ -0,0 +1,12 @@
+<script lang='ts' setup>
+</script>
+<!-- 模板区域 -->
+<template>
+<div>
+<PageMain>
+</PageMain>
+</div>
+</template>
+
+<!-- 行为区域 -->
+<!-- 样式区域 -->

+ 11 - 0
src/views/personnel/memberManagement.vue

@@ -0,0 +1,11 @@
+<script lang='ts' setup>
+</script>
+<!-- 模板区域 -->
+<template>
+<div>
+<PageMain>
+</PageMain>
+</div>
+</template>
+
+<!-- 行为区域 -->

+ 115 - 0
src/views/personnel/roleManagement.vue

@@ -0,0 +1,115 @@
+<script lang='ts' setup>
+
+const roleName = ref<string>("")
+const roleId = ref<string>("")
+
+const roleList = ref([
+  { name: "财务", id: "1" },
+  { name: "运营", id: "2" },
+  { name: "开发", id: "3" },
+  { name: "admin", id: "4" },
+])
+  function roleobj(id:string){
+    roleId.value=id
+    console.log(roleId.value)
+  }
+interface Tree {
+  id: string
+  label: string
+  children?: Tree[]
+}
+const getKey = (prefix: string, id: number) => {
+  return `${prefix}-${id}`
+}
+
+const createData = (
+  maxDeep: number,
+  maxChildren: number,
+  minNodesNumber: number,
+  deep = 1,
+  key = 'node'
+): Tree[] => {
+  let id = 0
+  return Array.from({ length: minNodesNumber })
+    .fill(deep)
+    .map(() => {
+      const childrenNumber =
+        deep === maxDeep ? 0 : Math.round(Math.random() * maxChildren)
+      const nodeKey = getKey(key, ++id)
+      return {
+        id: nodeKey,
+        label: nodeKey,
+        children: childrenNumber
+          ? createData(maxDeep, maxChildren, childrenNumber, deep + 1, nodeKey)
+          : undefined,
+      }
+    })
+}
+
+const props = {
+  value: 'id',
+  label: 'label',
+  children: 'children',
+}
+const data = createData(4, 30, 40)
+</script>
+<!-- 模板区域 -->
+<template>
+  <div>
+    <ElRow :gutter="20">
+      <ElCol :md="6">
+        <PageMain class="vh100">
+          <ElFormItem prop="roleName">
+            <ElCol :md="17">
+              <ElInput v-model="roleName" placeholder="角色名称查找" type="text" tabindex="1">
+                <template #prefix>
+                  <SvgIcon name="i-ri:user-3-fill" />
+                </template>
+              </ElInput>
+            </ElCol>
+            <ElCol :md="6">
+              <ElButton type="primary">查找</ElButton>
+            </ElCol>
+          </ElFormItem>
+          <div class="roleitem flex j-s a-c" :class="roleId===item.id?'active':''" v-for="(item, index) in roleList" :key="index" @click="roleobj(item.id)">
+            <span>{{ item.name }}</span>
+          </div>
+        </PageMain>
+      </ElCol>
+      <ElCol :md="18">
+        <PageMain class="vh100">
+          <template #title>
+            <div class="flex j-s a-c">
+              <span class="strong">角色管理</span>
+              <div>
+                <ElButton type="primary">编辑</ElButton>
+                <ElButton type="primary">删除</ElButton>
+              </div>
+            </div>
+          </template>
+          <ElDivider></ElDivider>
+          <ElTreeV2 style="max-width: 600px;" :data="data" :props="props" show-checkbox :height="208"></ElTreeV2>
+        </PageMain>
+      </ElCol>
+    </ElRow>
+  </div>
+</template>
+
+<!-- 行为区域 -->
+<!-- 样式区域 -->
+<style lang="scss" scoped>
+.roleitem {
+  padding: 20px;
+  cursor: pointer;
+  background: white;
+}
+
+.roleitem:hover {
+  background: #b4b2b2;
+  transition: 0.2s;
+}
+
+.active {
+  background: #b4b2b2;
+}
+</style>