Преглед на файлове

前端路由数据处理,角色录入功能

@dongkboy преди 1 година
родител
ревизия
8073d72974

+ 2 - 2
.env.development

@@ -3,8 +3,8 @@ VITE_APP_SETTING = true
 # 页面标题
 VITE_APP_TITLE = 掌柜运营平台
 # 接口请求地址,会设置到 axios 的 baseURL 参数上
-# VITE_APP_API_BASEURL = https://test.baoxianzhanggui.com/web-api/ #默认地址
-VITE_APP_API_BASEURL = http://192.168.5.48:8081/  #田智
+# 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 =

+ 1 - 1
.env.production

@@ -3,7 +3,7 @@ VITE_APP_SETTING = false
 # 页面标题
 VITE_APP_TITLE = 生产环境
 # 接口请求地址,会设置到 axios 的 baseURL 参数上
-VITE_APP_API_BASEURL = https://sxzgkj.baoxianzhanggui.com/web-api/
+VITE_APP_API_BASEURL = https://sxzgkj.baoxianzhanggui.com/web-api
 # 调试工具,可设置 eruda 或 vconsole,如果不需要开启则留空
 VITE_APP_DEBUG_TOOL =
 # 是否禁用开发者工具,可防止被调试

+ 1 - 1
.env.test

@@ -3,7 +3,7 @@ VITE_APP_SETTING = false
 # 页面标题
 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
 # 调试工具,可设置 eruda 或 vconsole,如果不需要开启则留空
 VITE_APP_DEBUG_TOOL =
 # 是否禁用开发者工具,可防止被调试

+ 2 - 0
src/api/index.ts

@@ -7,6 +7,7 @@ import Message from 'vue-m-message'
 // 导入 API 模块
 import appApi from './modules/app'
 import userApi from './modules/user'
