From 6cbc2ddc14df9cf1ccd42de18fcaf5590cce4c5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=86=99=E6=84=8F?= Date: Sun, 6 Apr 2025 07:56:48 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=A7=92=E8=89=B2=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=A4=8D=E5=88=B6=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Service/Role/Dto/RoleInput.cs | 4 + .../Service/Role/SysRoleApiService.cs | 17 ++++ .../Service/Role/SysRoleMenuService.cs | 17 ++++ .../Service/Role/SysRoleOrgService.cs | 17 ++++ .../Service/Role/SysRoleService.cs | 42 ++++++++++ .../Service/Role/SysRoleTableService.cs | 30 +++++++ Web/src/api-services/apis/sys-role-api.ts | 84 +++++++++++++++++++ .../api-services/models/copy-role-input.ts | 30 +++++++ Web/src/api-services/models/index.ts | 1 + Web/src/i18n/pages/systemMenu/zh-CN.ts | 5 +- Web/src/views/system/role/index.vue | 22 ++++- 11 files changed, 266 insertions(+), 3 deletions(-) create mode 100644 Web/src/api-services/models/copy-role-input.ts diff --git a/Admin.NET/Admin.NET.Core/Service/Role/Dto/RoleInput.cs b/Admin.NET/Admin.NET.Core/Service/Role/Dto/RoleInput.cs index 33f83902..fa091a6e 100644 --- a/Admin.NET/Admin.NET.Core/Service/Role/Dto/RoleInput.cs +++ b/Admin.NET/Admin.NET.Core/Service/Role/Dto/RoleInput.cs @@ -42,4 +42,8 @@ public class UpdateRoleInput : AddRoleInput public class DeleteRoleInput : BaseIdInput { +} + +public class CopyRoleInput : BaseIdInput +{ } \ No newline at end of file diff --git a/Admin.NET/Admin.NET.Core/Service/Role/SysRoleApiService.cs b/Admin.NET/Admin.NET.Core/Service/Role/SysRoleApiService.cs index fce11594..f33af6a6 100644 --- a/Admin.NET/Admin.NET.Core/Service/Role/SysRoleApiService.cs +++ b/Admin.NET/Admin.NET.Core/Service/Role/SysRoleApiService.cs @@ -59,4 +59,21 @@ public class SysRoleApiService : ITransient { await _sysRoleApiRep.DeleteAsync(u => u.RoleId == roleId); } + + /// + /// 根据角色Id复制角色接口 + /// + /// + /// + /// + public async Task CopyRoleApiByRoleId(long roleId, long newRoleId) + { + var roleApiList = await _sysRoleApiRep.GetListAsync(u => u.RoleId == roleId); + roleApiList.ForEach(u => + { + u.Id = 0; + u.RoleId = newRoleId; + }); + await _sysRoleApiRep.InsertRangeAsync(roleApiList); + } } \ No newline at end of file diff --git a/Admin.NET/Admin.NET.Core/Service/Role/SysRoleMenuService.cs b/Admin.NET/Admin.NET.Core/Service/Role/SysRoleMenuService.cs index c6a2e019..77ccca2c 100644 --- a/Admin.NET/Admin.NET.Core/Service/Role/SysRoleMenuService.cs +++ b/Admin.NET/Admin.NET.Core/Service/Role/SysRoleMenuService.cs @@ -65,4 +65,21 @@ public class SysRoleMenuService : ITransient { await _sysRoleMenuRep.DeleteAsync(u => u.RoleId == roleId); } + + /// + /// 根据角色Id复制角色菜单 + /// + /// + /// + /// + public async Task CopyRoleMenuByRoleId(long roleId, long newRoleId) + { + var roleMenuList = await _sysRoleMenuRep.GetListAsync(u => u.RoleId == roleId); + roleMenuList.ForEach(u => + { + u.Id = 0; + u.RoleId = newRoleId; + }); + await _sysRoleMenuRep.InsertRangeAsync(roleMenuList); + } } \ No newline at end of file diff --git a/Admin.NET/Admin.NET.Core/Service/Role/SysRoleOrgService.cs b/Admin.NET/Admin.NET.Core/Service/Role/SysRoleOrgService.cs index fe077447..6da7b30e 100644 --- a/Admin.NET/Admin.NET.Core/Service/Role/SysRoleOrgService.cs +++ b/Admin.NET/Admin.NET.Core/Service/Role/SysRoleOrgService.cs @@ -72,4 +72,21 @@ public class SysRoleOrgService : ITransient { await _sysRoleOrgRep.DeleteAsync(u => u.RoleId == roleId); } + + /// + /// 根据角色Id复制角色机构 + /// + /// + /// + /// + public async Task CopyRoleOrgByRoleId(long roleId, long newRoleId) + { + var roleOrgList = await _sysRoleOrgRep.GetListAsync(u => u.RoleId == roleId); + roleOrgList.ForEach(u => + { + u.Id = 0; + u.RoleId = newRoleId; + }); + await _sysRoleOrgRep.InsertRangeAsync(roleOrgList); + } } \ No newline at end of file diff --git a/Admin.NET/Admin.NET.Core/Service/Role/SysRoleService.cs b/Admin.NET/Admin.NET.Core/Service/Role/SysRoleService.cs index f36278d8..28f57fd8 100644 --- a/Admin.NET/Admin.NET.Core/Service/Role/SysRoleService.cs +++ b/Admin.NET/Admin.NET.Core/Service/Role/SysRoleService.cs @@ -159,6 +159,48 @@ public class SysRoleService : IDynamicApiController, ITransient // 级联删除角色接口数据 await _sysRoleApiService.DeleteRoleApiByRoleId(sysRole.Id); + + // 级联删除角色表格数据 + await _sysRoleTableService.DeleteRolTableByRoleId(sysRole.Id); + } + + /// + /// 复制角色 🔖 + /// + /// + /// + [UnitOfWork] + [ApiDescriptionSettings(Name = "Copy"), HttpPost] + [DisplayName("复制角色")] + public async Task CopyRole(CopyRoleInput input) + { + // 查找角色 + var sysRole = await _sysRoleRep.GetByIdAsync(input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D1002); + + // 新增角色 + var newRoleId = YitIdHelper.NextId(); + sysRole.Id = newRoleId; + sysRole.Code = $"{sysRole.Code} - copy"; + sysRole.Name = $"{sysRole.Name} - copy"; + sysRole.CreateTime = DateTime.Now; + sysRole.CreateUserId = null; + sysRole.CreateUserName = null; + sysRole.UpdateTime = null; + sysRole.UpdateUserId = null; + sysRole.UpdateUserName = null; + await _sysRoleRep.InsertAsync(sysRole); + + // 复制角色数据范围 + await _sysRoleOrgService.CopyRoleOrgByRoleId(input.Id, newRoleId); + + // 复制角色菜单数据 + await _sysRoleMenuService.CopyRoleMenuByRoleId(input.Id, newRoleId); + + // 复制角色接口数据 + await _sysRoleApiService.CopyRoleApiByRoleId(input.Id, newRoleId); + + // 复制角色表格数据 + await _sysRoleTableService.CopyRolTableByRoleId(input.Id, newRoleId); } /// diff --git a/Admin.NET/Admin.NET.Core/Service/Role/SysRoleTableService.cs b/Admin.NET/Admin.NET.Core/Service/Role/SysRoleTableService.cs index 1f45691d..c663e5fb 100644 --- a/Admin.NET/Admin.NET.Core/Service/Role/SysRoleTableService.cs +++ b/Admin.NET/Admin.NET.Core/Service/Role/SysRoleTableService.cs @@ -59,6 +59,7 @@ public class SysRoleTableService : ITransient sysRoleTableList.Add(sysRoleTable); } } + await _sysRoleTableRep.InsertRangeAsync(sysRoleTableList); } @@ -139,10 +140,12 @@ public class SysRoleTableService : ITransient }; columnList.Add(column); } + table.Columns = columnList; roleTableList.Add(table); } } + return roleTableList; } @@ -155,4 +158,31 @@ public class SysRoleTableService : ITransient { return string.IsNullOrWhiteSpace(propertyName) ? null : propertyName[..1].ToLower() + propertyName[1..]; } + + /// + /// 根据角色Id删除角色表格 + /// + /// + /// + public async Task DeleteRolTableByRoleId(long roleId) + { + await _sysRoleTableRep.DeleteAsync(u => u.RoleId == roleId); + } + + /// + /// 根据角色Id复制角色表格 + /// + /// + /// + /// + public async Task CopyRolTableByRoleId(long roleId, long newRoleId) + { + var roleTableList = await _sysRoleTableRep.GetListAsync(u => u.RoleId == roleId); + roleTableList.ForEach(u => + { + u.Id = 0; + u.RoleId = newRoleId; + }); + await _sysRoleTableRep.InsertRangeAsync(roleTableList); + } } \ No newline at end of file diff --git a/Web/src/api-services/apis/sys-role-api.ts b/Web/src/api-services/apis/sys-role-api.ts index 18585b36..6648fc73 100644 --- a/Web/src/api-services/apis/sys-role-api.ts +++ b/Web/src/api-services/apis/sys-role-api.ts @@ -25,6 +25,7 @@ import { AdminNETResultListRoleOutput } from '../models'; import { AdminNETResultListRoleTableOutput } from '../models'; import { AdminNETResultListString } from '../models'; import { AdminNETResultSqlSugarPagedListPageRoleOutput } from '../models'; +import { CopyRoleInput } from '../models'; import { DeleteRoleInput } from '../models'; import { PageRoleInput } from '../models'; import { RoleApiInput } from '../models'; @@ -132,6 +133,54 @@ export const SysRoleApiAxiosParamCreator = function (configuration?: Configurati options: localVarRequestOptions, }; }, + /** + * + * @summary 复制角色 🔖 + * @param {CopyRoleInput} [body] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + apiSysRoleCopyPost: async (body?: CopyRoleInput, options: AxiosRequestConfig = {}): Promise => { + const localVarPath = `/api/sysRole/copy`; + // 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 删除角色 🔖 @@ -949,6 +998,20 @@ export const SysRoleApiFp = function(configuration?: Configuration) { return axios.request(axiosRequestArgs); }; }, + /** + * + * @summary 复制角色 🔖 + * @param {CopyRoleInput} [body] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async apiSysRoleCopyPost(body?: CopyRoleInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise>> { + const localVarAxiosArgs = await SysRoleApiAxiosParamCreator(configuration).apiSysRoleCopyPost(body, options); + return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => { + const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url}; + return axios.request(axiosRequestArgs); + }; + }, /** * * @summary 删除角色 🔖 @@ -1201,6 +1264,16 @@ export const SysRoleApiFactory = function (configuration?: Configuration, basePa async apiSysRoleAllTableColumnListGet(options?: AxiosRequestConfig): Promise> { return SysRoleApiFp(configuration).apiSysRoleAllTableColumnListGet(options).then((request) => request(axios, basePath)); }, + /** + * + * @summary 复制角色 🔖 + * @param {CopyRoleInput} [body] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async apiSysRoleCopyPost(body?: CopyRoleInput, options?: AxiosRequestConfig): Promise> { + return SysRoleApiFp(configuration).apiSysRoleCopyPost(body, options).then((request) => request(axios, basePath)); + }, /** * * @summary 删除角色 🔖 @@ -1392,6 +1465,17 @@ export class SysRoleApi extends BaseAPI { public async apiSysRoleAllTableColumnListGet(options?: AxiosRequestConfig) : Promise> { return SysRoleApiFp(this.configuration).apiSysRoleAllTableColumnListGet(options).then((request) => request(this.axios, this.basePath)); } + /** + * + * @summary 复制角色 🔖 + * @param {CopyRoleInput} [body] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof SysRoleApi + */ + public async apiSysRoleCopyPost(body?: CopyRoleInput, options?: AxiosRequestConfig) : Promise> { + return SysRoleApiFp(this.configuration).apiSysRoleCopyPost(body, options).then((request) => request(this.axios, this.basePath)); + } /** * * @summary 删除角色 🔖 diff --git a/Web/src/api-services/models/copy-role-input.ts b/Web/src/api-services/models/copy-role-input.ts new file mode 100644 index 00000000..7b0e5f43 --- /dev/null +++ b/Web/src/api-services/models/copy-role-input.ts @@ -0,0 +1,30 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Admin.NET 通用权限开发平台 + * 让 .NET 开发更简单、更通用、更流行。整合最新技术,模块插件式开发,前后端分离,开箱即用。
👮不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! + * + * 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 CopyRoleInput + */ +export interface CopyRoleInput { + + /** + * 主键Id + * + * @type {number} + * @memberof CopyRoleInput + */ + id: number; +} diff --git a/Web/src/api-services/models/index.ts b/Web/src/api-services/models/index.ts index 9484c9ad..2f4cd6ea 100644 --- a/Web/src/api-services/models/index.ts +++ b/Web/src/api-services/models/index.ts @@ -162,6 +162,7 @@ export * from './column-relation'; export * from './compare-info'; export * from './const-output'; export * from './constructor-info'; +export * from './copy-role-input'; export * from './create-entity-input'; export * from './create-pay-transaction-native-output'; export * from './create-pay-transaction-output'; diff --git a/Web/src/i18n/pages/systemMenu/zh-CN.ts b/Web/src/i18n/pages/systemMenu/zh-CN.ts index ece1e0fa..c4d95644 100644 --- a/Web/src/i18n/pages/systemMenu/zh-CN.ts +++ b/Web/src/i18n/pages/systemMenu/zh-CN.ts @@ -349,6 +349,9 @@ export default { currentProgress:"当前进度", welcomein:'欢迎使用 Admin.NET 通用权限开发框架', emailRequired:"邮箱不能为空", - emailNotMatch:"邮箱与账号必须要相同" + emailNotMatch:"邮箱与账号必须要相同", + confirmCopyRole: '确定复制角色:【{roleName}】?', + authAccount: '授权账号', + successCopy: '复制成功', } }; diff --git a/Web/src/views/system/role/index.vue b/Web/src/views/system/role/index.vue index 0ddcd4f5..6a8f7ecb 100644 --- a/Web/src/views/system/role/index.vue +++ b/Web/src/views/system/role/index.vue @@ -58,11 +58,14 @@ + + + {{ $t('message.list.authMenu') }} {{ $t('message.list.authData') }} {{ $t('message.list.fieldBlacklist') }} {{ $t('message.list.apiBlacklist') }} - 授权账号 + {{ $t('message.list.authAccount') }} @@ -136,7 +139,7 @@ const options = useVxeTable( { field: 'orderNo', title: i18n.t('message.list.orderNo'), width: 80, showOverflow: 'tooltip' }, { field: 'status', title: i18n.t('message.list.status'), width: 80, showOverflow: 'tooltip', slots: { default: 'row_status' } }, { field: 'record', title: i18n.t('message.list.record'), width: 100, showOverflow: 'tooltip', slots: { default: 'row_record' } }, - { field: 'buttons', title: i18n.t('message.list.operation'), fixed: 'right', width: 520, showOverflow: true, slots: { default: 'row_buttons' } }, + { field: 'buttons', title: i18n.t('message.list.operation'), fixed: 'right', width: 540, showOverflow: true, slots: { default: 'row_buttons' } }, ], }, // vxeGrid配置参数(此处可覆写任何参数),参考vxe-table官方文档 @@ -204,6 +207,21 @@ const handleDelete = (row: any) => { .catch(() => {}); }; +// 复制 +const handleCopy = (row: any) => { + ElMessageBox.confirm(i18n.t('message.list.confirmCopyRole', { roleName: row.name }), i18n.t('message.list.hint'), { + confirmButtonText: i18n.t('message.list.confirmButtonText'), + cancelButtonText: i18n.t('message.list.cancelButtonText'), + type: 'warning', + }) + .then(async () => { + await getAPI(SysRoleApi).apiSysRoleCopyPost({ id: row.id }); + await handleQuery(); + ElMessage.success(i18n.t('message.list.successCopy')); + }) + .catch(() => {}); +}; + // 表格事件 const gridEvents: VxeGridListeners = { // 只对 pager-config 配置时有效,分页发生改变时会触发该事件