- 权限一览:formatRoleAuthzTree 子节点键 apps→children(zTree 只认 children,导致除分类外全不渲染) - 权限一览:所属部门按行所在组请求 UserGroupTree,多组用户只显示该组链路,(本组)标记指向该组 - 角色授权:用户管理新增「部门」列,添加/删除按(用户,组)维度,切组清空勾选避免误绑 - 编辑用户:切「所在组」时身份与角色属性双回显,该组角色未就绪拦截提交防误存;保存按组覆盖 - 组用户管理:左侧树滚动条收敛到树节点(页面级新增 group-user-tree 类,不动全局 .tree-container)
This commit is contained in:
Vendored
+18
-1
@@ -179,11 +179,18 @@ export interface GroupAppAssignRequest {
|
||||
}
|
||||
export interface UserAppRoleBindRequest {
|
||||
userId: number;
|
||||
/** 绑定组ID(可选):角色归属的组,空则后端兜底主组 */
|
||||
groupId?: number;
|
||||
roleIds?: number[];
|
||||
}
|
||||
export interface AppRoleUserBinding {
|
||||
userId: number;
|
||||
/** 绑定发生时所选的组ID */
|
||||
groupId: number;
|
||||
}
|
||||
export interface AppRoleUserBindRequest {
|
||||
roleId: number;
|
||||
userIds?: number[];
|
||||
bindings?: AppRoleUserBinding[];
|
||||
}
|
||||
export interface AppRoleModuleAssignRequest {
|
||||
roleId: number;
|
||||
@@ -677,6 +684,10 @@ export interface AppRoleUserVo {
|
||||
id?: number;
|
||||
account?: string;
|
||||
realName?: string;
|
||||
/** 绑定发生时所选的组ID */
|
||||
groupId?: number;
|
||||
/** 组路径(查询时按 groupId 现算,scope 裁剪后) */
|
||||
groupPath?: string;
|
||||
}
|
||||
export interface AppRoleAuthzModuleVo {
|
||||
id?: number;
|
||||
@@ -2031,6 +2042,8 @@ declare global {
|
||||
Config extends Alova2MethodConfig<UserRoleVo[]> & {
|
||||
params: {
|
||||
userId: number;
|
||||
/** 组ID(可选):传入时只返回该组下的绑定(编辑弹窗按所在组回显) */
|
||||
groupId?: number;
|
||||
};
|
||||
}
|
||||
>(
|
||||
@@ -2129,6 +2142,8 @@ declare global {
|
||||
Config extends Alova2MethodConfig<UserGroupNodeVo[]> & {
|
||||
params: {
|
||||
userId: number;
|
||||
/** 上下文组ID(可选):传入且用户确属该组时只画该组祖先链 */
|
||||
groupId?: number;
|
||||
};
|
||||
}
|
||||
>(
|
||||
@@ -3036,6 +3051,8 @@ declare global {
|
||||
params: {
|
||||
roleId: number;
|
||||
userId: number;
|
||||
/** 绑定组ID:按行精确删除 */
|
||||
groupId: number;
|
||||
};
|
||||
}
|
||||
>(
|
||||
|
||||
@@ -262,9 +262,10 @@ async function onSelectUser(user: UserItem) {
|
||||
// 行自带组ID(多组用户每个组一行)优先;组列表模式回退左侧选中组
|
||||
const groupId = user.groupId ?? (selectedGroup.value?.id ? Number(selectedGroup.value.id) : undefined);
|
||||
// 三块数据并行加载,互不阻塞
|
||||
// userGroupTree 为新增接口:apiDefinitions 未重新生成(npm run api:gen)时方法不存在,降级为友好报错
|
||||
// userGroupTree 为新增接口:apiDefinitions 未重新生成(npm run api:gen)时方法不存在,降级为友好报错;
|
||||
// groupId 为行所在组(每行是「用户×组」对),所属部门只画该组链路而非用户全部归属组
|
||||
const userGroupTreeApi = (Apis.GroupAuthz as any).userGroupTree
|
||||
? Apis.GroupAuthz.userGroupTree({ params: { userId }, cacheFor: null })
|
||||
? Apis.GroupAuthz.userGroupTree({ params: { userId, groupId: groupId ?? undefined }, cacheFor: null })
|
||||
: Promise.reject(new Error("所属部门接口未生成,请重启后端后执行 npm run api:gen"));
|
||||
const [permRes, deptRes, roleRes] = await Promise.allSettled([
|
||||
Apis.GroupAuthz.userPermissionTree({
|
||||
@@ -371,9 +372,9 @@ function formatRoleAuthzTree(apps: any[], appListRes: any, typeRes: any): any[]
|
||||
if (children.length === 0) continue; // 角色未勾选任何模块的应用不展示
|
||||
const cid = catMap.get(Number(app.id)) ?? -1;
|
||||
if (!groups.has(cid)) {
|
||||
groups.set(cid, { id: cid, name: typeMap.get(cid) || "未分类", open: true, isParent: true, apps: [] });
|
||||
groups.set(cid, { id: cid, name: typeMap.get(cid) || "未分类", open: true, isParent: true, children: [] });
|
||||
}
|
||||
groups.get(cid).apps.push({
|
||||
groups.get(cid).children.push({
|
||||
id: `app_${app.id}_${cid}`,
|
||||
name: app.name || `应用${app.id}`,
|
||||
open: false, // 与用户视图一致:应用一级默认闭合,点击才展开模块
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="page-wrapper tree-wrapper group-user-page">
|
||||
<Group class="tree-container" v-model:curTreeNode="selectedNode" :treeApi="treeApi" @on-change="onTreeChange"
|
||||
@on-tree-data="onTreeData" />
|
||||
<Group class="tree-container group-user-tree" v-model:curTreeNode="selectedNode" :treeApi="treeApi"
|
||||
@on-change="onTreeChange" @on-tree-data="onTreeData" />
|
||||
<div class="main-container">
|
||||
<div class="search-wrap">
|
||||
<Button type="primary" @click="showAddUser">
|
||||
@@ -371,6 +371,23 @@ function onSortSaved() {
|
||||
left: 348px !important;
|
||||
}
|
||||
|
||||
/* 左侧树容器改为 flex 纵向布局并收起自身滚动,把滚动条收敛到树节点区域(.ztree 自带 overflow-y:auto),
|
||||
避免树过长时把顶部 opera-ul 操作按钮条滚出屏幕;仅作用于本页,不影响全局 .tree-container */
|
||||
.tree-wrapper.group-user-page .tree-container.group-user-tree {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
|
||||
.opera-ul {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.group-tree-search-panel {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.batch-status-body {
|
||||
padding: 8px 12px;
|
||||
|
||||
|
||||
@@ -68,10 +68,12 @@ async function handleSubmit(formData: Record<string, any>) {
|
||||
// 新增失败(onError 已提示),不继续绑定角色
|
||||
return;
|
||||
}
|
||||
// 新增成功后再绑定业务角色
|
||||
// 新增成功后再绑定业务角色(组维度:绑定挂在创建分组上,即左侧当前选中组)
|
||||
if (newId != null && appRolesToSave.length) {
|
||||
try {
|
||||
await Apis.AppRole.saveUserRoles({ data: { userId: newId, roleIds: appRolesToSave } });
|
||||
await Apis.AppRole.saveUserRoles({
|
||||
data: { userId: newId, groupId: currentGroupId.value ?? undefined, roleIds: appRolesToSave },
|
||||
});
|
||||
} catch (e: any) {
|
||||
// 全局拦截器已弹窗,这里仅记录日志避免二次弹窗
|
||||
console.warn('[AddUserContainer] 用户已创建,但角色属性保存失败:', e?.message || '未知错误');
|
||||
|
||||
@@ -20,10 +20,8 @@ const userGroups = ref<{ id: number; name: string }[]>([]);
|
||||
const userGroupIdsArr = ref<number[]>([]);
|
||||
// 角色属性下拉:来自角色授权页的全量角色
|
||||
const roleOptions = ref<{ id: number; name: string }[]>([]);
|
||||
// 角色属性是否成功加载(控制编辑后是否回写 saveUserRoles,避免加载失败时误清空)
|
||||
// 角色属性是否成功加载(控制编辑后是否回写 saveUserRoles,避免下拉失败时误清空)
|
||||
const roleOptionsLoaded = ref(false);
|
||||
// 已绑定角色是否成功加载(与 roleOptionsLoaded 同时为真才回写,防止误清空)
|
||||
const userRolesLoaded = ref(false);
|
||||
// 待保存的角色属性(用户多选结果)
|
||||
let appRolesToSave: number[] = [];
|
||||
|
||||
@@ -62,7 +60,6 @@ async function open(row: any, groups: any[], curGroupId?: number | null, onSucce
|
||||
const groupList = groups || [];
|
||||
onSuccessCallback = onSuccess || null;
|
||||
roleOptionsLoaded.value = false;
|
||||
userRolesLoaded.value = false;
|
||||
userGroups.value = [];
|
||||
userGroupIdsArr.value = [];
|
||||
roleOptions.value = [];
|
||||
@@ -104,28 +101,17 @@ async function open(row: any, groups: any[], curGroupId?: number | null, onSucce
|
||||
console.warn('[EditUserContainer] 加载角色列表失败:', e?.message || '未知错误');
|
||||
}
|
||||
|
||||
// 3) 已绑定角色 -> appRoles 回填(相互独立)
|
||||
// 所在组(只读)默认选中「当前组」:优先用进入编辑时的左侧树/列表组(curGroupId),否则取用户所属组的第一个
|
||||
// 3) 角色属性回显不再在此加载:UserForm 内部监听 userGroupId(初始选中即触发),
|
||||
// 按组调 GET UserRoles 回显该组角色,并对「该组回显未就绪」拦截提交,防止误清空。
|
||||
// 所在组默认选中「当前组」:优先用进入编辑时的左侧树/列表组(curGroupId),否则取用户所属组的第一个
|
||||
const defaultGroupId = (curGroupId != null && userGroupIdsArr.value.includes(curGroupId))
|
||||
? curGroupId
|
||||
: (userGroupIdsArr.value[0] ?? null);
|
||||
try {
|
||||
const userRolesResp = await Apis.GroupAuthz.userRoles({ params: { userId: row.id } });
|
||||
const userRoleIds: number[] = (Array.isArray(userRolesResp) ? userRolesResp : [])
|
||||
.map((r: any) => r.id)
|
||||
.filter((x: any): x is number => x != null);
|
||||
userRolesLoaded.value = true;
|
||||
detailData.value = buildInitForm(row, userRoleIds, defaultGroupId);
|
||||
} catch (e: any) {
|
||||
// 已绑定角色加载失败:仍回填其它字段,但标记未加载成功(提交时不回写,避免误清空)
|
||||
detailData.value = buildInitForm(row, [], defaultGroupId);
|
||||
// 全局拦截器已弹窗,这里仅记录日志避免二次弹窗
|
||||
console.warn('[EditUserContainer] 加载用户已绑定角色失败:', e?.message || '未知错误');
|
||||
}
|
||||
detailData.value = buildInitForm(row, defaultGroupId);
|
||||
}
|
||||
|
||||
/* ---------- 把行数据映射成表单回填数据 ---------- */
|
||||
function buildInitForm(row: any, userRoleIds: number[], defaultGroupId: number | null = null) {
|
||||
function buildInitForm(row: any, defaultGroupId: number | null = null) {
|
||||
return {
|
||||
id: row.id,
|
||||
account: row.account || '',
|
||||
@@ -135,10 +121,10 @@ function buildInitForm(row: any, userRoleIds: number[], defaultGroupId: number |
|
||||
password: '',
|
||||
confirmPassword: '',
|
||||
gender: row.gender ?? 0,
|
||||
// 用户身份回显唯一来源是 GET UserIdentity(UserForm 内部按「所在组」加载):
|
||||
// 用户身份/角色属性回显唯一来源是 GET UserIdentity / GET UserRoles(UserForm 内部按「所在组」加载):
|
||||
// roles 列已停写,row.roles 为冻结历史值,误用回显会把废弃值固化进权威表
|
||||
userType: [],
|
||||
appRoles: userRoleIds || [],
|
||||
appRoles: [],
|
||||
userGroupId: defaultGroupId ?? null,
|
||||
};
|
||||
}
|
||||
@@ -154,10 +140,17 @@ async function handleSubmit(formData: Record<string, any>) {
|
||||
// 编辑失败(onError 已提示),不继续回写角色
|
||||
return;
|
||||
}
|
||||
// 编辑成功后再回写业务角色(全量覆盖);仅当角色列表与已绑定角色都成功加载才回写,防止误清空
|
||||
if (roleOptionsLoaded.value && userRolesLoaded.value) {
|
||||
// 编辑成功后再回写业务角色(按组覆盖:只覆盖当前所在组下的绑定,不影响其他组);
|
||||
// 仅当角色下拉成功加载才回写,防止误清空(该组角色回显未就绪时 UserForm 已拦截提交)
|
||||
if (roleOptionsLoaded.value) {
|
||||
try {
|
||||
await Apis.AppRole.saveUserRoles({ data: { userId: currentId.value as number, roleIds: appRolesToSave } });
|
||||
await Apis.AppRole.saveUserRoles({
|
||||
data: {
|
||||
userId: currentId.value as number,
|
||||
groupId: (formData.userGroupId as number | null) ?? undefined,
|
||||
roleIds: appRolesToSave,
|
||||
},
|
||||
});
|
||||
} catch (e: any) {
|
||||
// 全局拦截器已弹窗,这里仅记录日志避免二次弹窗
|
||||
console.warn('[EditUserContainer] 用户已更新,但角色属性保存失败:', e?.message || '未知错误');
|
||||
|
||||
@@ -57,12 +57,12 @@
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<!-- 第 5 行:所在组(仅编辑展示;切换只触发下方「用户身份」回显,不改变实际所在组) -->
|
||||
<!-- 第 5 行:所在组(仅编辑展示;切换只触发下方「用户身份/角色属性」回显,不改变实际所在组) -->
|
||||
<Row v-if="isEdit">
|
||||
<Col span="24">
|
||||
<FormItem label="所在组:">
|
||||
<Select v-model="form.userGroupId" transfer clearable
|
||||
placeholder="切换后回显该组身份(不改变实际所在组)">
|
||||
placeholder="切换后回显该组的身份与角色属性(不改变实际所在组)">
|
||||
<Option v-for="g in userGroups" :key="g.id" :value="g.id" :label="g.name" />
|
||||
</Select>
|
||||
</FormItem>
|
||||
@@ -155,6 +155,9 @@ const form = reactive(defaultForm());
|
||||
// 编辑模式回显到的最新的身份基线(用于「非空清成空」二次确认;随所在组切换同步更新)
|
||||
let baselineUserType: number[] = [];
|
||||
|
||||
// 编辑模式:当前所在组的角色属性是否已回显成功(未就绪时拦截提交,避免把上一组的角色写到新组)
|
||||
let appRolesEchoed = false;
|
||||
|
||||
// 外部 initForm 变化时回填
|
||||
watch(() => props.initForm, (val) => {
|
||||
if (val && Object.keys(val).length > 0) {
|
||||
@@ -185,11 +188,19 @@ const userTypeOptions = computed(() => {
|
||||
return SYS_ROLE_FALLBACK;
|
||||
});
|
||||
|
||||
/* ---------- 用户身份回显(唯一来源 GET UserIdentity) ---------- */
|
||||
// 所在组 Select 切换(含弹窗打开时的初始选中)→ 后端解析 schoolId 后回显 {schoolId, roleIds}。
|
||||
/* ---------- 所在组切换:身份 + 角色属性 双回显(唯一来源 GET UserIdentity / GET UserRoles) ---------- */
|
||||
// 所在组 Select 切换(含弹窗打开时的初始选中)→ 后端解析 schoolId 后回显 {schoolId, roleIds};
|
||||
// 角色属性为组维度(一行 = 用户×组×角色),同步按所选组回显该组下的角色,互不影响其他组绑定。
|
||||
// 同一学校多组由后端返回同一 schoolId 与角色并集;前端不感知解析逻辑。
|
||||
watch(() => form.userGroupId, (gid: number | null) => {
|
||||
if (!props.isEdit || gid == null || !form.id) return;
|
||||
if (!props.isEdit) return;
|
||||
if (gid == null || !form.id) {
|
||||
// 清空所在组:回显状态失效并拦截提交,避免把上一组的角色经「主组兜底」误存到别的组
|
||||
appRolesEchoed = false;
|
||||
return;
|
||||
}
|
||||
// 切组即置为未就绪:两组数据任一未回来前不允许提交
|
||||
appRolesEchoed = false;
|
||||
Apis.SysUser.userIdentity({ params: { userId: form.id, groupId: gid }, cacheFor: null })
|
||||
.then((resp: any) => {
|
||||
const roleIds = Array.isArray(resp?.roleIds) ? resp.roleIds.map((v: any) => Number(v)) : [];
|
||||
@@ -201,6 +212,16 @@ watch(() => form.userGroupId, (gid: number | null) => {
|
||||
// 全局拦截器已弹窗,这里仅记录日志避免二次弹窗;schoolId 保持 null 时提交会被后端拒绝,不会误清空
|
||||
console.warn('[UserForm] 加载用户身份失败:', e?.message || '未知错误');
|
||||
});
|
||||
Apis.GroupAuthz.userRoles({ params: { userId: form.id, groupId: gid }, cacheFor: null })
|
||||
.then((resp: any) => {
|
||||
const ids = Array.isArray(resp) ? resp.map((r: any) => Number(r?.id)).filter((v: any) => v != null) : [];
|
||||
form.appRoles = ids;
|
||||
appRolesEchoed = true;
|
||||
})
|
||||
.catch((e: any) => {
|
||||
// 回显失败保持未就绪:提交会被拦截,不会把上一组的角色误存到本组
|
||||
console.warn('[UserForm] 加载该组角色属性失败:', e?.message || '未知错误');
|
||||
});
|
||||
});
|
||||
|
||||
/* ---------- 校验规则 ---------- */
|
||||
@@ -291,6 +312,11 @@ async function handleSubmit() {
|
||||
Message.warning('用户身份数据加载中,请稍候再提交');
|
||||
return false;
|
||||
}
|
||||
// 编辑模式角色属性回显未就绪时拦截:避免把上一组的角色属性误存到当前组
|
||||
if (props.isEdit && !appRolesEchoed) {
|
||||
Message.warning('角色属性加载中,请稍候再提交');
|
||||
return false;
|
||||
}
|
||||
// 勾选由非空清成空:二次确认(空数组提交 = 清空该校身份)
|
||||
if (props.isEdit && baselineUserType.length > 0 && form.userType.length === 0) {
|
||||
const ok = await MyConfirm({
|
||||
|
||||
@@ -37,7 +37,8 @@ import GroupTreeSearchPanel from "@/components/GroupTreeSearchPanel.vue";
|
||||
|
||||
const props = defineProps<{
|
||||
roleId: number;
|
||||
existingUserIds: number[];
|
||||
/** 已有「用户×组」绑定明细,用于按 (用户, 当前选中组) 去重/禁用 */
|
||||
existingBindings: { id: number; groupId: number }[];
|
||||
visible: boolean;
|
||||
}>();
|
||||
const emit = defineEmits<{
|
||||
@@ -60,7 +61,10 @@ const saving = ref(false);
|
||||
// 组织树数据源(与组用户管理一致)
|
||||
const treeApi = () => Apis.SysGroup.getTree();
|
||||
|
||||
const existingSet = computed(() => new Set(props.existingUserIds ?? []));
|
||||
// 已有绑定集合:键为 `${userId}:${groupId}`,同一用户可在不同组下分别绑定
|
||||
const existingKeys = computed(() =>
|
||||
new Set((props.existingBindings ?? []).map(b => `${b.id}:${b.groupId}`))
|
||||
);
|
||||
|
||||
const filteredCandidates = computed(() => {
|
||||
const k = kw.value.trim().toLowerCase();
|
||||
@@ -73,7 +77,7 @@ const filteredCandidates = computed(() => {
|
||||
});
|
||||
|
||||
function isExisting(u: any) {
|
||||
return existingSet.value.has(u.id);
|
||||
return groupId.value != null && existingKeys.value.has(`${u.id}:${groupId.value}`);
|
||||
}
|
||||
function isChecked(u: any) {
|
||||
return isExisting(u) || selectedIds.value.has(u.id);
|
||||
@@ -88,6 +92,8 @@ function toggle(u: any, v: boolean) {
|
||||
|
||||
async function onTreeChange(node: any) {
|
||||
groupId.value = node?.id ?? null;
|
||||
// 绑定记「勾选时所在组」:切换组即清空勾选,避免把 A 组下勾的人误绑到 B 组
|
||||
selectedIds.value = new Set();
|
||||
if (!groupId.value) {
|
||||
candidates.value = [];
|
||||
return;
|
||||
@@ -113,12 +119,25 @@ function onVisibleChange(v: boolean) {
|
||||
}
|
||||
|
||||
async function save() {
|
||||
if (!groupId.value) {
|
||||
Message.warning("请先选择左侧组织节点");
|
||||
return;
|
||||
}
|
||||
if (!selectedIds.value.size) {
|
||||
Message.warning("请先勾选要添加的用户");
|
||||
return;
|
||||
}
|
||||
saving.value = true;
|
||||
try {
|
||||
// 全量覆盖:现有绑定 ∪ 本次新选
|
||||
const all = new Set<number>([...existingSet.value, ...selectedIds.value]);
|
||||
// 增量添加「用户×组」绑定(组 = 左侧树当前选中组);后端对已存在的 (userId, groupId) 幂等跳过
|
||||
await Apis.AppRole.saveRoleUsers(
|
||||
{ data: { roleId: props.roleId, userIds: [...all] }, cacheFor: null }
|
||||
{
|
||||
data: {
|
||||
roleId: props.roleId,
|
||||
bindings: [...selectedIds.value].map(id => ({ userId: id, groupId: groupId.value as number })),
|
||||
},
|
||||
cacheFor: null,
|
||||
}
|
||||
);
|
||||
Message.success("添加成功");
|
||||
emit("success");
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<div class="role-user-manage">
|
||||
<div class="rum-toolbar">
|
||||
<span class="rum-count">共 {{ userList.length }} 位用户</span>
|
||||
<span class="rum-count">共 {{ userList.length }} 条绑定</span>
|
||||
<Button type="primary" icon="md-person-add" :disabled="!roleId" @click="openBind">添加用户</Button>
|
||||
</div>
|
||||
|
||||
<Table :columns="columns" :data="userList" :loading="loading" size="small" border></Table>
|
||||
|
||||
<RoleUserBindModal v-model:visible="bindVisible" :role-id="roleId" :existing-user-ids="existingIds"
|
||||
<RoleUserBindModal v-model:visible="bindVisible" :role-id="roleId" :existing-bindings="existingBindings"
|
||||
@success="onBindSuccess" />
|
||||
</div>
|
||||
</template>
|
||||
@@ -31,12 +31,18 @@ const userList = ref<any[]>([]);
|
||||
const loading = ref(false);
|
||||
const bindVisible = ref(false);
|
||||
|
||||
// 当前角色已绑定的用户 id 集合(传给弹窗做去重/禁用)
|
||||
const existingIds = computed(() => userList.value.map((u: any) => u.id));
|
||||
// 当前角色已绑定的「用户×组」明细(传给弹窗按 (用户, 组) 去重/禁用)
|
||||
const existingBindings = computed(() =>
|
||||
userList.value
|
||||
.filter((u: any) => u.id != null && u.groupId != null)
|
||||
.map((u: any) => ({ id: u.id as number, groupId: u.groupId as number }))
|
||||
);
|
||||
|
||||
// 部门列为查询时按 groupId 拼接的组路径(非超管按数据范围裁剪,学校管理员只看到本校路径)
|
||||
const columns = [
|
||||
{ title: "账号", key: "account", minWidth: 140 },
|
||||
{ title: "姓名", key: "realName", minWidth: 110 },
|
||||
{ title: "部门", key: "groupPath", minWidth: 200 },
|
||||
{
|
||||
title: "操作", key: "action", width: 90, align: "center",
|
||||
render: (h: any, { row }: any) => $utils.operatingTextHandle(h, "删除", "text-error", () => removeUser(row)),
|
||||
@@ -61,13 +67,13 @@ async function loadUsers() {
|
||||
|
||||
function removeUser(row: any) {
|
||||
MyConfirm({
|
||||
title: "移除用户",
|
||||
msg: `确定将用户【${row.realName || row.account}】从此角色移除?`,
|
||||
info: "移除后该用户不再拥有此角色所授权的权限。",
|
||||
title: "移除绑定",
|
||||
msg: `确定将用户【${row.realName || row.account}】在部门【${row.groupPath || '未知'}】下的该角色移除?`,
|
||||
info: "移除后该用户在该组下不再拥有此角色所授权的权限;其在其他组下的绑定不受影响。",
|
||||
async onOk() {
|
||||
try {
|
||||
await Apis.AppRole.removeRoleUser(
|
||||
{ params: { roleId: props.roleId, userId: row.id }, cacheFor: null }
|
||||
{ params: { roleId: props.roleId, userId: row.id, groupId: row.groupId }, cacheFor: null }
|
||||
);
|
||||
Message.success("已移除");
|
||||
await loadUsers();
|
||||
|
||||
Reference in New Issue
Block a user