+import roleApi from './modules/role'
 
 const axiosInstance:ApiInstance = axios.create({
   baseURL: (import.meta.env.DEV && import.meta.env.VITE_OPEN_PROXY === 'true') ? '/proxy/' : import.meta.env.VITE_APP_API_BASEURL,
@@ -85,5 +86,6 @@ axiosInstance.interceptors.response.use(
 const api = {
   appApi: appApi(axiosInstance),
   userApi: userApi(axiosInstance),
+  roleApi: roleApi(axiosInstance),
 }
 export default api

+ 14 - 0
src/api/modules/role.ts

@@ -0,0 +1,14 @@
+import { ApiInstance } from '../type'
+interface roleData {
+  name: string;
+  desc: string;
+  system: string,
+  permsId: number[],
+  perms: string[]
+}
+const roleApi = (axiosInstance: ApiInstance) => ({
+  // 新增角色
+  roleAdd: (data: roleData) => axiosInstance.post('userRole/roleAdd', data, {}),
+})
+
+export default roleApi

+ 1 - 1
src/api/modules/user.ts

@@ -17,7 +17,7 @@ const userApi = (axiosInstance: ApiInstance) => ({
 
   }),
   // 获取权限
-  permission: () => axiosInstance.get('user/permission', {
+  permission: () => axiosInstance.get('auth/getUserPer', {
   }),
 
   // 修改密码

+ 17 - 1
src/assets/styles/globals.css

@@ -225,9 +225,25 @@ textarea {
 }
 
 .vh100 {
-  min-height: calc(100vh - 200px);
+  height: calc(100vh - 200px);
 }
 
 .strong {
   font-weight: bold;
 }
+
+.size14 {
+  font-size: 14px;
+}
+
+.pad-1 {
+  padding: 10px;
+}
+
+.pad-2 {
+  padding: 20px;
+}
+
+.pad-3 {
+  padding: 30px;
+}

+ 1 - 1
src/components/LoginForm/index.vue

@@ -58,7 +58,7 @@ function refreshCaptcha() {
   let randnum = Math.floor(Math.random() * (1000000 - 1 + 1)) + 1;
   captchaSrc.value =
     baseurl +
-    "auth/captchaById?t=" +
+    "/auth/captchaById?t=" +
     new Date().getTime() +
     "&captchaId=" +
     randnum;

+ 1 - 1
src/layouts/components/Topbar/Toolbar/rightSide.vue

@@ -46,7 +46,7 @@ watch(() => userStore.avatar, () => {
       <div class="flex-center gap-1">
         <img v-if="userStore.avatar && !avatarError" :src="userStore.avatar" :onerror="() => (avatarError = true)" class="h-[24px] w-[24px] rounded-full">
         <SvgIcon v-else name="i-carbon:user-avatar-filled-alt" :size="24" class="text-gray-400" />
-        {{ userStore.account }}
+        {{ userStore.userName }}
         <SvgIcon name="i-ep:caret-bottom" />
       </div>
     </HDropdownMenu>

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

@@ -9,6 +9,7 @@ const routes: RouteRecordRaw = {
   name: 'Example',
   meta: {
     title: '演示',
+    type: 0,
   },
   children: [
     {
@@ -17,6 +18,7 @@ const routes: RouteRecordRaw = {
       component: () => import('@/views/example/index.vue'),
       meta: {
         title: '演示页面',
+        Type: 1,
       },
     },
     {
@@ -25,6 +27,8 @@ const routes: RouteRecordRaw = {
       component: () => import('@/views/example/ceshi.vue'),
       meta: {
         title: '权限测试',
+        Type: 1,
+        
       },
     },
   ],

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

@@ -17,6 +17,8 @@ const routes: RouteRecordRaw = {
       component: () => import('@/views/personnel/memberManagement.vue'),
       meta: {
         title: '成员管理',
+
+
       },
     },
     {
@@ -25,6 +27,7 @@ const routes: RouteRecordRaw = {
       component: () => import('@/views/personnel/roleManagement.vue'),
       meta: {
         title: '角色管理',
+        auth:['role.add','role.view','role.delete','role.edit']
       },
     },
   ],

+ 3 - 2
src/store/modules/menu.ts

@@ -1,6 +1,6 @@
 import type { Menu, Route } from '#/global'
 import type { RouteRecordRaw } from 'vue-router'
-import apiApp from '@/api/modules/app'
+import api from '@/api'
 import menu from '@/menu'
 import { resolveRoutePath } from '@/utils'
 import { cloneDeep } from 'lodash-es'
@@ -143,6 +143,7 @@ const useMenuStore = defineStore(
       let isAuth = false
       if (menu.meta?.auth) {
         isAuth = permissions.some((auth) => {
+          console.log(auth)
           if (typeof menu.meta?.auth === 'string') {
             return menu.meta.auth !== '' ? menu.meta.auth === auth : true
           }
@@ -183,7 +184,7 @@ const useMenuStore = defineStore(
     }
     // 生成导航(后端生成)
     async function generateMenusAtBack() {
-      await apiApp.menuList().then(async (res) => {
+      await api.appApi.menuList().then(async (res) => {
         filesystemMenusRaw.value = (res.data as Menu.recordMainRaw[]).filter(item => item.children.length !== 0)
       }).catch(() => {})
     }

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

@@ -61,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
     }
     // 修改密码
     async function editPassword(data: {

+ 3 - 0
src/types/auto-imports.d.ts

@@ -9,6 +9,7 @@ declare global {
   const EffectScope: typeof import('vue')['EffectScope']
   const acceptHMRUpdate: typeof import('pinia')['acceptHMRUpdate']
   const computed: typeof import('vue')['computed']
+  const convertToTreeData: typeof import('../utils/composables/routeUtils')['convertToTreeData']
   const createApp: typeof import('vue')['createApp']
   const createPinia: typeof import('pinia')['createPinia']
   const customRef: typeof import('vue')['customRef']
@@ -48,6 +49,8 @@ declare global {
   const onUnmounted: typeof import('vue')['onUnmounted']
   const onUpdated: typeof import('vue')['onUpdated']
   const onWatcherCleanup: typeof import('vue')['onWatcherCleanup']
+  const permissionDictionary: typeof import('../utils/composables/routeUtils')['permissionDictionary']
+  const preprocessRoutes: typeof import('../utils/composables/routeUtils')['preprocessRoutes']
   const provide: typeof import('vue')['provide']
   const reactive: typeof import('vue')['reactive']
   const readonly: typeof import('vue')['readonly']

+ 96 - 0
src/utils/composables/routeUtils.ts

@@ -0,0 +1,96 @@
+// routeUtils.ts
+export const permissionDictionary: Record<string, string> = {
+  'add': '新增',
+  'view': '查看',
+  'edit': '修改',
+  'delete': '删除',
+  // 添加更多操作类型映射
+};
+export interface RouteItem {
+  path: string;
+  name?: string;
+  meta?: {
+    title?: string;
+    icon?: string;
+    auth?: string[];
+  };
+  children?: RouteItem[];
+}
+
+export interface TreeNode {
+  id: number;
+  title: string;
+  icon?: string;
+  type?:string,
+  children?: TreeNode[];
+  [key: string]: any; // 允许任意其他属性
+}
+
+let idCounter = 0;
+
+// 生成唯一 ID
+const generateId = (): number => {
+  return ++idCounter;
+};
+
+// 预处理函数:确保 children 和 auth 类型正确
+export const preprocessRoutes = (routes: any[]): RouteItem[] => {
+  return routes.map(route => {
+    const processedRoute: RouteItem = {
+      path: route.path || '',
+      name: route.name,
+      meta: {
+        ...route.meta,
+        // 确保 meta.auth 始终是一个数组
+        auth: Array.isArray(route.meta?.auth)
+          ? route.meta.auth
+          : route.meta?.auth
+          ? [route.meta.auth]
+          : [],
+      },
+      // 确保 children 存在且是数组
+      children: route.children ? preprocessRoutes(route.children) : [],
+    };
+
+    return processedRoute;
+  });
+};
+
+// 将 auth 转换为树节点
+const parseAuthToChildren = (authList: string[]): TreeNode[] => {
+  return authList.map(auth => {
+    const parts = auth.split('.');
+    const operation = parts[parts.length - 1]; // 获取最后一部分作为操作类型
+    const title = permissionDictionary[operation] || operation; // 使用字典获取英文名称
+
+    return {
+      id: generateId(),
+      title: `${title} (${auth})`, // 显示英文名称和原始权限
+      auth: auth, // 保留原始权限路径
+      type: '2',
+    };
+  });
+};
+
+// 将 RouteItem 转换为 TreeNode
+export const convertToTreeData = (routes: RouteItem[]): TreeNode[] => {
+  return routes.map(route => {
+    const node: TreeNode = {
+      id: generateId(),
+      title: route.meta?.title || route.name || '',
+      icon: route.meta?.icon,
+      type:route.path?"1":'0',
+    };
+
+    if (route.children && route.children.length > 0) {
+      node.children = convertToTreeData(route.children);
+    }
+
+    if (route.meta?.auth) {
+      const authNodes = parseAuthToChildren(route.meta.auth);
+      node.children = node.children ? node.children.concat(authNodes) : authNodes;
+    }
+
+    return node;
+  });
+};

+ 0 - 3
src/views/example/ceshi.vue

@@ -13,6 +13,3 @@
 
 <!-- 行为区域 -->
 <!-- 样式区域 -->
-<style lang='scss' scoped>
-
-</style>

+ 8 - 9
src/views/organizationManagement/organization.vue

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

+ 85 - 64
src/views/personnel/roleManagement.vue

@@ -1,59 +1,3 @@
-<script lang='ts' setup>
-import {ref} from "vue"
-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">
@@ -71,9 +15,7 @@ const data = createData(4, 30, 40)
               <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">
@@ -82,21 +24,100 @@ const data = createData(4, 30, 40)
             <div class="flex j-s a-c">
               <span class="strong">角色管理</span>
               <div>
-                <ElButton type="primary">编辑</ElButton>
-                <ElButton type="primary">删除</ElButton>
+                <ElButton type="primary" @click="roleSubmit">提交</ElButton>
               </div>
             </div>
           </template>
+          <h5>基本信息</h5>
+          <ElCol :md="6"></ElCol>
+          <ElForm :model="roleInfo" :rules="roleRules" label-width="auto" size="" style="max-width: 500px;">
+            <ElFormItem prop="name" label="角色名称">
+              <ElInput v-model="roleInfo.name" placeholder="输入20个字以内的角色名称" type="text" tabindex="1">
+              </ElInput>
+            </ElFormItem>
+            <ElFormItem prop="desc" label="角色描述">
+              <ElInput v-model="roleInfo.desc" placeholder="请输入" type="textarea" tabindex="2">
+              </ElInput>
+            </ElFormItem>
+          </ElForm>
           <ElDivider></ElDivider>
-          <ElTreeV2 style="max-width: 600px;" :data="data" :props="props" show-checkbox :height="208"></ElTreeV2>
+          <div>
+            <h5>角色权限</h5>
+            <ElTree style="max-height: 350px;overflow-y: auto;" :data="treeData" :props="defaultProps" show-checkbox
+              node-key="id" :default-expand-all="true" :default-checked-keys="[6]" @check="handleCheckChange" />
+          </div>
         </PageMain>
       </ElCol>
     </ElRow>
+
   </div>
 </template>
 
-<!-- 行为区域 -->
-<!-- 样式区域 -->
+<script lang='ts' setup>
+import { asyncRoutes } from '@/router/routes' // 请根据实际路径调整
+import { ref, reactive, onMounted } from 'vue';
+import type { FormRules } from 'element-plus';
+import { preprocessRoutes, convertToTreeData, TreeNode } from '@/utils/composables/routeUtils'; // 导入工具方法
+import api from '@/api'
+const roleName = ref<string>("");
+
+const roleInfo = reactive<{
+  name: string;
+  desc: string;
+  system: string,
+  permsId: number[],
+  perms: string[]
+}>({
+  name: "",//角色
+  desc: "",//描述
+  system: "PLATFORM",//系统
+  permsId: [],//权限id
+  perms: [],//权限标识
+});
+const roleRules = ref<FormRules>({
+  name: [
+    { required: true, trigger: 'blur', message: '请输入角色名称' },
+  ],
+
+});
+const treeData = ref<TreeNode[]>([]);
+const defaultProps = {
+  children: 'children',
+  label: 'title',
+};
+const handleCheckChange = (
+  _checkedNodes: TreeNode[],
+  checkedInfo: {
+    checkedKeys: number[];
+    checkedNodes: TreeNode[];
+    halfCheckedKeys: number[];
+    halfCheckedNodes: TreeNode[];
+  }
+) => {
+  // console.log('Checked keys:', checkedInfo.checkedKeys);
+  // console.log(checkedInfo.checkedNodes);
+  roleInfo.permsId = checkedInfo.checkedKeys;
+  roleInfo.perms = [];
+  checkedInfo.checkedNodes.forEach(val => {
+    if (val.type === '2' ) {
+      roleInfo.perms.push(val.auth);
+    }
+  });
+};
+   function roleSubmit() {
+    api.roleApi.roleAdd(roleInfo).then((res)=>{
+      console.log(res)
+    })
+  }
+onMounted(() => {
+  // 对 asyncRoutes 进行预处理并转换为树形结构
+  const processedRoutes = preprocessRoutes(asyncRoutes);
+  treeData.value = convertToTreeData(processedRoutes);
+
+});
+
+</script>
+
 <style lang="scss" scoped>
 .roleitem {
   padding: 20px;