😎优化授权角色接口资源

This commit is contained in:
zuohuaijun 2024-06-26 23:32:26 +08:00
parent 95d156fe71
commit 3001840e6e
12 changed files with 235 additions and 266 deletions

View File

@ -36,8 +36,8 @@
<PackageReference Include="SKIT.FlurlHttpClient.Wechat.TenpayV3" Version="3.5.0" /> <PackageReference Include="SKIT.FlurlHttpClient.Wechat.TenpayV3" Version="3.5.0" />
<PackageReference Include="SqlSugarCore" Version="5.1.4.159" /> <PackageReference Include="SqlSugarCore" Version="5.1.4.159" />
<PackageReference Include="SSH.NET" Version="2024.0.0" /> <PackageReference Include="SSH.NET" Version="2024.0.0" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.4.1" /> <PackageReference Include="System.Linq.Dynamic.Core" Version="1.4.2" />
<PackageReference Include="TencentCloudSDK.Sms" Version="3.0.1033" /> <PackageReference Include="TencentCloudSDK.Sms" Version="3.0.1034" />
<PackageReference Include="UAParser" Version="3.1.47" /> <PackageReference Include="UAParser" Version="3.1.47" />
<PackageReference Include="Yitter.IdGenerator" Version="1.0.14" /> <PackageReference Include="Yitter.IdGenerator" Version="1.0.14" />
</ItemGroup> </ItemGroup>

View File

@ -35,14 +35,17 @@ public class RoleApiJob : IJob
var sysRoleApis = new List<SysRoleApi>(); var sysRoleApis = new List<SysRoleApi>();
foreach (var baseApi in apiList) foreach (var baseApi in apiList)
{ {
foreach (var api in baseApi.Apis) foreach (var controller in baseApi.Children)
{ {
// 排除租户管理接口 // 排除租户管理接口
if (api.ControllerName == "sysTenant") continue; if (controller.Name == "sysTenant") continue;
// 为系统管理员分配接口 foreach (var api in controller.Children)
sysRoleApis.Add(new SysRoleApi { Id = 1400000000101 + index, RoleId = 1300000000101, Route = api.Route }); {
index++; // 为系统管理员分配接口
sysRoleApis.Add(new SysRoleApi { Id = 1400000000101 + index, RoleId = 1300000000101, Route = api.Route });
index++;
}
} }
} }
var db = serviceScope.ServiceProvider.GetRequiredService<ISqlSugarClient>(); var db = serviceScope.ServiceProvider.GetRequiredService<ISqlSugarClient>();

View File

