😎增加角色管理批量授权账号功能

This commit is contained in:
zuohuaijun 2025-02-06 12:28:19 +08:00
parent 18d8dfff19
commit 2d9ae4b676
16 changed files with 250 additions and 126 deletions

View File

@ -48,7 +48,7 @@
<PackageReference Include="SSH.NET" Version="2024.2.0" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.6.0.1" />
<PackageReference Include="System.Net.Http" Version="4.3.4" />
<PackageReference Include="TencentCloudSDK.Sms" Version="3.0.1173" />
<PackageReference Include="TencentCloudSDK.Sms" Version="3.0.1174" />
<PackageReference Include="UAParser" Version="3.1.47" />
<PackageReference Include="Yitter.IdGenerator" Version="1.0.14" />
</ItemGroup>

View File

@ -0,0 +1,18 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Core.Service;
/// <summary>
/// 授权角色表格
/// </summary>
public class RoleTableInput : BaseIdInput
{
/// <summary>
/// 表格字段集合
/// </summary>
public List<string> TableColumnList { get; set; }
}

View File

@ -27,15 +27,4 @@ public class TableColumnOutput
public string Pid { get; set; }
public string Name { get; set; }
public string Label { get; set; }
}
/// <summary>
/// 授权角色表格
/// </summary>
public class RoleTableInput : BaseIdInput
{
/// <summary>
/// 表格字段集合
/// </summary>
public List<string> TableColumnList { get; set; }
}

View File

@ -0,0 +1,18 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Core.Service;
/// <summary>
/// 授权角色用户
/// </summary>
public class RoleUserInput : BaseIdInput
{
/// <summary>
/// 用户Id集合
/// </summary>
public List<long> UserIdList { get; set; }
}

View File

@ -231,6 +231,9 @@ public class SysRoleService : IDynamicApiController, ITransient
}
break;
}
default:
break;
}
}
role.DataScope = (DataScopeEnum)dataScope;
@ -251,6 +254,18 @@ public class SysRoleService : IDynamicApiController, ITransient
await _sysRoleApiService.GrantRoleApi(input);
}
/// <summary>
/// 授权角色用户 🔖
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[UnitOfWork]
[DisplayName("授权角色用户")]
public async Task GrantUser(RoleUserInput input)
{
await _sysUserRoleService.GrantRoleUser(input);
}
/// <summary>
/// 设置角色状态 🔖
/// </summary>

View File

@ -28,12 +28,29 @@ public class SysUserRoleService : ITransient
await _sysUserRoleRep.DeleteAsync(u => u.UserId == input.UserId);
if (input.RoleIdList == null || input.RoleIdList.Count < 1) return;
var roles = input.RoleIdList.Select(u => new SysUserRole
var userRoles = input.RoleIdList.Select(u => new SysUserRole
{
UserId = input.UserId,
RoleId = u
}).ToList();
await _sysUserRoleRep.InsertRangeAsync(roles);
await _sysUserRoleRep.InsertRangeAsync(userRoles);
}
/// <summary>
/// 授权角色用户
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task GrantRoleUser(RoleUserInput input)
{
await _sysUserRoleRep.AsDeleteable().Where(u => input.UserIdList.Contains(u.UserId)).ExecuteCommandAsync();
var userRoles = input.UserIdList.Select(u => new SysUserRole
{
UserId = u,
RoleId = input.Id
}).ToList();
await _sysUserRoleRep.InsertRangeAsync(userRoles);
}
/// <summary>

View File

@ -2,7 +2,7 @@
"name": "admin.net.pro",
"type": "module",
"version": "2.4.33",
"lastBuildTime": "2025.02.04",
"lastBuildTime": "2025.02.06",
"description": "Admin.NET 站在巨人肩膀上的 .NET 通用权限开发框架",
"author": "zuohuaijun",
"license": "MIT",
@ -100,10 +100,10 @@
"less": "^4.2.2",
"prettier": "^3.4.2",
"rollup-plugin-visualizer": "^5.14.0",
"sass": "^1.83.4",
"terser": "^5.37.0",
"sass": "^1.84.0",
"terser": "^5.38.0",
"typescript": "^5.7.3",
"vite": "^6.0.11",
"vite": "^6.1.0",
"vite-plugin-cdn-import": "^1.0.1",
"vite-plugin-compression2": "^1.3.3",
"vite-plugin-vue-setup-extend": "^0.4.0",

