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 配置时有效,分页发生改变时会触发该事件