@ -31,10 +31,10 @@ public class SysConfigSeedData : ISqlSugarEntitySeedData<SysConfig>
new SysConfig{ Id=1300000000191, Name="发送异常日志邮件", Code="sys_error_mail", Value="True", SysFlag=YesNoEnum.Y, Remark="是否发送异常日志邮件", OrderNo=100, GroupCode="Default", CreateTime=DateTime.Parse("2022-02-10 00:00:00") }, new SysConfig{ Id=1300000000191, Name="发送异常日志邮件", Code="sys_error_mail", Value="True", SysFlag=YesNoEnum.Y, Remark="是否发送异常日志邮件", OrderNo=100, GroupCode="Default", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000201, Name="开启域登录验证", Code="sys_domain_login", Value="False", SysFlag=YesNoEnum.Y, Remark="是否开启域登录验证", OrderNo=110, GroupCode="Default", CreateTime=DateTime.Parse("2022-02-10 00:00:00") }, new SysConfig{ Id=1300000000201, Name="开启域登录验证", Code="sys_domain_login", Value="False", SysFlag=YesNoEnum.Y, Remark="是否开启域登录验证", OrderNo=110, GroupCode="Default", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000211, Name="开启数据校验日志", Code="sys_validation_log", Value="True", SysFlag=YesNoEnum.Y, Remark="是否数据校验日志", OrderNo=120, GroupCode="Default", CreateTime=DateTime.Parse("2022-02-10 00:00:00") }, new SysConfig{ Id=1300000000211, Name="开启数据校验日志", Code="sys_validation_log", Value="True", SysFlag=YesNoEnum.Y, Remark="是否数据校验日志", OrderNo=120, GroupCode="Default", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000221, Name="系统主标题", Code="sys_web_title", Value="Admin.NET", SysFlag=YesNoEnum.Y, Remark="系统主标题", OrderNo=130, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") }, new SysConfig{ Id=1300000000221, Name="系统主标题", Code="sys_web_title", Value="Admin.NET.Pro", SysFlag=YesNoEnum.Y, Remark="系统主标题", OrderNo=130, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000231, Name="系统副标题", Code="sys_web_viceTitle", Value="Admin.NET", SysFlag=YesNoEnum.Y, Remark="系统副标题", OrderNo=140, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") }, new SysConfig{ Id=1300000000231, Name="系统副标题", Code="sys_web_viceTitle", Value="Admin.NET.Pro", SysFlag=YesNoEnum.Y, Remark="系统副标题", OrderNo=140, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000241, Name="系统描述", Code="sys_web_viceDesc", Value="站在巨人肩膀上的 .NET 通用权限开发框架", SysFlag=YesNoEnum.Y, Remark="系统描述", OrderNo=150, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") }, new SysConfig{ Id=1300000000241, Name="系统描述", Code="sys_web_viceDesc", Value="站在巨人肩膀上的 .NET 通用权限开发框架", SysFlag=YesNoEnum.Y, Remark="系统描述", OrderNo=150, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000251, Name="水印内容", Code="sys_web_watermark", Value="Admin.NET", SysFlag=YesNoEnum.Y, Remark="水印内容", OrderNo=160, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") }, new SysConfig{ Id=1300000000251, Name="水印内容", Code="sys_web_watermark", Value="Admin.NET.Pro", SysFlag=YesNoEnum.Y, Remark="水印内容", OrderNo=160, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000261, Name="版权说明", Code="sys_web_copyright", Value="Copyright © 2021-present Admin.NET All rights reserved.", SysFlag=YesNoEnum.Y, Remark="版权说明", OrderNo=170, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") }, new SysConfig{ Id=1300000000261, Name="版权说明", Code="sys_web_copyright", Value="Copyright © 2021-present Admin.NET All rights reserved.", SysFlag=YesNoEnum.Y, Remark="版权说明", OrderNo=170, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000271, Name="系统图标", Code="sys_web_logo", Value="/Upload/logo.png", SysFlag=YesNoEnum.Y, Remark="系统图标", OrderNo=180, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") }, new SysConfig{ Id=1300000000271, Name="系统图标", Code="sys_web_logo", Value="/Upload/logo.png", SysFlag=YesNoEnum.Y, Remark="系统图标", OrderNo=180, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000281, Name="ICP备案号", Code="sys_web_icp", Value="省ICP备12345678号", SysFlag=YesNoEnum.Y, Remark="ICP备案号", OrderNo=190, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") }, new SysConfig{ Id=1300000000281, Name="ICP备案号", Code="sys_web_icp", Value="省ICP备12345678号", SysFlag=YesNoEnum.Y, Remark="ICP备案号", OrderNo=190, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },

View File

@ -343,7 +343,7 @@ public class SysCodeGenService : IDynamicApiController, ITransient
PrintType = input.PrintType, PrintType = input.PrintType,
PrintName = input.PrintName, PrintName = input.PrintName,
}; };
//模板目录 // 模板目录
var templatePathList = GetTemplatePathList(input); var templatePathList = GetTemplatePathList(input);
var templatePath = Path.Combine(App.WebHostEnvironment.WebRootPath, "Template"); var templatePath = Path.Combine(App.WebHostEnvironment.WebRootPath, "Template");

View File

