forked from wo123/SoybeanAdmin
		
	新增权限组页面,增删改查(未完成)
This commit is contained in:
		
							parent
							
								
									d4457b9f30
								
							
						
					
					
						commit
						4dd21ebc53
					
				@ -41,16 +41,26 @@ export function useTable<A extends NaiveUI.TableApiFn>(config: NaiveUI.NaiveTabl
 | 
			
		||||
    transformer: res => {
 | 
			
		||||
      console.log(res);
 | 
			
		||||
      const { data = [], current = 1, size = 10, total = 0 } = res || {};
 | 
			
		||||
 | 
			
		||||
      // Ensure that the size is greater than 0, If it is less than 0, it will cause paging calculation errors.
 | 
			
		||||
      console.log(total);
 | 
			
		||||
      const pageSize = size <= 0 ? 10 : size;
 | 
			
		||||
 | 
			
		||||
      const recordsWithIndex = data.map((item, index) => {
 | 
			
		||||
        return {
 | 
			
		||||
          ...item,
 | 
			
		||||
          index: (current - 1) * pageSize + index + 1
 | 
			
		||||
        };
 | 
			
		||||
      });
 | 
			
		||||
      if(data.data){
 | 
			
		||||
        var recordsWithIndex = data.data.map((item, index) => {
 | 
			
		||||
          return {
 | 
			
		||||
            ...item,
 | 
			
		||||
            index: (current - 1) * pageSize + index + 1
 | 
			
		||||
          };
 | 
			
		||||
        });
 | 
			
		||||
      }else{
 | 
			
		||||
        var recordsWithIndex = data.map((item, index) => {
 | 
			
		||||
          return {
 | 
			
		||||
            ...item,
 | 
			
		||||
            index: (current - 1) * pageSize + index + 1
 | 
			
		||||
          };
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      
 | 
			
		||||
      console.log(recordsWithIndex);
 | 
			
		||||
      return {
 | 
			
		||||
        data: recordsWithIndex,
 | 
			
		||||
 | 
			
		||||
@ -21,6 +21,7 @@ export const views: Record<LastLevelRouteKey, RouteComponent | (() => Promise<Ro
 | 
			
		||||
  "iframe-page": () => import("@/views/_builtin/iframe-page/[url].vue"),
 | 
			
		||||
  login: () => import("@/views/_builtin/login/index.vue"),
 | 
			
		||||
  home: () => import("@/views/home/index.vue"),
 | 
			
		||||
  system_auth: () => import("@/views/system/auth/index.vue"),
 | 
			
		||||
  system_menu: () => import("@/views/system/menu/index.vue"),
 | 
			
		||||
  system_user: () => import("@/views/system/user/index.vue"),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -84,6 +84,15 @@ export const generatedRoutes: GeneratedRoute[] = [
 | 
			
		||||
      i18nKey: 'route.system'
 | 
			
		||||
    },
 | 
			
		||||
    children: [
 | 
			
		||||
      {
 | 
			
		||||
        name: 'system_auth',
 | 
			
		||||
        path: '/system/auth',
 | 
			
		||||
        component: 'view.system_auth',
 | 
			
		||||
        meta: {
 | 
			
		||||
          title: 'system_auth',
 | 
			
		||||
          i18nKey: 'route.system_auth'
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        name: 'system_menu',
 | 
			
		||||
        path: '/system/menu',
 | 
			
		||||
 | 
			
		||||
@ -170,6 +170,7 @@ const routeMap: RouteMap = {
 | 
			
		||||
  "iframe-page": "/iframe-page/:url",
 | 
			
		||||
  "login": "/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?",
 | 
			
		||||
  "system": "/system",
 | 
			
		||||
  "system_auth": "/system/auth",
 | 
			
		||||
  "system_menu": "/system/menu",
 | 
			
		||||
  "system_user": "/system/user"
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										36
									
								
								src/service/api/group.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/service/api/group.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,36 @@
 | 
			
		||||
import { request } from '../request';
 | 
			
		||||
 | 
			
		||||
/** 获取API权限组列表 */
 | 
			
		||||
export function fetchGetGroups(params?: Api.Common.CommonSearchParams) {
 | 
			
		||||
  return request<GroupApi.GroupListResponse>({ 
 | 
			
		||||
    url: '/adminapi/group/index',
 | 
			
		||||
    method: 'get',
 | 
			
		||||
    params
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 添加API权限组 */
 | 
			
		||||
export function addGroup(data: Partial<GroupApi.Group>) {
 | 
			
		||||
  return request({
 | 
			
		||||
    url: '/adminapi/group/add',
 | 
			
		||||
    method: 'post',
 | 
			
		||||
    data
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 编辑API权限组 */
 | 
			
		||||
export function editGroup(data: Partial<GroupApi.Group>) {
 | 
			
		||||
  return request({
 | 
			
		||||
    url: `/adminapi/group/edit/ids/${data.id}`,
 | 
			
		||||
    method: 'post',
 | 
			
		||||
    data
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 删除API权限组 */
 | 
			
		||||
export function deleteGroup(id: number) {
 | 
			
		||||
  return request({
 | 
			
		||||
    url: `/adminapi/group/del/ids/${id}`,
 | 
			
		||||
    method: 'get'
 | 
			
		||||
  });
 | 
			
		||||
} 
 | 
			
		||||
							
								
								
									
										2
									
								
								src/typings/elegant-router.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								src/typings/elegant-router.d.ts
									
									
									
									
										vendored
									
									
								
							@ -24,6 +24,7 @@ declare module "@elegant-router/types" {
 | 
			
		||||
    "iframe-page": "/iframe-page/:url";
 | 
			
		||||
    "login": "/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?";
 | 
			
		||||
    "system": "/system";
 | 
			
		||||
    "system_auth": "/system/auth";
 | 
			
		||||
    "system_menu": "/system/menu";
 | 
			
		||||
    "system_user": "/system/user";
 | 
			
		||||
  };
 | 
			
		||||
@ -86,6 +87,7 @@ declare module "@elegant-router/types" {
 | 
			
		||||
    | "iframe-page"
 | 
			
		||||
    | "login"
 | 
			
		||||
    | "home"
 | 
			
		||||
    | "system_auth"
 | 
			
		||||
    | "system_menu"
 | 
			
		||||
    | "system_user"
 | 
			
		||||
  >;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										32
									
								
								src/typings/group.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/typings/group.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,32 @@
 | 
			
		||||
/**
 | 
			
		||||
 * 权限组相关类型定义
 | 
			
		||||
 */
 | 
			
		||||
declare namespace GroupApi {
 | 
			
		||||
  /** 权限组数据类型 */
 | 
			
		||||
  interface Group {
 | 
			
		||||
    /** 权限组ID */
 | 
			
		||||
    id: number;
 | 
			
		||||
    /** 权限组名称 */
 | 
			
		||||
    name: string;
 | 
			
		||||
    /** 规则ID */
 | 
			
		||||
    rules: string;
 | 
			
		||||
    /** 创建时间 */
 | 
			
		||||
    createtime: string;
 | 
			
		||||
    /** 更新时间 */
 | 
			
		||||
    updatetime: string;
 | 
			
		||||
    /** 状态 */
 | 
			
		||||
    status: string;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** 权限组列表响应 */
 | 
			
		||||
  interface GroupListResponse {
 | 
			
		||||
    /** 权限组列表 */
 | 
			
		||||
    data: Group[];
 | 
			
		||||
    /** 当前页码 */
 | 
			
		||||
    current: number;
 | 
			
		||||
    /** 每页条数 */
 | 
			
		||||
    size: number;
 | 
			
		||||
    /** 总条数 */
 | 
			
		||||
    total: number;
 | 
			
		||||
  }
 | 
			
		||||
} 
 | 
			
		||||
							
								
								
									
										278
									
								
								src/views/system/auth/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										278
									
								
								src/views/system/auth/index.vue
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,278 @@
 | 
			
		||||
<script setup lang="tsx">
 | 
			
		||||
import { ref } from 'vue';
 | 
			
		||||
import type { Ref } from 'vue';
 | 
			
		||||
import { NButton, NPopconfirm, NTag, NTreeSelect } from 'naive-ui';
 | 
			
		||||
import { useBoolean } from '@sa/hooks';
 | 
			
		||||
import { useAppStore } from '@/store/modules/app';
 | 
			
		||||
import { useTable, useTableOperate } from '@/hooks/common/table';
 | 
			
		||||
import { $t } from '@/locales';
 | 
			
		||||
import { yesOrNoRecord } from '@/constants/common';
 | 
			
		||||
import SvgIcon from '@/components/custom/svg-icon.vue';
 | 
			
		||||
import { fetchGetGroups, addGroup, editGroup, deleteGroup } from '@/service/api/group';
 | 
			
		||||
import { fetchGetUserRoutes } from '@/service/api/route';
 | 
			
		||||
 | 
			
		||||
const appStore = useAppStore();
 | 
			
		||||
 | 
			
		||||
const { bool: visible, setTrue: openModal } = useBoolean();
 | 
			
		||||
 | 
			
		||||
const wrapperRef = ref<HTMLElement | null>(null);
 | 
			
		||||
const title = ref('');
 | 
			
		||||
const rulesTree = ref<any[]>([]);
 | 
			
		||||
const rulesLoading = ref(false);
 | 
			
		||||
 | 
			
		||||
const model = ref<Partial<GroupApi.Group & { rulesArray: (string | number)[] }>>({
 | 
			
		||||
    id: 0,
 | 
			
		||||
    name: '',
 | 
			
		||||
    rules: '',
 | 
			
		||||
    status: '',
 | 
			
		||||
    rulesArray: []
 | 
			
		||||
});
 | 
			
		||||
const rules = {};
 | 
			
		||||
 | 
			
		||||
const { columns, columnChecks, data, loading, pagination, getData, getDataByPage } = useTable({
 | 
			
		||||
    apiFn: fetchGetGroups,
 | 
			
		||||
    columns: () => [
 | 
			
		||||
        {
 | 
			
		||||
            key: 'id',
 | 
			
		||||
            title: 'ID',
 | 
			
		||||
            align: 'center',
 | 
			
		||||
            width: 100,
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            key: 'name',
 | 
			
		||||
            title: '权限组名称',
 | 
			
		||||
            align: 'center',
 | 
			
		||||
            width: 250,
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            key: 'rules',
 | 
			
		||||
            title: '规则ID',
 | 
			
		||||
            align: 'center',
 | 
			
		||||
            width: 300,
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            key: 'createtime',
 | 
			
		||||
            title: '创建时间',
 | 
			
		||||
            align: 'center',
 | 
			
		||||
            width: 200,
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            key: 'updatetime',
 | 
			
		||||
            title: '更新时间',
 | 
			
		||||
            align: 'center',
 | 
			
		||||
            width: 200,
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            key: 'status',
 | 
			
		||||
            title: '状态',
 | 
			
		||||
            align: 'center',
 | 
			
		||||
            width: 120,
 | 
			
		||||
            render: (row) => {
 | 
			
		||||
                const status: CommonType.YesOrNo = row.status === 'hidden' ? 'N' : 'Y';
 | 
			
		||||
 | 
			
		||||
                const tagMap: Record<CommonType.YesOrNo, NaiveUI.ThemeColor> = {
 | 
			
		||||
                    Y: 'error',
 | 
			
		||||
                    N: 'default'
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                const label = $t(yesOrNoRecord[status]);
 | 
			
		||||
 | 
			
		||||
                return <NTag type={ tagMap[status] }> { label } </NTag>;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            key: 'operate',
 | 
			
		||||
            title: '操作',
 | 
			
		||||
            align: 'center',
 | 
			
		||||
            width: 230,
 | 
			
		||||
            render: (row) => (
 | 
			
		||||
                <div class= "flex-center justify-end gap-8px" >
 | 
			
		||||
                <NButton type="primary" ghost size="small" onClick={() => handleEdit(row)}>
 | 
			
		||||
                    编辑
 | 
			
		||||
                    </NButton>
 | 
			
		||||
                    < NPopconfirm onPositiveClick = {() => handleDelete(row.id as number)}>
 | 
			
		||||
                        {{
 | 
			
		||||
              default: () => '确定删除吗?',
 | 
			
		||||
        trigger: () => (
 | 
			
		||||
            <NButton type= "error" ghost size = "small" >
 | 
			
		||||
                删除
 | 
			
		||||
                </NButton>
 | 
			
		||||
              )
 | 
			
		||||
}}
 | 
			
		||||
</NPopconfirm>
 | 
			
		||||
    </div>
 | 
			
		||||
      )
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const { checkedRowKeys, onBatchDeleted, onDeleted } = useTableOperate(data, getData);
 | 
			
		||||
 | 
			
		||||
const operateType = ref('add');
 | 
			
		||||
 | 
			
		||||
function handleAdd() {
 | 
			
		||||
    operateType.value = 'add';
 | 
			
		||||
    title.value = '新增API权限组';
 | 
			
		||||
    // 清空model
 | 
			
		||||
    model.value = {
 | 
			
		||||
        id: 0,
 | 
			
		||||
        name: '',
 | 
			
		||||
        rules: '',
 | 
			
		||||
        status: '',
 | 
			
		||||
        rulesArray: []
 | 
			
		||||
    };
 | 
			
		||||
    openModal();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function handleDelete(id: number) {
 | 
			
		||||
    // request
 | 
			
		||||
    const { response } = await deleteGroup(id);
 | 
			
		||||
    console.log(response);
 | 
			
		||||
    if (response?.data?.code === 1) {
 | 
			
		||||
        window.$message?.success(response.data.msg);
 | 
			
		||||
        getData();
 | 
			
		||||
    } else {
 | 
			
		||||
        window.$message?.error(response?.data?.msg || '删除失败');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function handleEdit(item: any) {
 | 
			
		||||
    operateType.value = 'edit';
 | 
			
		||||
    title.value = '编辑API权限组';
 | 
			
		||||
    model.value = {
 | 
			
		||||
        id: item.id,
 | 
			
		||||
        name: item.name,
 | 
			
		||||
        rules: item.rules,
 | 
			
		||||
        status: item.status,
 | 
			
		||||
        rulesArray: rulesStrToArray(item.rules)
 | 
			
		||||
    };
 | 
			
		||||
    openModal();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function init() {
 | 
			
		||||
    initRulesTree();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 创建获取规则树数据的函数
 | 
			
		||||
async function initRulesTree() {
 | 
			
		||||
    rulesLoading.value = true;
 | 
			
		||||
    try {
 | 
			
		||||
        const { response } = await fetchGetUserRoutes();
 | 
			
		||||
        if (response?.data?.code === 1) {
 | 
			
		||||
            // 假设接口返回的数据结构需要转换成tree格式
 | 
			
		||||
            rulesTree.value = formatRulesTree(response.data.data || []);
 | 
			
		||||
        } else {
 | 
			
		||||
            window.$message?.error(response?.data?.msg || '获取规则列表失败');
 | 
			
		||||
        }
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
        console.error('获取规则列表失败', error);
 | 
			
		||||
        window.$message?.error('获取规则列表失败');
 | 
			
		||||
    } finally {
 | 
			
		||||
        rulesLoading.value = false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 转换规则树数据格式的函数
 | 
			
		||||
function formatRulesTree(data: any[]) {
 | 
			
		||||
    // 根据实际API返回结构进行格式转换
 | 
			
		||||
    // 这里假设API返回的数据结构已经是合适的树形结构
 | 
			
		||||
    // 可能需要根据实际情况调整键名,如把id改为key,把name改为label等
 | 
			
		||||
    return data.map(item => ({
 | 
			
		||||
        key: item.id,
 | 
			
		||||
        label: item.title || item.name,
 | 
			
		||||
        children: item.children ? formatRulesTree(item.children) : undefined
 | 
			
		||||
    }));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ID字符串转数组的函数
 | 
			
		||||
function rulesStrToArray(rulesStr: string): (string | number)[] {
 | 
			
		||||
    if (!rulesStr) return [];
 | 
			
		||||
    return rulesStr.split(',').map(item => {
 | 
			
		||||
        // 如果ID是数字类型,则转换为数字
 | 
			
		||||
        const numId = Number(item);
 | 
			
		||||
        return isNaN(numId) ? item : numId;
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ID数组转字符串的函数
 | 
			
		||||
function rulesArrayToStr(rulesArray: (string | number)[]): string {
 | 
			
		||||
    if (!rulesArray || !rulesArray.length) return '';
 | 
			
		||||
    return rulesArray.join(',');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// init
 | 
			
		||||
init();
 | 
			
		||||
 | 
			
		||||
async function handleSubmit() {
 | 
			
		||||
    // 在提交前将规则数组转换为字符串
 | 
			
		||||
    if (model.value.rulesArray) {
 | 
			
		||||
        model.value.rules = rulesArrayToStr(model.value.rulesArray);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    let res;
 | 
			
		||||
    if (operateType.value === 'add') {
 | 
			
		||||
        res = await addGroup(model.value);
 | 
			
		||||
    } else {
 | 
			
		||||
        res = await editGroup(model.value);
 | 
			
		||||
    }
 | 
			
		||||
    console.log('response: ', res.response);
 | 
			
		||||
    if (res.response?.data?.code === 1) {
 | 
			
		||||
        window.$message?.success(res.response.data.msg);
 | 
			
		||||
        visible.value = false;
 | 
			
		||||
        getData();
 | 
			
		||||
    } else {
 | 
			
		||||
        window.$message?.error(res.response?.data?.msg || '操作失败');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
    <div ref="wrapperRef" class="flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
 | 
			
		||||
        <NCard title="API权限组管理" :bordered="false" size="small" class="sm:flex-1-hidden card-wrapper">
 | 
			
		||||
            <template #header-extra>
 | 
			
		||||
                <TableHeaderOperation v-model:columns="columnChecks" :disabled-delete="checkedRowKeys.length === 0"
 | 
			
		||||
                    :loading="loading" @add="handleAdd" @refresh="getData" />
 | 
			
		||||
            </template>
 | 
			
		||||
            <NDataTable v-model:checked-row-keys="checkedRowKeys" :columns="columns" :data="data" size="small"
 | 
			
		||||
                :flex-height="!appStore.isMobile" :scroll-x="1088" :loading="loading" :row-key="row => row.id" remote
 | 
			
		||||
                :pagination="pagination" class="sm:h-full" />
 | 
			
		||||
        </NCard>
 | 
			
		||||
        <NModal v-model:show="visible" :title="title" preset="card" class="w-800px">
 | 
			
		||||
            <NScrollbar class="h-480px pr-20px">
 | 
			
		||||
                <NForm ref="formRef" :model="model" :rules="rules" label-placement="left" :label-width="100">
 | 
			
		||||
                    <NGrid responsive="screen" item-responsive>
 | 
			
		||||
                        <NFormItemGi span="24" label="权限组名称" path="name">
 | 
			
		||||
                            <NInput v-model:value="model.name" placeholder="请输入权限组名称" />
 | 
			
		||||
                        </NFormItemGi>
 | 
			
		||||
                        <NFormItemGi span="24" label="规则ID" path="rulesArray">
 | 
			
		||||
                            <NTreeSelect
 | 
			
		||||
                                v-model:value="model.rulesArray"
 | 
			
		||||
                                placeholder="请选择规则"
 | 
			
		||||
                                :options="rulesTree"
 | 
			
		||||
                                :loading="rulesLoading"
 | 
			
		||||
                                multiple
 | 
			
		||||
                                cascade
 | 
			
		||||
                                checkable
 | 
			
		||||
                                clearable
 | 
			
		||||
                            />
 | 
			
		||||
                        </NFormItemGi>
 | 
			
		||||
                        <NFormItemGi span="24 m:12" label="状态" path="status">
 | 
			
		||||
                            <NRadioGroup v-model:value="model.status">
 | 
			
		||||
                                <NRadio value="hidden" label="禁用" />
 | 
			
		||||
                                <NRadio value="normal" label="正常" />
 | 
			
		||||
                            </NRadioGroup>
 | 
			
		||||
                        </NFormItemGi>
 | 
			
		||||
                    </NGrid>
 | 
			
		||||
                </NForm>
 | 
			
		||||
            </NScrollbar>
 | 
			
		||||
            <template #footer>
 | 
			
		||||
                <NSpace justify="end" :size="16">
 | 
			
		||||
                    <NButton @click="visible = false">取消</NButton>
 | 
			
		||||
                    <NButton type="primary" @click="handleSubmit">确认</NButton>
 | 
			
		||||
                </NSpace>
 | 
			
		||||
            </template>
 | 
			
		||||
        </NModal>
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<style scoped></style>
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user