View File

@ -21,7 +21,6 @@ import { AdminNETResultBoolean } from '../models';
import { AdminNETResultCaptchaOutput } from '../models';
import { AdminNETResultLoginOutput } from '../models';
import { AdminNETResultLoginUserOutput } from '../models';
import { AdminNETResultString } from '../models';
import { LoginInput } from '../models';
import { LoginPhoneInput } from '../models';
/**
@ -320,54 +319,6 @@ export const SysAuthApiAxiosParamCreator = function (configuration?: Configurati
options: localVarRequestOptions,
};
},
/**
*
* @summary Token 🔖
* @param {string} [accessToken]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
apiSysAuthRefreshTokenGet: async (accessToken?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/api/sysAuth/refreshToken`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, 'https://example.com');
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions :AxiosRequestConfig = { method: 'GET', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication Bearer required
// http bearer authentication required
if (configuration && configuration.accessToken) {
const accessToken = typeof configuration.accessToken === 'function'
? await configuration.accessToken()
: await configuration.accessToken;
localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
}
if (accessToken !== undefined) {
localVarQueryParameter['accessToken'] = accessToken;
}
const query = new URLSearchParams(localVarUrlObj.search);
for (const key in localVarQueryParameter) {
query.set(key, localVarQueryParameter[key]);
}
for (const key in options.params) {
query.set(key, options.params[key]);
}
localVarUrlObj.search = (new URLSearchParams(query)).toString();
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
return {
url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
options: localVarRequestOptions,
};
},
/**
*
* @summary 🔖
@ -554,20 +505,6 @@ export const SysAuthApiFp = function(configuration?: Configuration) {
return axios.request(axiosRequestArgs);
};
},
/**
*
* @summary Token 🔖
* @param {string} [accessToken]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysAuthRefreshTokenGet(accessToken?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminNETResultString>>> {
const localVarAxiosArgs = await SysAuthApiAxiosParamCreator(configuration).apiSysAuthRefreshTokenGet(accessToken, options);
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
return axios.request(axiosRequestArgs);
};
},
/**
*
* @summary 🔖
@ -662,16 +599,6 @@ export const SysAuthApiFactory = function (configuration?: Configuration, basePa
async apiSysAuthLogoutPost(options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
return SysAuthApiFp(configuration).apiSysAuthLogoutPost(options).then((request) => request(axios, basePath));
},
/**
*
* @summary Token 🔖
* @param {string} [accessToken]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysAuthRefreshTokenGet(accessToken?: string, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminNETResultString>> {
return SysAuthApiFp(configuration).apiSysAuthRefreshTokenGet(accessToken, options).then((request) => request(axios, basePath));
},
/**
*
* @summary 🔖
@ -765,17 +692,6 @@ export class SysAuthApi extends BaseAPI {
public async apiSysAuthLogoutPost(options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
return SysAuthApiFp(this.configuration).apiSysAuthLogoutPost(options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @summary Token 🔖
* @param {string} [accessToken]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof SysAuthApi
*/
public async apiSysAuthRefreshTokenGet(accessToken?: string, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminNETResultString>> {
return SysAuthApiFp(this.configuration).apiSysAuthRefreshTokenGet(accessToken, options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @summary 🔖

View File

@ -32,6 +32,7 @@ import { RoleInput } from '../models';
import { RoleMenuInput } from '../models';
import { RoleOrgInput } from '../models';
import { RoleTableInput } from '../models';
import { RoleUserInput } from '../models';
import { StatusEnum } from '../models';
import { UpdateRoleInput } from '../models';
/**
@ -371,6 +372,54 @@ export const SysRoleApiAxiosParamCreator = function (configuration?: Configurati
options: localVarRequestOptions,
};
},
/**
*
* @summary 🔖
* @param {RoleUserInput} [body]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
apiSysRoleGrantUserPost: async (body?: RoleUserInput, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/api/sysRole/grantUser`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, 'https://example.com');
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions :AxiosRequestConfig = { method: 'POST', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication Bearer required
// http bearer authentication required
if (configuration && configuration.accessToken) {
const accessToken = typeof configuration.accessToken === 'function'
? await configuration.accessToken()
: await configuration.accessToken;
localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
}
localVarHeaderParameter['Content-Type'] = 'application/json-patch+json';
const query = new URLSearchParams(localVarUrlObj.search);
for (const key in localVarQueryParameter) {
query.set(key, localVarQueryParameter[key]);
}
for (const key in options.params) {
query.set(key, options.params[key]);
}
localVarUrlObj.search = (new URLSearchParams(query)).toString();
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
const needsSerialization = (typeof body !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json';
localVarRequestOptions.data = needsSerialization ? JSON.stringify(body !== undefined ? body : {}) : (body || "");
return {
url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
options: localVarRequestOptions,
};
},
/**
*
* @summary 🔖
@ -970,6 +1019,20 @@ export const SysRoleApiFp = function(configuration?: Configuration) {
return axios.request(axiosRequestArgs);
};
},
/**
*
* @summary 🔖
* @param {RoleUserInput} [body]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysRoleGrantUserPost(body?: RoleUserInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
const localVarAxiosArgs = await SysRoleApiAxiosParamCreator(configuration).apiSysRoleGrantUserPost(body, options);
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
return axios.request(axiosRequestArgs);
};
},
/**
*
* @summary 🔖
@ -1188,6 +1251,16 @@ export const SysRoleApiFactory = function (configuration?: Configuration, basePa
async apiSysRoleGrantRoleTablePost(body?: RoleTableInput, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
return SysRoleApiFp(configuration).apiSysRoleGrantRoleTablePost(body, options).then((request) => request(axios, basePath));
},
/**
*
* @summary 🔖
* @param {RoleUserInput} [body]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysRoleGrantUserPost(body?: RoleUserInput, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
return SysRoleApiFp(configuration).apiSysRoleGrantUserPost(body, options).then((request) => request(axios, basePath));
},
/**
*
* @summary 🔖
@ -1374,6 +1447,17 @@ export class SysRoleApi extends BaseAPI {
public async apiSysRoleGrantRoleTablePost(body?: RoleTableInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
return SysRoleApiFp(this.configuration).apiSysRoleGrantRoleTablePost(body, options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @summary 🔖
* @param {RoleUserInput} [body]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof SysRoleApi
*/
public async apiSysRoleGrantUserPost(body?: RoleUserInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
return SysRoleApiFp(this.configuration).apiSysRoleGrantUserPost(body, options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @summary 🔖

View File

@ -325,6 +325,7 @@ export * from './role-org-input';
export * from './role-output';
export * from './role-table-input';
export * from './role-table-output';
export * from './role-user-input';
export * from './runtime-field-handle';
export * from './runtime-method-handle';
export * from './runtime-type-handle';

View File

@ -0,0 +1,38 @@
/* 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.
*/
/**
*
*
* @export
* @interface RoleUserInput
*/
export interface RoleUserInput {
/**
* Id
*
* @type {number}
* @memberof RoleUserInput
*/
id: number;
/**
* Id集合
*
* @type {Array<number>}
* @memberof RoleUserInput
*/
userIdList?: Array<number> | null;
}

View File

@ -1,5 +1,5 @@
<template>
<el-dialog draggable v-model="visibleDialog" style="width: 70vw" append-to-body>
<el-dialog v-model="visibleDialog" style="width: 70vw" append-to-body draggable :close-on-click-modal="false">
<template #header>
<div style="color: #fff">
<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"> <ele-Edit /> </el-icon>
@ -188,8 +188,9 @@ const closeDialog = () => {
<style lang="scss" scoped>
.tip {
padding: 8px 16px;
background-color: rgb(197.7, 225.9, 255);
border-left: 5px solid #409eff;
background-color: var(--el-color-primary-light-9);
border-left: 5px solid var(--el-color-primary);
margin-bottom: 5px;
}
.boxHeight {

View File

@ -1,5 +1,5 @@
<template>
<el-dialog draggable v-model="visibleDialog" style="width: 70vw" append-to-body>
<el-dialog v-model="visibleDialog" style="width: 70vw" append-to-body draggable :close-on-click-modal="false">
<template #header>
<div style="color: #fff">
<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"> <ele-Edit /> </el-icon>
@ -207,8 +207,9 @@ const closeDialog = () => {
<style lang="scss" scoped>
.tip {
padding: 8px 16px;
background-color: rgb(197.7, 225.9, 255);
border-left: 5px solid #409eff;
background-color: var(--el-color-primary-light-9);
border-left: 5px solid var(--el-color-primary);
margin-bottom: 5px;
}
.boxHeight {

View File

@ -1,5 +1,5 @@
<template>
<el-dialog draggable v-model="visibleDialog" style="width: 70vw" append-to-body>
<el-dialog v-model="visibleDialog" style="width: 70vw" append-to-body draggable :close-on-click-modal="false">
<template #header>
<div style="color: #fff">
<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"> <ele-Edit /> </el-icon>
@ -210,8 +210,9 @@ const closeDialog = () => {
<style lang="scss" scoped>
.tip {
padding: 8px 16px;
background-color: rgb(197.7, 225.9, 255);
border-left: 5px solid #409eff;
background-color: var(--el-color-primary-light-9);
border-left: 5px solid var(--el-color-primary);
margin-bottom: 5px;
}
.boxHeight {

View File

@ -1,5 +1,5 @@
<template>
<el-dialog draggable v-model="visibleDialog" style="width: 70vw" append-to-body>
<el-dialog v-model="visibleDialog" style="width: 70vw" append-to-body draggable :close-on-click-modal="false">
<template #header>
<div style="color: #fff">
<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"> <ele-Edit /> </el-icon>
@ -25,8 +25,8 @@
</el-button-group>
</el-form-item>
</el-form>
<el-card class="full-table" shadow="hover" style="margin-top: 5px">
<el-table ref="refTable" :data="userList" style="height: calc(60vh - 100px)">
<el-card class="full-table" shadow="hover">
<el-table ref="refTable" :data="userList" style="height: calc(60vh - 96px)">
<el-table-column label="操作" width="60" align="center">
<template #default="scope">
<el-button link type="primary" @click="handleSelectUser(scope.row)">
@ -34,9 +34,10 @@
</el-button>
</template>
</el-table-column>
<el-table-column label="用户名称" prop="realName" width="100" align="center" :show-overflow-tooltip="true" />
<el-table-column label="联系方式" prop="phone" width="120" align="center" :show-overflow-tooltip="true" />
<el-table-column label="账号类型" prop="roleName" />
<el-table-column label="账号名称" prop="account" align="center" :show-overflow-tooltip="true" />
<el-table-column label="真实姓名" prop="realName" align="center" :show-overflow-tooltip="true" />
<el-table-column label="联系方式" prop="phone" align="center" :show-overflow-tooltip="true" />
<el-table-column label="所属机构" prop="orgName" align="center" :show-overflow-tooltip="true" />
</el-table>
<el-pagination
@ -48,6 +49,7 @@
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
layout="total, sizes, prev, pager, next, jumper"
style="padding-bottom: 8px"
/>
</el-card>
</div>
@ -62,14 +64,15 @@
</div>
</template>
</el-table-column>
<el-table-column label="账号名称" prop="account" :show-overflow-tooltip="true" />
<el-table-column label="用户名称" prop="realName" :show-overflow-tooltip="true" />
</el-table>
</el-col>
</el-row>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="saveDialog"> </el-button>
<el-button @click="closeDialog"> </el-button>
<el-button icon="ele-CircleCloseFilled" @click="closeDialog"> </el-button>
<el-button type="primary" icon="ele-CircleCheckFilled" @click="saveDialog"> </el-button>
</div>
</template>
</el-dialog>
@ -83,6 +86,7 @@ import OrgTree from '/@/views/system/org/component/orgTree.vue';
import { getAPI } from '/@/utils/axios-utils';
import { SysUserApi } from '/@/api-services/api';
import { A } from 'ol/renderer/webgl/FlowLayer';
let emits = defineEmits(['update:visible', 'change']);
const props = defineProps({
@ -122,8 +126,9 @@ watch(
if (newVal) {
checkedUsersList.value = props.data.map((item: any) => {
return {
id: item.targetId,
realName: item.name,
id: item.id,
account: item.account,
realName: item.realName,
};
});
}
@ -185,8 +190,9 @@ function handleRemove(row: { id: any }) {
let saveDialog = () => {
let checkedList = [...checkedUsersList.value].map((item) => ({
type: 1,
targetId: item.id,
name: item.realName,
id: item.id,
account: item.account,
realName: item.realName,
}));
emits('change', checkedList);
};
@ -213,8 +219,9 @@ const closeDialog = () => {
<style lang="scss" scoped>
.tip {
padding: 8px 16px;
background-color: rgb(197.7, 225.9, 255);
border-left: 5px solid #409eff;
background-color: var(--el-color-primary-light-9);
border-left: 5px solid var(--el-color-primary);
margin-bottom: 5px;
}
.boxHeight {

View File

@ -62,6 +62,7 @@
<el-button icon="ele-OfficeBuilding" size="small" text type="primary" @click="openGrantData(row)" v-auth="'sysRole/grantDataScope'">授权数据</el-button>
<el-button icon="ele-Grid" size="small" text type="primary" @click="openGrantTable(row)" v-auth="'sysRole/grantTable'">字段黑名单</el-button>
<el-button icon="ele-Link" size="small" text type="primary" @click="openGrantApi(row)" v-auth="'sysRole/grantApi'"> 接口黑名单 </el-button>
<el-button icon="ele-User" size="small" text type="primary" @click="openGrantUser(row)" v-auth="'sysRole/grantApi'"> 授权账号 </el-button>
</template>
</vxe-grid>
</el-card>
@ -71,6 +72,7 @@
<GrantTable ref="grantTableRef" />
<GrantData ref="grantDataRef" @handleQuery="handleQuery" />
<GrantApi ref="grantApiRef" />
<GrantUser v-model:visible="state.grantUserVisible" @change="closeGrantUser" />
</div>
</template>
@ -86,6 +88,7 @@ import GrantMenu from '/@/views/system/role/component/grantMenu.vue';
import GrantTable from '/@/views/system/role/component/grantTable.vue';
import GrantData from '/@/views/system/role/component/grantData.vue';
import GrantApi from '/@/views/system/role/component/grantApi.vue';
import GrantUser from '/@/components/selector/userSelectorDialog.vue';
import ModifyRecord from '/@/components/table/modifyRecord.vue';
import { getAPI } from '/@/utils/axios-utils';
@ -109,6 +112,8 @@ const state = reactive({
},
visible: false,
title: '',
grantUserVisible: false, //
roleRow: {} as any, //
});
//
@ -128,7 +133,7 @@ const options = useVxeTable<PageRoleOutput>(
{ field: 'orderNo', title: '排序', width: 80, showOverflow: 'tooltip' },
{ field: 'status', title: '状态', width: 80, showOverflow: 'tooltip', slots: { default: 'row_status' } },
{ field: 'record', title: '修改记录', width: 100, showOverflow: 'tooltip', slots: { default: 'row_record' } },
{ field: 'buttons', title: '操作', fixed: 'right', width: 440, showOverflow: true, slots: { default: 'row_buttons' } },
{ field: 'buttons', title: '操作', fixed: 'right', width: 520, showOverflow: true, slots: { default: 'row_buttons' } },
],
},
// vxeGrid()vxe-table
@ -229,4 +234,17 @@ const openGrantData = (row: any) => {
const openGrantApi = (row: any) => {
grantApiRef.value?.openDrawer(row);
};
//
const openGrantUser = (row: any) => {
state.roleRow = row;
state.grantUserVisible = true;
};
//
const closeGrantUser = (data: any) => {
var userIds = data.map((u: any) => u.id);
getAPI(SysRoleApi).apiSysRoleGrantUserPost({ id: state.roleRow.id, userIdList: userIds });
state.grantUserVisible = false;
};
</script>