@ -7,30 +7,14 @@
namespace Admin.NET.Core.Service; namespace Admin.NET.Core.Service;
/// <summary> /// <summary>
/// 接口/动态API输出 /// 接口/动态API 树形列表
/// </summary> /// </summary>
public class ApiOutput public class ApiOutput
{ {
/// <summary> /// <summary>
/// 组名称 /// 名称(组名、路由名)
/// </summary> /// </summary>
public string GroupName { get; set; } public string Name { get; set; }
/// <summary>
/// 接口列表
/// </summary>
public List<ApiInfo> Apis { get; set; } = new List<ApiInfo>();
}
/// <summary>
/// 接口/动态API信息
/// </summary>
public class ApiInfo
{
/// <summary>
/// 接口名称
/// </summary>
public string DisplayName { get; set; }
/// <summary> /// <summary>
/// 路由 /// 路由
@ -43,17 +27,12 @@ public class ApiInfo
public string HttpMethod { get; set; } public string HttpMethod { get; set; }
/// <summary> /// <summary>
/// 控制器名称 /// 排序
/// </summary> /// </summary>
public string ControllerName { get; set; } public int Order { get; set; }
/// <summary> /// <summary>
/// 方法名称 /// 接口列表
/// </summary> /// </summary>
public string ActionName { get; set; } public List<ApiOutput> Children { get; set; } = new List<ApiOutput>();
///// <summary>
///// 组名称
///// </summary>
//public string GroupName { get; set; }
} }

View File

@ -77,32 +77,44 @@ public class SysCommonService : IDynamicApiController, ITransient
var apiOuput = new ApiOutput var apiOuput = new ApiOutput
{ {
GroupName = string.IsNullOrWhiteSpace(group.GroupName) ? "系统接口" : group.GroupName Name = string.IsNullOrWhiteSpace(group.GroupName) ? "系统接口" : group.GroupName,
Route = "",
}; };
// 获取接口分组的所有方法/接口 // 获取分组的所有接口
var actions = group.Items; var actions = group.Items;
foreach (ApiDescription action in actions) foreach (ApiDescription action in actions)
{ {
// 路由名称(去掉参数) // 路由
var routeName = action.RelativePath.Contains('{') ? action.RelativePath[..action.RelativePath.IndexOf('{')] : action.RelativePath; var route = action.RelativePath.Contains('{') ? action.RelativePath[..action.RelativePath.IndexOf('{')] : action.RelativePath; // 去掉路由参数
// 去掉路由前缀 route = route[(route.IndexOf('/') + 1)..]; // 去掉路由前缀
routeName = routeName[(routeName.IndexOf('/') + 1)..];
// 接口分组/控制器信息
var controllerActionDescriptor = action.ActionDescriptor as ControllerActionDescriptor; var controllerActionDescriptor = action.ActionDescriptor as ControllerActionDescriptor;
var displayName = controllerActionDescriptor.MethodInfo.GetCustomAttribute<DisplayNameAttribute>(true)?.DisplayName; var apiDescription = controllerActionDescriptor.ControllerTypeInfo.GetCustomAttribute<ApiDescriptionSettingsAttribute>(true);
var controllerName = controllerActionDescriptor.ControllerName;
apiOuput.Apis.Add(new ApiInfo if (!apiOuput.Children.Exists(u => u.Name == controllerName))
{ {
DisplayName = displayName, apiOuput.Children.Add(new ApiOutput
Route = routeName, {
Name = controllerName,
Route = "",
Order = apiDescription?.Order ?? 0,
});
}
// 接口信息
var apiController = apiOuput.Children.FirstOrDefault(u => u.Name.Equals(controllerName));
var displayName = controllerActionDescriptor.MethodInfo.GetCustomAttribute<DisplayNameAttribute>(true)?.DisplayName;
apiController.Children.Add(new ApiOutput
{
Name = displayName,
Route = route,
HttpMethod = action.HttpMethod, HttpMethod = action.HttpMethod,
ControllerName = controllerActionDescriptor.ControllerName, Order = apiDescription?.Order ?? 0,
ActionName = controllerActionDescriptor.ActionName,
//GroupName = string.IsNullOrWhiteSpace(action.GroupName) ? "Default" : action.GroupName,
}); });
// 按照控制器名称进行排序 // 接口分组/控制器排序
apiOuput.Apis = apiOuput.Apis.OrderBy(u => u.ControllerName).ToList(); apiOuput.Children = apiOuput.Children.OrderByDescending(u => u.Order).ToList();
} }
apiList.Add(apiOuput); apiList.Add(apiOuput);

