+ {hasRules && (
+ <>
+
+
+ 💡
+
+ {$t('menu.rules')}
+ {$t('form.role.permissionGuide')}
+
+
+ {$t('menu.rules.desc2')}
+
+
+
+ {/* View card */}
+
+
+ handleRulesViewChange(e.target.checked)
+ }
+ >
+
+ 👁️
+
+
+
+ {$t('menu.rules.view')}
+
+
+ {$t('menu.rules.view.badge')}
+
+
+
+ {$t('menu.rules.view.desc')}
+
+
+
+
+
+
+ {/* Manage card */}
+
+
+ handleRulesManageChange(e.target.checked)
+ }
+ >
+
+ ⚙️
+
+
+
+ {$t('menu.rules.edit')}
+
+
+ {$t('menu.rules.edit.badge')}
+
+
+
+ {$t('menu.rules.desc2')}
+
+
+
+
+
+
+ >
+ )}
+
+ {showDivider && (
+
+
+ {$t('form.role.otherPermissions')}
+
+
+ )}
+
+ {hasBelow && (
+
+ {belowMenus.map((node) => {
+ if (node.children?.length) {
+ const childIds = getAllDescendantIds(node).filter(
+ (id) => id !== node.id,
+ );
+ const checkedCount = childIds.filter((id) =>
+ checkedSet.has(id),
+ ).length;
+ return (
+ 0 && checkedCount === childIds.length}
+ indeterminate={checkedCount > 0 && checkedCount < childIds.length}
+ disabled={disabled}
+ onChange={(e: CheckboxChangeEvent) =>
+ handleGroupedParentChange(node, e.target.checked)
+ }
+ >
+ {node.meta?.icon || ''} {node.meta?.title || node.menuName}
+ {node.meta?.describe && (
+
+ ({node.meta.describe})
+
+ )}
+
+ );
+ }
+ return (
+
+ handleFlatChange(node, e.target.checked)
+ }
+ >
+ {node.meta?.icon || ''} {node.meta?.title || node.menuName}
+ {node.meta?.describe && (
+
+ ({node.meta.describe})
+
+ )}
+
+ );
+ })}
+
+ )}
+
+ );
+};
+
+export default PermissionCheckboxGroup;
diff --git a/src/pages/role/components/style.less b/src/pages/role/components/style.less
new file mode 100644
index 0000000..b29c7c1
--- /dev/null
+++ b/src/pages/role/components/style.less
@@ -0,0 +1,152 @@
+// --- Rules help banner ---
+.perm-help-banner {
+ padding: 12px 14px;
+ margin-bottom: 12px;
+ background: linear-gradient(
+ 135deg,
+ rgba(79, 70, 229, 0.08),
+ rgba(14, 165, 233, 0.06)
+ );
+ border: 1px solid rgba(99, 102, 241, 0.18);
+ border-radius: 10px;
+ color: var(--text-secondary, #64748b);
+ font-size: 12px;
+ line-height: 1.65;
+
+ &__title {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ margin-bottom: 4px;
+
+ strong {
+ color: var(--text-primary, #1e293b);
+ font-size: 13px;
+ }
+ }
+}
+
+// --- Rules cards (2-column) ---
+.perm-rules-grid {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 12px;
+}
+
+.perm-rules-card {
+ padding: 14px;
+ border-radius: 12px;
+ min-height: 112px;
+ box-shadow: 0 6px 18px rgba(15, 23, 42, 0.04);
+
+ // full-width checkbox so entire card is clickable
+ .ant-checkbox-wrapper {
+ width: 100%;
+ align-items: flex-start;
+ }
+
+ // Card layout: [checkbox-indicator] [icon] [text]
+ &__inner {
+ display: flex;
+ gap: 12px;
+ align-items: flex-start;
+ }
+
+ &__icon {
+ width: 38px;
+ height: 38px;
+ border-radius: 10px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 18px;
+ flex-shrink: 0;
+ }
+
+ &__body {
+ display: flex;
+ flex-direction: column;
+ gap: 7px;
+ line-height: 1.35;
+ min-width: 0;
+ }
+
+ &__header {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ flex-wrap: wrap;
+ }
+
+ &__title {
+ font-size: 15px;
+ color: var(--text-primary, #1e293b);
+ font-weight: 600;
+ }
+
+ &__desc {
+ font-size: 12px;
+ }
+
+ // View card (blue)
+ &--view {
+ border: 1px solid rgba(59, 130, 246, 0.46);
+ background: rgba(239, 246, 255, 0.92);
+
+ .perm-rules-card__icon {
+ background: rgba(59, 130, 246, 0.12);
+ color: #2563eb;
+ }
+ }
+
+ // Manage card (orange)
+ &--manage {
+ border: 1px solid rgba(245, 158, 11, 0.48);
+ background: rgba(255, 251, 235, 0.92);
+
+ .perm-rules-card__icon {
+ background: rgba(245, 158, 11, 0.12);
+ color: #d97706;
+ }
+ }
+}
+
+// --- Divider between rules and other permissions ---
+.perm-divider {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ margin: 12px 0 8px;
+ color: var(--text-muted, #94a3b8);
+ font-size: 12px;
+ font-weight: 600;
+
+ &__line {
+ height: 1px;
+ background: var(--border-color, #e2e8f0);
+ flex: 1;
+ }
+}
+
+// --- Below section: other grouped + flat checkboxes ---
+.perm-below-grid {
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ gap: 4px 16px;
+ align-items: center;
+}
+
+.perm-checkbox--grouped {
+ padding: 6px 10px;
+ // font-weight: 600;
+}
+
+.perm-checkbox--flat {
+ padding: 6px 10px;
+ min-width: 190px;
+}
+
+.perm-checkbox-desc {
+ font-size: 12px;
+ margin-left: 8px;
+}
diff --git a/src/pages/role/index.tsx b/src/pages/role/index.tsx
index 36d0d06..60e6577 100644
--- a/src/pages/role/index.tsx
+++ b/src/pages/role/index.tsx
@@ -15,7 +15,12 @@ import HeadStatisticCard, {
} from '@/components/HeadStatisticCard';
import MyTag from '@/components/MyTag';
import useUserInfo from '@/hooks/useUserInfo';
-import { getCompanyList, getRoleList, roleHandle } from '@/services/api';
+import {
+ getCompanyList,
+ getRoleDetail,
+ getRoleList,
+ roleHandle,
+} from '@/services/api';
import { $t } from '@/utils/i18n';
import useRoleCardList from './cardList';
import Popup from './Popup';
@@ -33,7 +38,24 @@ const Role: React.FC = () => {
const { isGlobalCompany, isSuperAdmin, isCompanyAdmin } = useAccess();
const globalCompanyId = isGlobalCompany ? userInfo?.companyId : 0;
const tableRef = useRef