/**
* TalkingQ Platform - RBAC Permission Management Page
*/
registerPage('rbac', function(container) {
const DEFAULT_ROLE_COMPANIES = getDefaultCompanyIds();
const PERMISSION_CATALOG = [
{ key: 'dashboard', label: '数据仪表盘', desc: '查看公司维度统计数据' },
{ key: 'agent-dev', label: '配置应用', desc: '配置智能体模型、Prompt、技能和运行体验' },
{ key: 'agent-manage', label: '应用管理', desc: '创建、发布、回收应用' },
{ key: 'session', label: '会话分析', desc: '查看设备会话和热门话题' },
{ key: 'badcase', label: 'Bad Case 管理', desc: '标注、处理和关闭问题案例' },
{ key: 'device', label: '设备管理', desc: '查看和维护公司设备' },
{ key: 'ota', label: 'OTA 升级', desc: '上传固件和创建升级任务' },
{ key: 'rbac', label: '权限管理', desc: '管理用户、角色和授权范围' },
{ key: 'settings', label: '系统设置', desc: '管理 API Key 和平台配置' },
];
const DEFAULT_ROLE_CONFIGS = [
{
id: 'admin',
name: 'Admin',
desc: '超级管理员,拥有平台全部权限和全部公司数据访问权',
color: '#722ed1',
companyScope: 'all',
permissions: PERMISSION_CATALOG.map(item => item.key),
locked: true,
},
{
id: 'worker',
name: 'Worker',
desc: '内部运营 / 研发人员,可配置应用并处理运营问题',
color: '#1890ff',
companyScope: 'all',
permissions: ['dashboard', 'agent-dev', 'agent-manage', 'session', 'badcase', 'device', 'ota'],
locked: false,
},
{
id: 'client',
name: 'Client',
desc: 'B 端客户,只能访问自己公司的客户可见数据',
color: '#52c41a',
companyScope: 'single',
permissions: ['dashboard', 'session', 'device'],
locked: true,
},
];
const DEFAULT_USERS = [
{ id: 'u001', displayName: '张明华', loginName: 'zhangmh@talkingq.com', status: 'active', lastLogin: '2026-05-12 14:10', role: 'admin', remark: '超级管理员' },
{ id: 'u002', displayName: '李思远', loginName: 'lisiy@talkingq.com', status: 'active', lastLogin: '2026-05-12 11:30', role: 'worker', remark: '运营人员' },
{ id: 'u003', displayName: '王晓燕', loginName: 'wangxy@partner.com', status: 'active', lastLogin: '2026-05-11 09:00', role: 'client', companyId: 'company_a', allowedCompanies: ['company_a'], remark: '智慧星科技-客户' },
{ id: 'u004', displayName: '刘亚楠', loginName: 'liuyn@partner.com', status: 'inactive', lastLogin: '2026-04-28 16:00', role: 'client', companyId: 'company_b', allowedCompanies: ['company_b'], remark: '未来玩具厂-客户' },
{ id: 'u005', displayName: '陈志强', loginName: 'chenzq@talkingq.com', status: 'active', lastLogin: '2026-05-10 09:15', role: 'worker', remark: '开发人员' },
];
const DEFAULT_AUDIT_LOGS = [
{ id: 'a001', time: '2026-05-12 14:22:05', user: '张明华', action: '登录', target: '系统', ip: '192.168.1.10', ok: true },
{ id: 'a002', time: '2026-05-12 14:18:30', user: '张明华', action: '修改 Prompt', target: '小Q故事机器人 v2.3', ip: '192.168.1.10', ok: true },
{ id: 'a003', time: '2026-05-12 13:55:12', user: '李思远', action: '关闭 Bad Case', target: 'BC-2026-004', ip: '10.0.2.15', ok: true },
{ id: 'a004', time: '2026-05-12 11:30:00', user: 'system', action: '自动触发内容安全', target: 'sess-3f7a', ip: 'internal', ok: false },
{ id: 'a005', time: '2026-05-12 09:15:42', user: '张明华', action: '创建 OTA 任务', target: 'OTA-2026-002', ip: '192.168.1.10', ok: true },
];
let activeTab = window.__rbacActiveTab || 'users';
let roleConfigs = window.__rbacRoleConfigs || cloneRoleConfigs(DEFAULT_ROLE_CONFIGS);
let users = loadUsers();
let auditLogs = window.__rbacAuditLogs || DEFAULT_AUDIT_LOGS.map(item => ({ ...item }));
window.__rbacRoleConfigs = roleConfigs;
window.__rbacUsers = users;
window.__rbacAuditLogs = auditLogs;
window.__lookupRbacUserByLoginName = function(loginName) {
const normalized = String(loginName || '').trim().toLowerCase();
return users.find(user => user.loginName === normalized) || null;
};
window.__getRoleConfig = function(role) {
return getRoleConfig(role);
};
function getDefaultCompanyIds() {
const ids = (window.companies || [])
.filter(company => company.id !== 'all')
.map(company => company.id);
return ids.length ? ids : ['company_a', 'company_b', 'company_c'];
}
function cloneRoleConfigs(list) {
return list.map(role => ({
...role,
permissions: [...role.permissions],
allowedCompanyIds: role.allowedCompanyIds ? [...role.allowedCompanyIds] : DEFAULT_ROLE_COMPANIES.slice(),
}));
}
function cloneUsers(list) {
return list.map(item => ({
...item,
allowedCompanies: Array.isArray(item.allowedCompanies) ? [...item.allowedCompanies] : item.allowedCompanies,
permissions: Array.isArray(item.permissions) ? [...item.permissions] : item.permissions,
}));
}
function loadUsers() {
try {
localStorage.removeItem('talkingq_rbac_users_v1');
if (Array.isArray(window.__rbacUsers) && window.__rbacUsers.length) {
return window.__rbacUsers.map((user, index) => normalizeUser(user, index));
}
} catch (error) {
console.warn('Failed to reset legacy RBAC storage', error);
}
return cloneUsers(DEFAULT_USERS).map((user, index) => normalizeUser(user, index));
}
function saveUsers(nextUsers = users) {
users = nextUsers;
window.__rbacUsers = users;
}
function saveRoles(nextRoles = roleConfigs) {
roleConfigs = nextRoles;
window.__rbacRoleConfigs = roleConfigs;
}
function saveAudit(nextLogs = auditLogs) {
auditLogs = nextLogs.slice(0, 80);
window.__rbacAuditLogs = auditLogs;
}
function normalizeRole(role) {
const raw = String(role || '').toLowerCase();
if (raw === 'admin' || raw === 'administrator') return 'admin';
if (raw === 'worker' || raw === 'employee') return 'worker';
if (raw === 'client' || raw === 'customer') return 'client';
return 'worker';
}
function inferRoleFromRemark(remark) {
const text = String(remark || '');
if (text.includes('超级管理员')) return 'admin';
if (text.includes('客户')) return 'client';
return 'worker';
}
function getRoleConfig(role) {
const roleId = normalizeRole(role);
return roleConfigs.find(item => item.id === roleId) || roleConfigs.find(item => item.id === 'worker');
}
function getRoleDefaultPermissions(role) {
return [...(getRoleConfig(role)?.permissions || [])];
}
function normalizeAllowedCompanies(value, companyId, role) {
if (role !== 'client') return DEFAULT_ROLE_COMPANIES.slice();
if (Array.isArray(value) && value.length) return value;
return companyId ? [companyId] : [];
}
function normalizeUser(user, index = 0) {
const role = normalizeRole(user.role || inferRoleFromRemark(user.remark));
const fallbackCompanyId = DEFAULT_ROLE_COMPANIES[index % DEFAULT_ROLE_COMPANIES.length];
const companyId = role === 'client'
? (user.companyId || user.allowedCompanies?.[0] || fallbackCompanyId)
: null;
return {
id: user.id || `u${String(index + 1).padStart(3, '0')}`,
displayName: user.displayName || user.loginName || '未命名用户',
loginName: String(user.loginName || '').trim().toLowerCase(),
status: user.status || 'active',
lastLogin: user.lastLogin || '-',
role,
companyId,
allowedCompanies: normalizeAllowedCompanies(user.allowedCompanies, companyId, role),
permissions: Array.isArray(user.permissions) && user.permissions.length
? [...user.permissions]
: getRoleDefaultPermissions(role),
remark: user.remark || (role === 'client' ? `${getCompanyName(companyId)}-客户` : role === 'admin' ? '超级管理员' : '运营人员'),
};
}
function escapeHtml(value) {
return String(value ?? '')
.replace(/&/g, '&')
.replace(//g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
function getNowText() {
const now = new Date();
const pad = value => String(value).padStart(2, '0');
return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())} ${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}`;
}
function getCompanyName(companyId) {
return window.__getCompanyNameById ? window.__getCompanyNameById(companyId) : companyId;
}
function getCompanyOptionsHtml(selectedCompanyId = '') {
const companies = (window.companies || []).filter(company => company.id !== 'all');
return companies.map(company => `
`).join('');
}
function renderCompanyCheckboxes(selectedIds = DEFAULT_ROLE_COMPANIES) {
const selected = new Set(selectedIds);
const companies = (window.companies || []).filter(company => company.id !== 'all');
return companies.map(company => `
`).join('');
}
function getUserById(userId) {
return users.find(user => user.id === userId);
}
function getUserRoleLabel(user) {
if (user.role === 'admin') return '管理员';
if (user.role === 'client') return '客户';
return '运营人员';
}
function getCompanyScopeText(user) {
if (user.role !== 'client') return '全部公司';
return user.companyId ? getCompanyName(user.companyId) : '未绑定公司';
}
function getStatusLabel(status) {
return status === 'inactive' ? '已禁用' : '启用中';
}
function getStatusBadge(status) {
return status === 'inactive' ? 'badge-default' : 'badge-success';
}
function getActorName() {
try {
const user = JSON.parse(sessionStorage.getItem('talkingq_user') || 'null');
return user?.displayName || user?.username || '张明华';
} catch (error) {
return '张明华';
}
}
function addAuditLog(action, target, ok = true) {
saveAudit([
{
id: `a${Date.now()}`,
time: getNowText(),
user: getActorName(),
action,
target,
ip: 'local-demo',
ok,
},
...auditLogs,
]);
}
function getPermissionLabel(key) {
return PERMISSION_CATALOG.find(item => item.key === key)?.label || key;
}
function renderPermissionBadges(permissionKeys) {
const keys = permissionKeys.length ? permissionKeys : [];
const shown = keys.slice(0, 8);
return `
${shown.map(key => `${escapeHtml(getPermissionLabel(key))}`).join('')}
${keys.length > shown.length ? `+${keys.length - shown.length}` : ''}
`;
}
function renderPermissionCheckboxes(roleId, selectedKeys, editable = true) {
const role = getRoleConfig(roleId);
const selected = new Set(selectedKeys || role.permissions);
const locked = role.id === 'admin' || role.id === 'client' || !editable;
return PERMISSION_CATALOG.map(permission => {
const checked = role.id === 'admin' ? true : selected.has(permission.key);
const disabled = locked ? 'disabled' : '';
return `
`;
}).join('');
}
function collectCheckedValues(root, selector) {
return [...root.querySelectorAll(selector)]
.filter(input => input.checked)
.map(input => input.value);
}
function isLastActiveAdmin(userId) {
const activeAdmins = users.filter(user => user.role === 'admin' && user.status === 'active');
return activeAdmins.length <= 1 && activeAdmins.some(user => user.id === userId);
}
function renderPage() {
activeTab = activeTab || 'users';
window.__rbacActiveTab = activeTab;
container.innerHTML = `
${renderUsersTab()}
${renderRolesTab()}
${renderAuditTab()}
`;
bindEvents();
lucide.createIcons({ elements: [container] });
}
function renderUsersTab() {
return `
| 显示名称 |
登录名称 |
用户类型 |
数据范围 |
状态 |
备注 |
操作 |
${users.map(user => renderUserRow(user)).join('')}
`;
}
function renderUserRow(user) {
const role = getRoleConfig(user.role);
const safeName = escapeHtml(user.displayName);
return `
|
${safeName}
${user.status === 'active'
? ''
: ''}
|
${escapeHtml(user.loginName)} |
${escapeHtml(getUserRoleLabel(user))}
|
${escapeHtml(getCompanyScopeText(user))} |
${getStatusLabel(user.status)} |
|
|
|
|
`;
}
function renderRolesTab() {
return `
${roleConfigs.map(role => `
${escapeHtml(role.name)}
${role.id === 'admin' ? '全部' : role.permissions.length} 项权限
${escapeHtml(role.desc)}
可访问功能:
${renderPermissionBadges(role.id === 'admin' ? PERMISSION_CATALOG.map(item => item.key) : role.permissions)}
`).join('')}
RBAC 接口预留:GET /api/v1/rbac/roles、PUT /api/v1/rbac/roles/{id}、POST /api/v1/rbac/users/assign-role
`;
}
function renderAuditTab() {
return `
| 时间 | 操作人 | 操作类型 | 目标 | IP 地址 | 结果 |
${auditLogs.map(log => `
| ${escapeHtml(log.time)} |
${escapeHtml(log.user)} |
${escapeHtml(log.action)} |
${escapeHtml(log.target)} |
${escapeHtml(log.ip)} |
${log.ok ? '成功' : '告警'} |
`).join('')}
`;
}
function bindEvents() {
container.querySelectorAll('#rbacTabs .tab-item').forEach(tab => {
tab.addEventListener('click', () => {
activeTab = tab.dataset.tab;
renderPage();
});
});
container.querySelector('#addUserBtn')?.addEventListener('click', openAddUserModal);
container.querySelector('#refreshAuditBtn')?.addEventListener('click', () => {
addAuditLog('刷新审计日志', '权限管理 (RBAC)');
activeTab = 'audit';
renderPage();
Toast.success('审计日志已刷新');
});
}
function openAddUserModal() {
const modal = createModal({
title: '添加用户',
size: 'modal-lg',
content: `
`,
onConfirm: async () => {
const displayName = modal.overlay.querySelector('#newUserDisplayName')?.value.trim();
const loginName = modal.overlay.querySelector('#newUserLoginName')?.value.trim().toLowerCase();
const role = modal.overlay.querySelector('#newUserRole')?.value;
const status = modal.overlay.querySelector('#newUserStatus')?.value || 'active';
const companyId = modal.overlay.querySelector('#newUserCompany')?.value;
const password = modal.overlay.querySelector('#newUserPassword')?.value;
const remark = modal.overlay.querySelector('#newUserRemark')?.value.trim();
if (!displayName || !loginName || !role || !password) {
Toast.warning('请填写用户必填信息');
return false;
}
if (users.some(user => user.loginName === loginName)) {
Toast.warning('登录名称已存在');
return false;
}
if (role === 'client' && !companyId) {
Toast.warning('Client 角色必须选择所属公司');
return false;
}
const nextUser = normalizeUser({
id: `u${Date.now()}`,
displayName,
loginName,
role,
status,
companyId: role === 'client' ? companyId : null,
allowedCompanies: role === 'client' ? [companyId] : DEFAULT_ROLE_COMPANIES.slice(),
remark: remark || (role === 'client' ? `${getCompanyName(companyId)}-客户` : role === 'admin' ? '超级管理员' : '运营人员'),
}, users.length);
saveUsers([nextUser, ...users]);
addAuditLog('创建用户', `${nextUser.displayName} / ${getUserRoleLabel(nextUser)}`);
try {
await window.API?.rbac?.createUser?.({ displayName, loginName, role, companyId, status });
} catch (error) {
console.warn('Mock create user failed:', error);
}
Toast.success('用户创建成功');
activeTab = 'users';
renderPage();
},
confirmText: '创建用户',
});
bindRoleCompanyToggle(modal.overlay, '#newUserRole', '#newCompanyGroup', '#newUserCompany');
}
function bindRoleCompanyToggle(root, roleSelector, groupSelector, companySelector) {
const roleSelect = root.querySelector(roleSelector);
const group = root.querySelector(groupSelector);
const companySelect = root.querySelector(companySelector);
const sync = () => {
const isClient = roleSelect?.value === 'client';
if (group) group.style.display = isClient ? '' : 'none';
if (companySelect) companySelect.disabled = !isClient;
};
roleSelect?.addEventListener('change', sync);
sync();
}
window.editUser = function(userId) {
const user = getUserById(userId);
if (!user) return;
const modal = createModal({
title: '编辑用户',
size: 'modal-lg',
content: `
`,
onConfirm: async () => {
const displayName = modal.overlay.querySelector('#editUserDisplayName')?.value.trim();
const role = modal.overlay.querySelector('#editUserRole')?.value || 'worker';
const status = modal.overlay.querySelector('#editUserStatus')?.value || 'active';
const companyId = modal.overlay.querySelector('#editUserCompany')?.value;
const remark = modal.overlay.querySelector('#editUserRemark')?.value.trim();
if (!displayName) {
Toast.warning('请填写显示名称');
return false;
}
if (role === 'client' && !companyId) {
Toast.warning('Client 角色必须选择所属公司');
return false;
}
if (status === 'inactive' && isLastActiveAdmin(user.id)) {
Toast.warning('至少需要保留一个启用中的管理员');
return false;
}
const nextUser = normalizeUser({
...user,
displayName,
role,
status,
companyId: role === 'client' ? companyId : null,
allowedCompanies: role === 'client' ? [companyId] : DEFAULT_ROLE_COMPANIES.slice(),
permissions: role === user.role ? user.permissions : getRoleDefaultPermissions(role),
remark: remark || (role === 'client' ? `${getCompanyName(companyId)}-客户` : role === 'admin' ? '超级管理员' : '运营人员'),
});
saveUsers(users.map(item => item.id === user.id ? nextUser : item));
addAuditLog('编辑用户', `${nextUser.displayName} / ${getUserRoleLabel(nextUser)}`);
try {
await window.API?.rbac?.updateUser?.(user.id, nextUser);
} catch (error) {
console.warn('Mock update user failed:', error);
}
Toast.success(`用户 ${nextUser.displayName} 信息已更新`);
activeTab = 'users';
renderPage();
},
confirmText: '保存',
});
bindRoleCompanyToggle(modal.overlay, '#editUserRole', '#editCompanyGroup', '#editUserCompany');
};
window.managePermissions = function(userId) {
const user = getUserById(userId);
if (!user) return;
const modal = createModal({
title: `权限管理 - ${escapeHtml(user.displayName)}`,
size: 'modal-lg',
content: `
后端接口预留:POST /api/v1/rbac/users/assign-role、PUT /api/v1/rbac/users/{id}/permissions
`,
onConfirm: async () => {
const nextRole = modal.overlay.querySelector('#permRoleSelect')?.value || user.role;
const companyId = modal.overlay.querySelector('#permCompanySelect')?.value;
if (nextRole === 'client' && !companyId) {
Toast.warning('Client 角色必须选择所属公司');
return false;
}
const role = getRoleConfig(nextRole);
const permissions = role.locked
? getRoleDefaultPermissions(nextRole)
: collectCheckedValues(modal.overlay, '.rbac-permission-checkbox');
if (!permissions.length) {
Toast.warning('请至少保留一项权限');
return false;
}
const nextUser = normalizeUser({
...user,
role: nextRole,
companyId: nextRole === 'client' ? companyId : null,
allowedCompanies: nextRole === 'client' ? [companyId] : DEFAULT_ROLE_COMPANIES.slice(),
permissions,
remark: nextRole === 'client' ? `${getCompanyName(companyId)}-客户` : nextRole === 'admin' ? '超级管理员' : '运营人员',
});
saveUsers(users.map(item => item.id === user.id ? nextUser : item));
addAuditLog('更新用户权限', `${nextUser.displayName} / ${getUserRoleLabel(nextUser)}`);
try {
await window.API?.rbac?.assignRole?.(user.id, nextRole);
await window.API?.rbac?.updateUser?.(user.id, nextUser);
} catch (error) {
console.warn('Mock update permissions failed:', error);
}
Toast.success(`${nextUser.displayName} 的权限已更新`);
activeTab = 'users';
renderPage();
},
confirmText: '保存权限',
});
const roleSelect = modal.overlay.querySelector('#permRoleSelect');
const companyGroup = modal.overlay.querySelector('#permCompanyGroup');
const companySelect = modal.overlay.querySelector('#permCompanySelect');
const grid = modal.overlay.querySelector('#permCheckboxGrid');
const sync = () => {
const roleId = roleSelect?.value || user.role;
const role = getRoleConfig(roleId);
if (companyGroup) companyGroup.style.display = roleId === 'client' ? '' : 'none';
if (companySelect) companySelect.disabled = roleId !== 'client';
if (grid) grid.innerHTML = renderPermissionCheckboxes(roleId, roleId === user.role ? user.permissions : role.permissions, !role.locked);
lucide.createIcons({ elements: [modal.overlay] });
};
roleSelect?.addEventListener('change', sync);
sync();
};
window.toggleUserStatus = function(userId) {
const user = getUserById(userId);
if (!user) return;
const nextStatus = user.status === 'active' ? 'inactive' : 'active';
createModal({
title: `${nextStatus === 'active' ? '启用' : '禁用'}用户`,
content: `
确认${nextStatus === 'active' ? '启用' : '禁用'} ${escapeHtml(user.displayName)}?
${nextStatus === 'active' ? '启用后用户可重新登录平台。' : '禁用后用户将无法登录平台。'}
`,
onConfirm: async () => {
if (nextStatus === 'inactive' && isLastActiveAdmin(user.id)) {
Toast.warning('至少需要保留一个启用中的管理员');
return false;
}
const nextUser = { ...user, status: nextStatus };
saveUsers(users.map(item => item.id === user.id ? nextUser : item));
addAuditLog(nextStatus === 'active' ? '启用用户' : '禁用用户', user.displayName);
try {
await window.API?.rbac?.updateUser?.(user.id, { status: nextStatus });
} catch (error) {
console.warn('Mock update status failed:', error);
}
Toast.success(`用户 ${user.displayName} 已${nextStatus === 'active' ? '启用' : '禁用'}`);
renderPage();
},
confirmText: nextStatus === 'active' ? '确认启用' : '确认禁用',
});
lucide.createIcons();
};
window.deleteUser = function(userId) {
const user = getUserById(userId);
if (!user) return;
createModal({
title: '确认删除',
content: `
确认删除用户 ${escapeHtml(user.displayName)}?
此操作不可撤销,删除后该用户将无法登录系统。
`,
onConfirm: async () => {
if (isLastActiveAdmin(user.id)) {
Toast.warning('至少需要保留一个启用中的管理员');
return false;
}
saveUsers(users.filter(item => item.id !== user.id));
addAuditLog('删除用户', user.displayName);
try {
await window.API?.rbac?.deleteUser?.(user.id);
} catch (error) {
console.warn('Mock delete user failed:', error);
}
Toast.success(`用户 ${user.displayName} 已删除`);
activeTab = 'users';
renderPage();
},
confirmText: '确认删除',
cancelText: '取消',
});
lucide.createIcons();
};
window.editRolePermissions = function(roleId) {
const role = getRoleConfig(roleId);
if (!role) return;
const modal = createModal({
title: `编辑 ${escapeHtml(role.name)} 角色权限`,
size: 'modal-lg',
content: `
角色说明
${escapeHtml(role.desc)}
后端接口预留:PUT /api/v1/rbac/roles/${escapeHtml(role.id)}
`,
onConfirm: async () => {
const permissions = role.locked
? getRoleDefaultPermissions(role.id)
: collectCheckedValues(modal.overlay, '.rbac-permission-checkbox');
const allowedCompanyIds = role.id === 'admin'
? DEFAULT_ROLE_COMPANIES.slice()
: collectCheckedValues(modal.overlay, '.rbac-company-checkbox');
if (!permissions.length) {
Toast.warning('请至少保留一项权限');
return false;
}
if (role.id !== 'admin' && !allowedCompanyIds.length) {
Toast.warning('请至少选择一个可分配公司');
return false;
}
const nextRole = {
...role,
permissions,
allowedCompanyIds,
};
saveRoles(roleConfigs.map(item => item.id === role.id ? nextRole : item));
addAuditLog('编辑角色权限', role.name);
try {
await window.API?.rbac?.updateRole?.(role.id, nextRole);
} catch (error) {
console.warn('Mock update role failed:', error);
}
Toast.success(`${role.name} 角色权限已更新`);
activeTab = 'roles';
renderPage();
},
confirmText: '保存',
});
lucide.createIcons({ elements: [modal.overlay] });
};
window.viewRoleUsers = function(roleId) {
const role = getRoleConfig(roleId);
if (!role) return;
const roleUsers = users.filter(user => user.role === role.id);
createModal({
title: `${escapeHtml(role.name)} 角色下的用户`,
size: 'modal-lg',
content: `
共 ${roleUsers.length} 个用户
${roleUsers.length ? roleUsers.map(user => `
${escapeHtml(user.displayName)}
${escapeHtml(user.loginName)}
${getStatusLabel(user.status)}
${escapeHtml(getCompanyScopeText(user))}
`).join('') : `
`}
`,
confirmText: '关闭',
showCancel: false,
});
};
renderPage();
});