View File

@ -69,7 +69,7 @@
"devDependencies": { "devDependencies": {
"@plugin-web-update-notification/vite": "^1.7.1", "@plugin-web-update-notification/vite": "^1.7.1",
"@types/lodash-es": "^4.17.12", "@types/lodash-es": "^4.17.12",
"@types/node": "^20.14.8", "@types/node": "^20.14.9",
"@types/nprogress": "^0.2.3", "@types/nprogress": "^0.2.3",
"@types/sortablejs": "^1.15.8", "@types/sortablejs": "^1.15.8",
"@typescript-eslint/eslint-plugin": "^7.14.1", "@typescript-eslint/eslint-plugin": "^7.14.1",

View File

@ -1,62 +0,0 @@
/* tslint:disable */
/* eslint-disable */
/**
* Admin.NET
* .NET <br/><u><b><font color='FF0000'> 👮</font></b></u>
*
* OpenAPI spec version: 1.0.0
*
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
/**
* /API信息
*
* @export
* @interface ApiInfo
*/
export interface ApiInfo {
/**
*
*
* @type {string}
* @memberof ApiInfo
*/
displayName?: string | null;
/**
*
*
* @type {string}
* @memberof ApiInfo
*/
route?: string | null;
/**
*
*
* @type {string}
* @memberof ApiInfo
*/
httpMethod?: string | null;
/**
*
*
* @type {string}
* @memberof ApiInfo
*/
controllerName?: string | null;
/**
*
*
* @type {string}
* @memberof ApiInfo
*/
actionName?: string | null;
}

View File

@ -12,9 +12,9 @@
* Do not edit the class manually. * Do not edit the class manually.
*/ */
import { ApiInfo } from './api-info'; import { ApiOutput } from './api-output';
/** /**
* /API输出 * /API
* *
* @export * @export
* @interface ApiOutput * @interface ApiOutput
@ -22,18 +22,42 @@ import { ApiInfo } from './api-info';
export interface ApiOutput { export interface ApiOutput {
/** /**
* *
* *
* @type {string} * @type {string}
* @memberof ApiOutput * @memberof ApiOutput
*/ */
groupName?: string | null; name?: string | null;
/**
*
*
* @type {string}
* @memberof ApiOutput
*/
route?: string | null;
/**
*
*
* @type {string}
* @memberof ApiOutput
*/
httpMethod?: string | null;
/**
*
*
* @type {number}
* @memberof ApiOutput
*/
order?: number;
/** /**
* *
* *
* @type {Array<ApiInfo>} * @type {Array<ApiOutput>}
* @memberof ApiOutput * @memberof ApiOutput
*/ */
apis?: Array<ApiInfo> | null; children?: Array<ApiOutput> | null;
} }

View File

@ -98,7 +98,6 @@ export * from './admin-result-visual-db-table';
export * from './admin-result-wechat-pay-output'; export * from './admin-result-wechat-pay-output';
export * from './admin-result-wx-open-id-output'; export * from './admin-result-wx-open-id-output';
export * from './admin-result-wx-phone-output'; export * from './admin-result-wx-phone-output';
export * from './api-info';
export * from './api-output'; export * from './api-output';
export * from './assembly'; export * from './assembly';
export * from './base-api-input'; export * from './base-api-input';

View File

@ -1,32 +1,47 @@
<template> <template>
<div class="sys-baseApi-container"> <div class="sys-baseApi-container">
<el-drawer v-model="state.isVisible" :title="state.drawerTitle" size="50%"> <el-drawer v-model="state.isVisible" :title="state.drawerTitle" size="35%">
<el-tabs v-loading="state.loading" v-model="state.selectedTabName" style="margin: 10px"> <el-card class="tree-card" shadow="hover" style="height: calc(100vh - 110px)" body-style="height:100%; overflow:auto">
<el-tab-pane v-for="(item, i) in state.allApiData" :label="item.groupName" :name="i"> <template #header>
<template #label> <div class="card-header">
<el-icon style="margin-right: 3px; display: inline; vertical-align: middle"><ele-Promotion /></el-icon> <div class="tree-h-flex">
<span>{{ item.groupName }}</span> <div class="tree-h-left">
</template> <el-input :prefix-icon="Search" v-model="filterText" placeholder="API路由" />
<el-table ref="tableRef" :data="item.apis" style="width: 100%" v-loading="state.loading" border @selection-change="handleSelectionChange" height="calc(100vh - 180px)"> </div>
<el-table-column type="selection" width="55" align="center" /> </div>
<el-table-column type="index" label="序号" width="55" align="center" /> </div>
<el-table-column prop="displayName" label="接口名称" min-width="170" header-align="center" show-overflow-tooltip /> </template>
<el-table-column prop="route" label="路由" min-width="300" header-align="center" show-overflow-tooltip /> <el-form-item v-loading="state.loading" style="margin-bottom: 45px">
<el-table-column prop="httpMethod" label="请求方式" min-width="80" align="center" show-overflow-tooltip> <el-row :gutter="24">
<template #default="scope"> <el-col :span="24" class="mb8">
<el-tag type="primary" v-if="scope.row.httpMethod === 'GET'">GET</el-tag> <el-tree
<el-tag type="success" v-else-if="scope.row.httpMethod === 'POST'">POST</el-tag> ref="treeRef"
<el-tag type="warning" v-else-if="scope.row.httpMethod === 'PUT'">PUT</el-tag> class="filter-tree"
<el-tag type="danger" v-else-if="scope.row.httpMethod === 'DELETE'">DELETE</el-tag> :data="state.allApiData"
<el-tag type="info" v-else>{{ scope.row.httpMethod }}</el-tag> :filter-node-method="filterNode"
</template> node-key="route"
</el-table-column> :props="{ children: 'children', label: 'name' }"
<el-table-column prop="controllerName" label="控制器" min-width="150" header-align="center" show-overflow-tooltip /> show-checkbox
<!-- <el-table-column prop="actionName" label="方法名" header-align="center" show-overflow-tooltip /> --> icon="ele-Menu"
<!-- <el-table-column prop="groupName" label="分组" min-width="150" header-align="center" show-overflow-tooltip /> --> highlight-current
</el-table> >
</el-tab-pane> <template #default="{ node, data }">
</el-tabs> <span v-if="node.level == 1 || node.level == 2">{{ node.label }}</span>
<span v-if="node.level == 3">
<el-icon style="margin-right: 3px; display: inline; vertical-align: middle"><ele-Link /></el-icon>
{{ node.label }} {{ node.key }}
<el-tag type="primary" v-if="data.httpMethod === 'GET'">GET</el-tag>
<el-tag type="success" v-else-if="data.httpMethod === 'POST'">POST</el-tag>
<el-tag type="warning" v-else-if="data.httpMethod === 'PUT'">PUT</el-tag>
<el-tag type="danger" v-else-if="data.httpMethod === 'DELETE'">DELETE</el-tag>
<el-tag type="info" v-else>{{ data.httpMethod }}</el-tag>
</span>
</template>
</el-tree>
</el-col>
</el-row>
</el-form-item>
</el-card>
<template #footer> <template #footer>
<div style="margin-bottom: 20px; margin-right: 20px"> <div style="margin-bottom: 20px; margin-right: 20px">
<el-button @click="cancel"> </el-button> <el-button @click="cancel"> </el-button>
@ -38,13 +53,14 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { reactive, ref } from 'vue'; import { reactive, onMounted, ref, watch } from 'vue';
import { ElTable } from 'element-plus'; import type { ElTree } from 'element-plus';
import { Search, MoreFilled } from '@element-plus/icons-vue';
import { getAPI } from '/@/utils/axios-utils'; import { getAPI } from '/@/utils/axios-utils';
import { SysCommonApi, SysRoleApi } from '/@/api-services/api'; import { SysCommonApi, SysRoleApi } from '/@/api-services/api';
const tableRef = ref<InstanceType<typeof ElTable>>() as any; const filterText = ref('');
const treeRef = ref<InstanceType<typeof ElTree>>();
const state = reactive({ const state = reactive({
loading: false, loading: false,
@ -56,47 +72,46 @@ const state = reactive({
selectedTabName: 0, selectedTabName: 0,
}); });
// onMounted(() => {
const openDrawer = () => { initTreeData();
state.selectedTabName = 0; });
state.drawerTitle = '基础接口资源';
state.isVisible = true;
handleQuery();
};
// watch(filterText, (val) => {
const handleQuery = async () => { treeRef.value!.filter(val);
// });
const initTreeData = async () => {
state.loading = true; state.loading = true;
var res = await getAPI(SysCommonApi).apiSysCommonApiListGet(); var res = await getAPI(SysCommonApi).apiSysCommonApiListGet();
state.allApiData = res.data.result ?? []; var tData = res.data.result ?? [];
treeRef.value?.setCheckedKeys([]); //
state.allApiData = tData;
state.loading = false;
};
//
const openDrawer = async () => {
state.selectedTabName = 0;
state.drawerTitle = '设置基础接口资源【免鉴权授权】';
state.isVisible = true;
state.loading = false; state.loading = false;
// //
state.loading = true;
var res1 = await getAPI(SysRoleApi).apiSysRoleBaseApiListGet(); var res1 = await getAPI(SysRoleApi).apiSysRoleBaseApiListGet();
state.ownApiList = res1.data.result ?? []; state.ownApiList = res1.data.result ?? [];
state.loading = false;
// setTimeout(() => {
if (state.ownApiList.length > 0) { treeRef.value?.setCheckedKeys(state.ownApiList ?? []);
for (let index = 0; index < state.ownApiList.length; index++) { }, 200);
for (let i = 0; i < state.allApiData.length; i++) {
var row = state.allApiData[i].apis.find((api: any) => api.route === state.ownApiList[index]); state.loading = false;
if (row != null) {
if (tableRef && tableRef.value != undefined && tableRef.value[i]) {
tableRef.value[i]!.toggleRowSelection(row, true);
}
break;
}
}
}
}
}; };
// const filterNode = (value: string, data: any) => {
const handleSelectionChange = (val: any) => { if (!value) return true;
state.selectRow = val; return data.route.includes(value);
}; };
// //
@ -106,15 +121,7 @@ const cancel = () => {
// //
const submit = async () => { const submit = async () => {
state.ownApiList = []; state.ownApiList = treeRef.value?.getCheckedKeys() as Array<string>;
for (let i = 0; i < state.allApiData.length; i++) {
if (tableRef.value != undefined && tableRef.value[i] && tableRef.value[i]!.getSelectionRows().length > 0) {
tableRef.value[i]!.getSelectionRows().forEach(function (item: any) {
state.ownApiList.push(item.route);
});
}
}
await getAPI(SysRoleApi).apiSysRoleSetBaseApiPost({ id: 0, apiList: state.ownApiList }); await getAPI(SysRoleApi).apiSysRoleSetBaseApiPost({ id: 0, apiList: state.ownApiList });
cancel(); cancel();
}; };

View File

@ -1,32 +1,47 @@
<template> <template>
<div class="sys-grantApi-container"> <div class="sys-grantApi-container">
<el-drawer v-model="state.isVisible" :title="state.drawerTitle" size="50%"> <el-drawer v-model="state.isVisible" :title="state.drawerTitle" size="35%">
<el-tabs v-loading="state.loading" v-model="state.selectedTabName" style="margin: 10px"> <el-card class="tree-card" shadow="hover" style="height: calc(100vh - 110px)" body-style="height:100%; overflow:auto">
<el-tab-pane v-for="(item, i) in state.allApiData" :label="item.groupName" :name="i"> <template #header>
<template #label> <div class="card-header">
<el-icon style="margin-right: 3px; display: inline; vertical-align: middle"><ele-Promotion /></el-icon> <div class="tree-h-flex">
<span>{{ item.groupName }}</span> <div class="tree-h-left">
</template> <el-input :prefix-icon="Search" v-model="filterText" placeholder="API路由" />
<el-table ref="tableRef" :data="item.apis" style="width: 100%" v-loading="state.loading" border @selection-change="handleSelectionChange" height="calc(100vh - 180px)"> </div>
<el-table-column type="selection" width="55" align="center" /> </div>
<el-table-column type="index" label="序号" width="55" align="center" /> </div>
<el-table-column prop="displayName" label="接口名称" min-width="170" header-align="center" show-overflow-tooltip /> </template>
<el-table-column prop="route" label="路由" min-width="300" header-align="center" show-overflow-tooltip /> <el-form-item v-loading="state.loading" style="margin-bottom: 45px">
<el-table-column prop="httpMethod" label="请求方式" min-width="80" align="center" show-overflow-tooltip> <el-row :gutter="24">
<template #default="scope"> <el-col :span="24" class="mb8">
<el-tag type="primary" v-if="scope.row.httpMethod === 'GET'">GET</el-tag> <el-tree
<el-tag type="success" v-else-if="scope.row.httpMethod === 'POST'">POST</el-tag> ref="treeRef"
<el-tag type="warning" v-else-if="scope.row.httpMethod === 'PUT'">PUT</el-tag> class="filter-tree"
<el-tag type="danger" v-else-if="scope.row.httpMethod === 'DELETE'">DELETE</el-tag> :data="state.allApiData"
<el-tag type="info" v-else>{{ scope.row.httpMethod }}</el-tag> :filter-node-method="filterNode"
</template> node-key="route"
</el-table-column> :props="{ children: 'children', label: 'name' }"
<el-table-column prop="controllerName" label="控制器" min-width="150" header-align="center" show-overflow-tooltip /> show-checkbox
<!-- <el-table-column prop="actionName" label="方法名" header-align="center" show-overflow-tooltip /> --> icon="ele-Menu"
<!-- <el-table-column prop="groupName" label="分组" min-width="150" header-align="center" show-overflow-tooltip /> --> highlight-current
</el-table> >
</el-tab-pane> <template #default="{ node, data }">
</el-tabs> <span v-if="node.level == 1 || node.level == 2">{{ node.label }}</span>
<span v-if="node.level == 3">
<el-icon style="margin-right: 3px; display: inline; vertical-align: middle"><ele-Link /></el-icon>
{{ node.label }} {{ node.key }}
<el-tag type="primary" v-if="data.httpMethod === 'GET'">GET</el-tag>
<el-tag type="success" v-else-if="data.httpMethod === 'POST'">POST</el-tag>
<el-tag type="warning" v-else-if="data.httpMethod === 'PUT'">PUT</el-tag>
<el-tag type="danger" v-else-if="data.httpMethod === 'DELETE'">DELETE</el-tag>
<el-tag type="info" v-else>{{ data.httpMethod }}</el-tag>
</span>
</template>
</el-tree>
</el-col>
</el-row>
</el-form-item>
</el-card>
<template #footer> <template #footer>
<div style="margin-bottom: 20px; margin-right: 20px"> <div style="margin-bottom: 20px; margin-right: 20px">
<el-button @click="cancel"> </el-button> <el-button @click="cancel"> </el-button>
@ -38,13 +53,14 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { reactive, ref } from 'vue'; import { reactive, onMounted, ref, watch } from 'vue';
import { ElTable } from 'element-plus'; import type { ElTree } from 'element-plus';
import { Search, MoreFilled } from '@element-plus/icons-vue';
import { getAPI } from '/@/utils/axios-utils'; import { getAPI } from '/@/utils/axios-utils';
import { SysCommonApi, SysRoleApi } from '/@/api-services/api'; import { SysCommonApi, SysRoleApi } from '/@/api-services/api';
const tableRef = ref<InstanceType<typeof ElTable>>() as any; const filterText = ref('');
const treeRef = ref<InstanceType<typeof ElTree>>();
const state = reactive({ const state = reactive({
loading: false, loading: false,
@ -57,48 +73,47 @@ const state = reactive({
selectedTabName: 0, selectedTabName: 0,
}); });
// onMounted(() => {
const openDrawer = (row: any) => { initTreeData();
state.selectedTabName = 0; });
state.roleId = row.id;
state.drawerTitle = '授权接口资源【' + row.name + '】';
state.isVisible = true;
handleQuery();
};
// watch(filterText, (val) => {
const handleQuery = async () => { treeRef.value!.filter(val);
// });
const initTreeData = async () => {
state.loading = true; state.loading = true;
var res = await getAPI(SysCommonApi).apiSysCommonApiListGet(); var res = await getAPI(SysCommonApi).apiSysCommonApiListGet();
state.allApiData = res.data.result ?? []; var tData = res.data.result ?? [];
treeRef.value?.setCheckedKeys([]); //
state.allApiData = tData;
state.loading = false;
};
//
const openDrawer = async (row: any) => {
state.selectedTabName = 0;
state.roleId = row.id;
state.drawerTitle = '授权角色接口资源【' + row.name + '】';
state.isVisible = true;
state.loading = false; state.loading = false;
// //
state.loading = true;
var res1 = await getAPI(SysRoleApi).apiSysRoleOwnApiListGet(state.roleId); var res1 = await getAPI(SysRoleApi).apiSysRoleOwnApiListGet(state.roleId);
state.ownApiList = res1.data.result ?? []; state.ownApiList = res1.data.result ?? [];
state.loading = false;
// setTimeout(() => {
if (state.ownApiList.length > 0) { treeRef.value?.setCheckedKeys(state.ownApiList ?? []);
for (let index = 0; index < state.ownApiList.length; index++) { }, 200);
for (let i = 0; i < state.allApiData.length; i++) {
var row = state.allApiData[i].apis.find((api: any) => api.route === state.ownApiList[index]); state.loading = false;
if (row != null) {
if (tableRef && tableRef.value != undefined && tableRef.value[i]) {
tableRef.value[i]!.toggleRowSelection(row, true);
}
break;
}
}
}
}
}; };
// const filterNode = (value: string, data: any) => {
const handleSelectionChange = (val: any) => { if (!value) return true;
state.selectRow = val; return data.route.includes(value);
}; };
// //
@ -108,15 +123,7 @@ const cancel = () => {
// //
const submit = async () => { const submit = async () => {
state.ownApiList = []; state.ownApiList = treeRef.value?.getCheckedKeys() as Array<string>;
for (let i = 0; i < state.allApiData.length; i++) {
if (tableRef.value != undefined && tableRef.value[i] && tableRef.value[i]!.getSelectionRows().length > 0) {
tableRef.value[i]!.getSelectionRows().forEach(function (item: any) {
state.ownApiList.push(item.route);
});
}
}
await getAPI(SysRoleApi).apiSysRoleGrantApiPost({ id: state.roleId, apiList: state.ownApiList }); await getAPI(SysRoleApi).apiSysRoleGrantApiPost({ id: state.roleId, apiList: state.ownApiList });
cancel(); cancel();
}; };