<template>
  <section
    class="system-permission-page"
    :class="{ 'system-permission-page--maintenance': permissionMainTab === 'maintenance' }"
    @click="closeContextMenu"
  >
    <header class="system-permission-hero compact-hero page-hero-card system-permission-hero-card">
      <div class="page-hero-copy">
        <p class="eyebrow">系统管理</p>
        <div class="system-permission-title-row">
          <h3>系统权限管理</h3>
          <div class="system-permission-main-tabs admin-tab-switcher" role="tablist" aria-label="系统权限管理页签">
            <button
              type="button"
              :class="{ active: permissionMainTab === 'org' }"
              @click="permissionMainTab = 'org'"
            >
              组织架构
            </button>
            <button
              type="button"
              :class="{ active: permissionMainTab === 'maintenance' }"
              @click="permissionMainTab = 'maintenance'"
            >
              角色维护
            </button>
          </div>
        </div>
        <p class="page-hero-subtitle">组织架构负责公司层级、人员授权和系统账号；角色维护负责菜单权限和业务身份。</p>
      </div>
    </header>

    <section
      v-if="permissionMainTab === 'org'"
      class="system-permission-map-card full-width-card"
      :class="{ 'tree-layout-card': orgViewMode === 'tree' }"
    >
      <div class="section-head">
        <div>
          <p class="eyebrow">组织架构</p>
          <h3>权限组织架构</h3>
          <p class="permission-note">脑图和组织树共用同一套组织数据；脑图模式下员工节点默认收拢，人员授权和移除都在组织架构里处理。</p>
        </div>
        <div class="mindmap-card-actions">
          <div class="org-view-switch" role="tablist" aria-label="组织架构展示模式">
            <button
              type="button"
              :class="{ active: orgViewMode === 'mindmap' }"
              @click.stop="orgViewMode = 'mindmap'"
            >
              脑图模式
            </button>
            <button
              type="button"
              :class="{ active: orgViewMode === 'tree' }"
              @click.stop="orgViewMode = 'tree'"
            >
              组织树模式
            </button>
          </div>
          <span class="status-pill">{{ orgNodeCount }} 个组织节点</span>
          <div v-if="orgViewMode === 'mindmap'" class="mindmap-toolbar" aria-label="脑图工具栏">
            <button type="button" title="放大" @click.stop="zoomMindMap(0.1)">放大</button>
            <button type="button" title="缩小" @click.stop="zoomMindMap(-0.1)">缩小</button>
            <button type="button" title="一屏展示" @click.stop="fitMindMapToScreen">一屏展示</button>
            <button type="button" title="刷新" @click.stop="refreshMindMap">刷新</button>
          </div>
        </div>
      </div>

      <OrgMindMap
        v-if="orgViewMode === 'mindmap'"
        :nodes="orgNodes"
        :zoom-scale="mindMapScale"
        :fit-request-key="mindMapFitRequestKey"
        @select-node="selectOrgNode"
        @node-contextmenu="openContextMenu"
        @toggle-employee-leaves="selectOrgNode"
        @fit-scale="applyMindMapFitScale"
      />
      <OrgPermissionTree
        v-else
        :nodes="orgNodes"
        :selected-node-id="selectedOrgNodeId"
        @select-node="selectOrgNode"
        @node-contextmenu="openContextMenu"
        @add-employee="openOrgEmployeeDrawer"
        @authorize-employee="openAuthorizeDrawer"
        @remove-employee="removeOrgEmployee"
      />
    </section>

    <section v-if="permissionMainTab === 'maintenance'" class="system-permission-maintenance-card full-width-card">
      <div class="section-head">
        <div>
          <p class="eyebrow">角色权限</p>
          <h3>角色维护</h3>
          <p class="permission-note">角色用于配置菜单权限和业务身份；人员授权请回到组织架构中对人员节点操作。</p>
        </div>
        <div class="row-actions">
          <button
            class="primary-button"
            type="button"
            @click="openRoleDrawer()"
          >
            新增角色
          </button>
        </div>
      </div>
      <div class="maintenance-table-panel">
        <div class="table-wrap">
          <table class="data-table compact-table">
            <thead>
              <tr>
                <th>角色名称</th>
                <th>角色编码</th>
                <th>系统人员数</th>
                <th>状态</th>
                <th>操作</th>
              </tr>
            </thead>
            <tbody>
              <tr v-for="role in paginatedRoles" :key="role.role_id || role.role_code || role.role_name">
                <td>{{ role.role_name || role.name || "未命名角色" }}</td>
                <td>{{ role.role_code || "未设置编码" }}</td>
                <td>{{ role.user_count || 0 }} 人</td>
                <td><StatusBadge :value="role.status" /></td>
                <td class="action-row">
                  <button class="ghost-button" type="button" @click="openRoleDrawer(role)">编辑</button>
                </td>
              </tr>
              <tr v-if="!roles.length">
                <td colspan="5" class="empty-row">暂无角色数据</td>
              </tr>
            </tbody>
          </table>
        </div>
        <PaginationBar v-model:page="rolePage" v-model:page-size="rolePageSize" :total="roles.length" />
      </div>
    </section>

    <div
      v-if="contextMenu.visible"
      class="org-context-menu"
      :style="{ left: `${contextMenu.x}px`, top: `${contextMenu.y}px` }"
      @click.stop
    >
      <button
        v-for="action in contextMenuActions"
        :key="action.key"
        type="button"
        @click="runNodeAction(action.key, contextMenu.node)"
      >
        {{ action.label }}
      </button>
    </div>

    <div v-if="showAuthorizeDrawer" class="workflow-drawer-mask system-permission-drawer-mask" @click.self="showAuthorizeDrawer = false">
      <aside class="form-drawer system-permission-drawer authorize-drawer">
        <div class="drawer-header authorize-drawer-header">
          <div>
            <p class="eyebrow">人员授权</p>
            <h2>{{ authorizingEmployee?.employee_name || "人员授权" }}</h2>
            <p class="authorize-header-note">为该人员创建或更新系统账号，并分配可访问的系统角色。</p>
          </div>
          <button class="ghost-button authorize-close-button" type="button" @click="showAuthorizeDrawer = false">关闭窗口</button>
        </div>

        <section class="authorize-profile-card" aria-label="授权对象">
          <div class="authorize-avatar">{{ authorizingEmployeeInitial }}</div>
          <div class="authorize-profile-main">
            <strong>{{ authorizingEmployee?.employee_name || "未命名人员" }}</strong>
            <span>{{ authorizingOrganizationPath }}</span>
          </div>
          <div class="authorize-profile-meta">
            <span>电话 / 账号：{{ authorizingEmployeePhone || "未设置电话号码" }}</span>
            <span>账号状态：<StatusBadge :value="authorizingSystemUser?.status" :text="authorizingSystemUser ? accountStatusLabel(authorizingSystemUser.status) : '未创建账号'" /></span>
          </div>
        </section>

        <section class="authorize-section authorize-role-section" aria-label="角色授权">
          <div class="authorize-section-head">
            <div>
              <p class="eyebrow">角色授权</p>
              <h3>选择系统角色</h3>
            </div>
            <span class="authorize-selected-count">已选 {{ selectedAuthorizeRoles.length }} 个角色</span>
          </div>
          <div class="authorize-selected-strip">
            <span v-if="selectedAuthorizeRoleNames.length">{{ selectedAuthorizeRoleNames.join("、") }}</span>
            <span v-else>尚未选择角色，至少选择一个角色后才能保存。</span>
          </div>
          <div class="authorize-role-grid">
            <button
              v-for="role in roles"
              :key="role.role_id"
              type="button"
              class="authorize-role-card"
              :class="{ active: isAuthorizeRoleSelected(role.role_id), danger: isHighRiskRole(role) }"
              @click="toggleAuthorizeRole(role.role_id)"
            >
              <span class="authorize-role-check" aria-hidden="true">{{ isAuthorizeRoleSelected(role.role_id) ? "✓" : "" }}</span>
              <span class="authorize-role-body">
                <strong>{{ roleDisplayName(role) }}</strong>
                <small>{{ roleDisplayCode(role) }}</small>
                <em>{{ roleRiskText(role) }}</em>
              </span>
            </button>
          </div>
        </section>

        <section class="authorize-section authorize-account-section" aria-label="账号设置">
          <div class="authorize-section-head">
            <div>
              <p class="eyebrow">账号设置</p>
              <h3>{{ authorizingSystemUser ? "账号状态" : "创建账号" }}</h3>
            </div>
          </div>
          <label v-if="!authorizingSystemUser" class="form-field authorize-password-field">
            <span>初始密码</span>
            <input v-model="authorizeForm.password" type="password" placeholder="首次创建账号必填，最少6位" />
          </label>
          <div v-else class="authorize-account-note">
            该人员已创建系统账号；本次仅更新角色和账号启停状态，如需修改密码请使用右上角账号重置入口。
          </div>
          <div class="authorize-status-switch" role="group" aria-label="账号状态">
            <button type="button" :class="{ active: authorizeForm.status === 'ACTIVE' }" @click="authorizeForm.status = 'ACTIVE'">启用账号</button>
            <button type="button" :class="{ active: authorizeForm.status === 'INACTIVE' }" @click="authorizeForm.status = 'INACTIVE'">停用账号</button>
          </div>
        </section>

        <div class="authorize-save-summary">
          将为 <strong>{{ authorizingEmployee?.employee_name || "该人员" }}</strong>
          授权 <strong>{{ selectedAuthorizeRoles.length }}</strong> 个角色，账号状态为
          <strong>{{ accountStatusLabel(authorizeForm.status) }}</strong>
        </div>

        <div class="drawer-actions authorize-actions">
          <button class="primary-button" type="button" :disabled="!authorizeForm.role_ids.length" @click="submitAuthorizeUser">保存授权</button>
          <button class="ghost-button" type="button" @click="showAuthorizeDrawer = false">取消</button>
        </div>
      </aside>
    </div>

    <div v-if="showRoleDrawer" class="workflow-drawer-mask system-permission-drawer-mask" @click.self="showRoleDrawer = false">
      <aside class="form-drawer system-permission-drawer">
        <div class="drawer-header">
          <div>
            <p class="eyebrow">角色权限</p>
            <h2>{{ editingRole ? "编辑角色" : "新增角色" }}</h2>
          </div>
          <button class="ghost-button" type="button" @click="showRoleDrawer = false">关闭</button>
        </div>

        <label class="form-field">
          <span>角色编码</span>
          <input v-model="roleForm.role_code" type="text" :readonly="Boolean(editingRole)" placeholder="请输入角色编码（大写字母、数字或下划线）" />
        </label>
        <label class="form-field">
          <span>角色名称</span>
          <input v-model="roleForm.role_name" type="text" placeholder="请输入角色名称" />
        </label>
        <label class="form-field">
          <span>角色范围</span>
          <select v-model="roleForm.role_scope">
            <option value="SYSTEM">系统角色</option>
            <option v-if="roleForm.role_scope && roleForm.role_scope !== 'SYSTEM'" :value="roleForm.role_scope">自定义范围</option>
          </select>
        </label>
        <label class="form-field">
          <span>状态</span>
          <select v-model="roleForm.status">
            <option value="ACTIVE">启用</option>
            <option value="INACTIVE">停用</option>
          </select>
        </label>
        <label class="form-field">
          <span>备注</span>
          <textarea v-model="roleForm.remark" rows="3" placeholder="请输入备注"></textarea>
        </label>

        <div class="form-field">
          <span>菜单权限</span>
          <div class="permission-tree">
            <template v-for="group in permissionTree" :key="group.permission_code">
              <label class="permission-check" :class="{ partial: isPermissionIndeterminate(group) }">
                <input
                  type="checkbox"
                  :checked="isPermissionChecked(group)"
                  :indeterminate="isPermissionIndeterminate(group)"
                  @change="togglePermissionNode(group, $event.target.checked)"
                />
                <strong>{{ group.permission_name }}</strong>
                <span v-if="isPermissionIndeterminate(group)" class="partial-note">部分已选</span>
              </label>
              <label
                v-for="child in group.children || []"
                :key="child.permission_code"
                class="permission-check child"
              >
                <input
                  type="checkbox"
                  :checked="isPermissionChecked(child)"
                  :indeterminate="isPermissionIndeterminate(child)"
                  @change="togglePermissionNode(child, $event.target.checked)"
                />
                <span>{{ child.permission_name }}</span>
              </label>
            </template>
            <p v-if="!permissionTree.length" class="empty-state">暂无菜单权限数据。</p>
          </div>
        </div>

        <div class="drawer-actions">
          <button class="primary-button" type="button" @click="submitRole">保存</button>
          <button class="ghost-button" type="button" @click="showRoleDrawer = false">取消</button>
        </div>
      </aside>
    </div>

    <div v-if="showOrgDrawer" class="workflow-drawer-mask system-permission-drawer-mask" @click.self="showOrgDrawer = false">
      <aside class="form-drawer system-permission-drawer">
        <div class="drawer-header">
          <div>
            <p class="eyebrow">组织脑图</p>
            <h2>{{ orgDrawerTitle }}</h2>
          </div>
          <button class="ghost-button" type="button" @click="showOrgDrawer = false">关闭</button>
        </div>

        <div v-if="orgDrawerMode === 'create' || orgDrawerMode === 'rename'">
          <p v-if="orgDrawerMode === 'create'" class="permission-note">
            将在「{{ orgForm.parent_label }}」下新增{{ nodeTypeLabel(orgForm.node_type) }}，只需要填写名称。
          </p>
          <label class="form-field">
            <span>{{ nodeTypeLabel(orgForm.node_type) }}名称</span>
            <input v-model="orgForm.node_label" type="text" placeholder="请输入名称" />
          </label>
        </div>

        <div v-else-if="orgDrawerMode === 'manager'">
          <p class="permission-note">支持绑定多位主管，直接点击人员卡片即可选中或取消，不需要按键盘组合键。</p>
          <div class="form-field">
            <span>多位主管</span>
            <div class="selected-manager-tags">
              <span
                v-for="manager in selectedManagerOptions"
                :key="manager.employee_id"
                class="selected-manager-tag"
              >
                {{ manager.employee_name }}
                <button type="button" @click="toggleOrgManager(manager.employee_id)">×</button>
              </span>
              <em v-if="!selectedManagerOptions.length">暂未选择主管</em>
            </div>
            <label class="manager-search-box">
              <span>搜索主管</span>
              <input
                v-model.trim="managerSearchKeyword"
                type="search"
                placeholder="搜索主管姓名或手机号，也可输入部门/岗位"
              />
            </label>
            <div class="manager-option-grid">
              <button
                v-for="employee in filteredManagerOptions"
                :key="employee.employee_id"
                type="button"
                :class="{ active: isOrgManagerSelected(employee.employee_id) }"
                @click="toggleOrgManager(employee.employee_id)"
              >
                <strong>{{ employee.employee_name }}</strong>
                <span>{{ employee.mobile || "无电话" }}</span>
                <span>{{ employee.dept_name || "未分部门" }}{{ employee.job_title ? ` · ${employee.job_title}` : "" }}</span>
              </button>
            </div>
            <p v-if="!filteredManagerOptions.length" class="manager-empty-state">
              {{ managerSearchKeyword ? "没有匹配的主管，请换个关键词试试。" : "暂无可选人员。" }}
            </p>
          </div>
        </div>

        <div v-else-if="orgDrawerMode === 'employee'">
          <p class="permission-note">新增人员是把基础资料人员挂到当前脑图节点，不会修改小程序人员主数据。</p>
          <label class="form-field">
            <span>人员</span>
            <select v-model="orgEmployeeForm.employee_id">
              <option value="">请选择人员</option>
              <option v-for="employee in employeeOptions" :key="employee.employee_id" :value="employee.employee_id">
                {{ employee.employee_name }} · {{ employee.mobile || "无电话" }}
              </option>
            </select>
          </label>
        </div>

        <div class="drawer-actions">
          <button class="primary-button" type="button" @click="submitOrgNode">保存</button>
          <button class="ghost-button" type="button" @click="showOrgDrawer = false">取消</button>
        </div>
      </aside>
    </div>
  </section>
</template>

<script setup>
import { computed, nextTick, onMounted, reactive, ref, watch } from "vue";

import OrgMindMap from "../components/OrgMindMap.vue";
import OrgPermissionTree from "../components/OrgPermissionTree.vue";
import PaginationBar from "../components/PaginationBar.vue";
import StatusBadge from "../components/StatusBadge.vue";
import { deleteResource, fetchResource, postResource, putResource } from "../services/api";
import { notifyError, notifySuccess } from "../utils/notifications";
import { usePagination } from "../utils/pagination";

const orgTree = ref([]);
const roles = ref([]);
const users = ref([]);
const employeeOptions = ref([]);
const permissionTree = ref([]);
const permissionMainTab = ref("org");
const orgViewMode = ref("mindmap");
const selectedNode = ref(null);
const mindMapScale = ref(1);
const mindMapFitRequestKey = ref(0);
const showAuthorizeDrawer = ref(false);
const showRoleDrawer = ref(false);
const showOrgDrawer = ref(false);
const editingRole = ref(null);
const editingOrgNode = ref(null);
const orgDrawerMode = ref("create");
const managerSearchKeyword = ref("");
const authorizingEmployee = ref(null);

const contextMenu = reactive({
  visible: false,
  x: 0,
  y: 0,
  node: null
});

const authorizeForm = reactive({
  role_ids: [],
  password: "",
  status: "ACTIVE"
});

const roleForm = reactive({
  role_code: "",
  role_name: "",
  role_scope: "SYSTEM",
  status: "ACTIVE",
  remark: "",
  permission_codes: []
});

const orgForm = reactive({
  parent_id: "",
  parent_label: "",
  node_type: "DEPARTMENT",
  node_label: "",
  dept_code: "",
  dept_type: "ADMIN",
  manager_employee_id: "",
  manager_employee_ids: [],
  sort_no: 0,
  remark: "",
  status: "ACTIVE"
});

const orgEmployeeForm = reactive({
  employee_id: "",
  sort_no: 0
});

const orgNodes = computed(() => {
  if (Array.isArray(orgTree.value)) {
    return orgTree.value;
  }
  return orgTree.value ? [orgTree.value] : [];
});

const orgNodeCount = computed(() => flattenOrgNodes(orgNodes.value).length);
const selectedOrgNodeId = computed(() => selectedNode.value?.node_id || orgNodes.value[0]?.node_id || "");

const authorizingSystemUser = computed(() => {
  const employeeId = authorizingEmployee.value?.employee_id;
  if (!employeeId) {
    return null;
  }
  return users.value.find((user) => String(user.employee_id) === String(employeeId)) || null;
});

const authorizingEmployeePhone = computed(() =>
  authorizingEmployee.value?.mobile || authorizingSystemUser.value?.mobile || authorizingSystemUser.value?.username || ""
);

const authorizingOrganizationPath = computed(() =>
  authorizingEmployee.value?.organization_path || authorizingEmployee.value?.parent_node_label || "未标记组织"
);

const authorizingEmployeeInitial = computed(() => {
  const name = authorizingEmployee.value?.employee_name || authorizingEmployee.value?.display_name || authorizingEmployee.value?.username || "人";
  return String(name).slice(0, 1);
});

const selectedAuthorizeRoles = computed(() => {
  const selectedIds = new Set(authorizeForm.role_ids.map(String));
  return roles.value.filter((role) => selectedIds.has(String(role.role_id)));
});

const selectedAuthorizeRoleNames = computed(() => selectedAuthorizeRoles.value.map((role) => roleDisplayName(role)));

const orgDrawerTitle = computed(() => {
  if (orgDrawerMode.value === "rename") {
    return "重命名";
  }
  if (orgDrawerMode.value === "manager") {
    return "添加该节点的主管";
  }
  if (orgDrawerMode.value === "employee") {
    return "新增人员";
  }
  return `新增${nodeTypeLabel(orgForm.node_type)}`;
});

const contextMenuActions = computed(() => (contextMenu.node ? nodeActions(contextMenu.node) : []));
const selectedManagerOptions = computed(() => {
  const selectedIds = new Set(orgForm.manager_employee_ids.map(String));
  return employeeOptions.value.filter((employee) => selectedIds.has(String(employee.employee_id)));
});

const filteredManagerOptions = computed(() => {
  const keyword = managerSearchKeyword.value.trim().toLowerCase();
  if (!keyword) {
    return employeeOptions.value;
  }
  return employeeOptions.value.filter((employee) => {
    const searchableText = [
      employee.employee_name,
      employee.mobile,
      employee.phone,
      employee.dept_name,
      employee.job_title,
      employee.position,
      employee.employee_code
    ]
      .filter(Boolean)
      .join(" ")
      .toLowerCase();
    return searchableText.includes(keyword);
  });
});

const roleRowsForTable = computed(() => roles.value);

const {
  page: rolePage,
  pageSize: rolePageSize,
  rows: paginatedRoles
} = usePagination(roleRowsForTable);

async function loadAll() {
  const [orgRows, roleRows, userRows, employeeRows, menuPermissionRows] = await Promise.all([
    fetchResource("/system-permissions/org-tree", []),
    fetchResource("/system-permissions/roles", []),
    fetchResource("/system-permissions/users", []),
    fetchResource("/system-permissions/employee-options", []),
    fetchResource("/system-permissions/menu-permission-tree", [])
  ]);
  orgTree.value = Array.isArray(orgRows) ? orgRows : [];
  roles.value = Array.isArray(roleRows) ? roleRows : [];
  users.value = Array.isArray(userRows) ? userRows : [];
  employeeOptions.value = Array.isArray(employeeRows) ? employeeRows : [];
  permissionTree.value = Array.isArray(menuPermissionRows) ? menuPermissionRows : [];
}

function flattenOrgNodes(nodes) {
  const result = [];
  for (const node of nodes || []) {
    result.push(node);
    result.push(...flattenOrgNodes(node.children || []));
  }
  return result;
}

function selectOrgNode(node) {
  selectedNode.value = node;
}

function zoomMindMap(delta) {
  const nextScale = Number((mindMapScale.value + delta).toFixed(1));
  setMindMapScale(nextScale);
}

function setMindMapScale(scale) {
  const numericScale = Number(scale || 1);
  mindMapScale.value = Math.min(1.8, Math.max(0.12, numericScale));
}

function applyMindMapFitScale(scale) {
  const numericScale = Number(scale || 1);
  mindMapScale.value = Math.min(1, Math.max(0.12, numericScale));
}

async function requestMindMapFitToScreen({ showToast = false, closeMenu = false } = {}) {
  if (closeMenu) {
    closeContextMenu();
  }
  await nextTick();
  if (permissionMainTab.value !== "org" || orgViewMode.value !== "mindmap") {
    return;
  }
  mindMapFitRequestKey.value += 1;
  if (showToast) {
    notifySuccess("脑图已按当前展开状态适配一屏");
  }
}

function fitMindMapToScreen() {
  requestMindMapFitToScreen({ showToast: true, closeMenu: true });
}

async function refreshMindMap() {
  closeContextMenu();
  await loadAll();
  notifySuccess("脑图已刷新");
}

function nodeTypeLabel(type) {
  return {
    COMPANY: "总公司",
    BRANCH: "分公司",
    DEPARTMENT: "部门",
    GROUP: "小组",
    EMPLOYEE: "人员"
  }[type] || "组织";
}

function isOrgManagerSelected(employeeId) {
  return orgForm.manager_employee_ids.map(String).includes(String(employeeId));
}

function toggleOrgManager(employeeId) {
  const targetId = String(employeeId);
  if (isOrgManagerSelected(targetId)) {
    orgForm.manager_employee_ids = orgForm.manager_employee_ids.filter((id) => String(id) !== targetId);
  } else {
    orgForm.manager_employee_ids = [...orgForm.manager_employee_ids, targetId];
  }
}

function defaultDeptType(type) {
  return {
    COMPANY: "ADMIN",
    BRANCH: "ADMIN",
    DEPARTMENT: "ADMIN",
    GROUP: "ADMIN"
  }[type] || "ADMIN";
}

function isAuthorizeRoleSelected(roleId) {
  return authorizeForm.role_ids.map(String).includes(String(roleId));
}

function toggleAuthorizeRole(roleId) {
  const targetId = String(roleId);
  if (isAuthorizeRoleSelected(targetId)) {
    authorizeForm.role_ids = authorizeForm.role_ids.filter((id) => String(id) !== targetId);
  } else {
    authorizeForm.role_ids = [...authorizeForm.role_ids, targetId];
  }
}

function roleDisplayName(role) {
  return role?.role_name || role?.name || role?.role_code || "未命名角色";
}

function roleDisplayCode(role) {
  return role?.role_code ? `角色编码：${role.role_code}` : "未设置角色编码";
}

function isHighRiskRole(role) {
  const text = [role?.role_code, roleDisplayName(role)].filter(Boolean).join(" ").toUpperCase();
  return text.includes("ADMIN") || text.includes("超级") || text.includes("管理员");
}

function roleRiskText(role) {
  if (isHighRiskRole(role)) {
    return "高权限角色，请谨慎授权";
  }
  return "业务角色，可按岗位职责授权";
}

function accountStatusLabel(status) {
  if (status === "INACTIVE") {
    return "停用";
  }
  return "启用";
}

function nodeActions(node) {
  if (!node) {
    return [];
  }
  if (node.employee_id) {
    return [
      { key: "authorizeEmployee", label: "授权" },
      { key: "removeEmployee", label: "移除" }
    ];
  }
  const actions = [
    { key: "rename", label: "重命名" },
    { key: "manager", label: "添加该节点的主管" }
  ];
  if (node.node_type === "COMPANY") {
    actions.push({ key: "addBranch", label: "新增分公司节点" });
    actions.push({ key: "addDepartment", label: "新增直属部门" });
  }
  if (node.node_type === "BRANCH") {
    actions.push({ key: "addDepartment", label: "新增部门节点" });
  }
  if (node.node_type === "DEPARTMENT") {
    actions.push({ key: "addGroup", label: "新增小组节点" });
    actions.push({ key: "addEmployee", label: "新增人员" });
  }
  if (node.node_type === "GROUP") {
    actions.push({ key: "addEmployee", label: "新增人员" });
  }
  if (node.dept_code !== "ORG_ROOT") {
    actions.push({ key: "delete", label: "删除节点" });
  }
  return actions;
}

function openContextMenu(eventPayload) {
  selectedNode.value = eventPayload.node;
  const menuWidth = 220;
  const menuHeight = 280;
  const viewportWidth = window.innerWidth || 1280;
  const viewportHeight = window.innerHeight || 720;
  contextMenu.visible = true;
  contextMenu.x = Math.max(12, Math.min(Number(eventPayload.x || 12), viewportWidth - menuWidth - 12));
  contextMenu.y = Math.max(12, Math.min(Number(eventPayload.y || 12), viewportHeight - menuHeight - 12));
  contextMenu.node = eventPayload.node;
}

function closeContextMenu() {
  contextMenu.visible = false;
}

function runNodeAction(actionKey, node) {
  closeContextMenu();
  if (!node) {
    return;
  }
  if (actionKey === "rename") {
    openOrgRenameDrawer(node);
  } else if (actionKey === "manager") {
    openOrgManagerDrawer(node);
  } else if (actionKey === "addBranch") {
    openOrgCreateDrawer(node, "BRANCH");
  } else if (actionKey === "addDepartment") {
    openOrgCreateDrawer(node, "DEPARTMENT");
  } else if (actionKey === "addGroup") {
    openOrgCreateDrawer(node, "GROUP");
  } else if (actionKey === "addEmployee") {
    openOrgEmployeeDrawer(node);
  } else if (actionKey === "authorizeEmployee") {
    openAuthorizeDrawer(node);
  } else if (actionKey === "removeEmployee") {
    removeOrgEmployee(node);
  } else if (actionKey === "delete") {
    removeOrgNode(node);
  }
}

function fillOrgFormFromNode(node) {
  editingOrgNode.value = node;
  orgForm.parent_id = node?.parent_id ?? "";
  orgForm.parent_label = "";
  orgForm.node_type = node?.node_type || "DEPARTMENT";
  orgForm.node_label = node?.node_label || "";
  orgForm.dept_code = node?.dept_code || "";
  orgForm.dept_type = node?.dept_type || "ADMIN";
  orgForm.manager_employee_id = node?.manager_employee_id ?? "";
  orgForm.manager_employee_ids = Array.isArray(node?.manager_employee_ids) && node.manager_employee_ids.length
    ? node.manager_employee_ids.map(String)
    : node?.manager_employee_id
      ? [String(node.manager_employee_id)]
      : [];
  orgForm.sort_no = node?.sort_no ?? 0;
  orgForm.remark = node?.remark || "";
  orgForm.status = node?.status || "ACTIVE";
}

function openOrgCreateDrawer(parent, nodeType) {
  editingOrgNode.value = null;
  orgDrawerMode.value = "create";
  orgForm.parent_id = parent?.node_id ?? "";
  orgForm.parent_label = parent?.node_label || "当前节点";
  orgForm.node_type = nodeType;
  orgForm.node_label = "";
  orgForm.dept_code = "";
  orgForm.dept_type = defaultDeptType(nodeType);
  orgForm.manager_employee_id = "";
  orgForm.manager_employee_ids = [];
  orgForm.sort_no = 0;
  orgForm.remark = "";
  orgForm.status = "ACTIVE";
  showOrgDrawer.value = true;
}

function openOrgRenameDrawer(node) {
  orgDrawerMode.value = "rename";
  fillOrgFormFromNode(node);
  showOrgDrawer.value = true;
}

function openOrgManagerDrawer(node) {
  orgDrawerMode.value = "manager";
  fillOrgFormFromNode(node);
  managerSearchKeyword.value = "";
  showOrgDrawer.value = true;
}

function openOrgEmployeeDrawer(node) {
  orgDrawerMode.value = "employee";
  fillOrgFormFromNode(node);
  orgEmployeeForm.employee_id = "";
  orgEmployeeForm.sort_no = (node?.employees?.length || 0) + 1;
  showOrgDrawer.value = true;
}

function openOrgDrawer(parent = null, node = null) {
  if (node) {
    openOrgRenameDrawer(node);
    return;
  }
  openOrgCreateDrawer(parent || orgNodes.value[0], parent?.node_type === "COMPANY" ? "BRANCH" : "DEPARTMENT");
}

async function submitOrgNode() {
  try {
    if (orgDrawerMode.value === "employee") {
      if (!orgEmployeeForm.employee_id) {
        notifyError("请选择人员");
        return;
      }
      await postResource(`/system-permissions/org-nodes/${editingOrgNode.value.node_id}/employees`, {
        employee_id: Number(orgEmployeeForm.employee_id),
        sort_no: Number(orgEmployeeForm.sort_no || 0)
      });
      notifySuccess("人员已加入组织节点");
    } else {
      if (!orgForm.node_label.trim() && orgDrawerMode.value !== "manager") {
        notifyError("请输入名称");
        return;
      }
      const updatePayload = {
        node_label: orgForm.node_label.trim() || editingOrgNode.value?.node_label || "",
        dept_type: orgForm.dept_type || "ADMIN",
        manager_employee_id: orgForm.manager_employee_ids.length ? Number(orgForm.manager_employee_ids[0]) : null,
        manager_employee_ids: orgForm.manager_employee_ids.map(Number),
        sort_no: Number(orgForm.sort_no || 0),
        remark: orgForm.remark,
        status: orgForm.status
      };
      const createPayload = {
        parent_id: orgForm.parent_id ? Number(orgForm.parent_id) : null,
        node_type: orgForm.node_type,
        dept_code: orgForm.dept_code.trim() || null,
        ...updatePayload
      };

      if (editingOrgNode.value) {
        await putResource(`/system-permissions/org-nodes/${editingOrgNode.value.node_id}`, updatePayload);
        notifySuccess(orgDrawerMode.value === "manager" ? "主管已更新" : "节点已更新");
      } else {
        await postResource("/system-permissions/org-nodes", createPayload);
        notifySuccess("组织节点已新增");
      }
    }

    showOrgDrawer.value = false;
    editingOrgNode.value = null;
    await loadAll();
  } catch (error) {
    notifyError(error.message || "组织架构保存失败");
  }
}

async function removeOrgNode(node) {
  if (!window.confirm(`确认删除「${node.node_label}」吗？有下级或人员时系统会阻止删除。`)) {
    return;
  }
  try {
    await deleteResource(`/system-permissions/org-nodes/${node.node_id}`);
    notifySuccess("组织节点已删除");
    selectedNode.value = null;
    await loadAll();
  } catch (error) {
    notifyError(error.message || "组织节点删除失败");
  }
}

async function removeOrgEmployee(node) {
  const parentNodeId = node.parent_node_id;
  if (!parentNodeId) {
    notifyError("缺少上级组织节点，无法移除人员");
    return;
  }
  if (!window.confirm(`确认从组织架构中移除「${node.employee_name}」吗？不会删除人员主数据。`)) {
    return;
  }
  try {
    await deleteResource(`/system-permissions/org-nodes/${parentNodeId}/employees/${node.employee_id}`);
    notifySuccess("人员已从组织架构移除");
    selectedNode.value = null;
    await loadAll();
  } catch (error) {
    notifyError(error.message || "人员移除失败");
  }
}

function openAuthorizeDrawer(employee) {
  const existingUser = users.value.find((user) => String(user.employee_id) === String(employee?.employee_id));
  authorizingEmployee.value = employee;
  authorizeForm.role_ids = existingUser?.role_ids?.length
    ? existingUser.role_ids.map(String)
    : (employee?.role_ids || []).map(String);
  authorizeForm.password = "";
  authorizeForm.status = existingUser?.status || "ACTIVE";
  showAuthorizeDrawer.value = true;
}

async function submitAuthorizeUser() {
  if (!authorizingEmployee.value?.employee_id) {
    notifyError("请选择有效人员");
    return;
  }
  if (!authorizingEmployeePhone.value) {
    notifyError("该人员没有电话号码，不能作为账号");
    return;
  }
  if (!authorizeForm.role_ids.length) {
    notifyError("请选择角色");
    return;
  }
  if (!authorizingSystemUser.value && (!authorizeForm.password || authorizeForm.password.length < 6)) {
    notifyError("密码最少6位");
    return;
  }

  try {
    if (authorizingSystemUser.value) {
      await putResource(`/system-permissions/users/${authorizingSystemUser.value.user_id}/roles`, {
        role_ids: authorizeForm.role_ids.map(Number)
      });
      if (authorizingSystemUser.value.status !== authorizeForm.status) {
        await putResource(`/system-permissions/users/${authorizingSystemUser.value.user_id}/status`, {
          status: authorizeForm.status
        });
      }
      notifySuccess("人员角色授权已更新");
    } else {
      await postResource("/system-permissions/users", {
        employee_id: Number(authorizingEmployee.value.employee_id),
        role_ids: authorizeForm.role_ids.map(Number),
        password: authorizeForm.password,
        status: authorizeForm.status
      });
      notifySuccess("系统账号已创建并授权");
    }
    showAuthorizeDrawer.value = false;
    authorizingEmployee.value = null;
    await loadAll();
  } catch (error) {
    notifyError(error.message || "人员授权失败");
  }
}

function openRoleDrawer(role = null) {
  editingRole.value = role;
  roleForm.role_code = role?.role_code || "";
  roleForm.role_name = role?.role_name || "";
  roleForm.role_scope = role?.role_scope || "SYSTEM";
  roleForm.status = role?.status || "ACTIVE";
  roleForm.remark = role?.remark || "";
  roleForm.permission_codes = [...(role?.permission_codes || [])];
  showRoleDrawer.value = true;
}

function collectPermissionCodes(node) {
  const codes = node?.permission_code ? [node.permission_code] : [];
  for (const child of node?.children || []) {
    codes.push(...collectPermissionCodes(child));
  }
  return codes;
}

function collectPersistablePermissionCodes(node) {
  const children = node?.children || [];
  if (children.length) {
    return children.flatMap((child) => collectPersistablePermissionCodes(child));
  }
  return node?.permission_code ? [node.permission_code] : [];
}

function isPermissionChecked(node) {
  const codes = collectPersistablePermissionCodes(node);
  if (!codes.length) {
    return false;
  }
  const selectedCodes = new Set(roleForm.permission_codes);
  return codes.every((code) => selectedCodes.has(code));
}

function isPermissionIndeterminate(node) {
  const descendantCodes = (node?.children || []).flatMap((child) => collectPersistablePermissionCodes(child));
  if (!descendantCodes.length) {
    return false;
  }
  const selectedCodes = new Set(roleForm.permission_codes);
  const selectedDescendantCount = descendantCodes.filter((code) => selectedCodes.has(code)).length;
  return selectedDescendantCount > 0 && selectedDescendantCount < descendantCodes.length;
}

function togglePermissionNode(node, checked) {
  const next = new Set(roleForm.permission_codes);
  for (const code of collectPersistablePermissionCodes(node)) {
    if (checked) {
      next.add(code);
    } else {
      next.delete(code);
    }
  }
  roleForm.permission_codes = Array.from(next);
}

async function submitRole() {
  if (!roleForm.role_name.trim()) {
    notifyError("请输入角色名称");
    return;
  }
  if (!editingRole.value && !roleForm.role_code.trim()) {
    notifyError("请输入角色编码");
    return;
  }

  const payload = {
    role_name: roleForm.role_name.trim(),
    role_scope: roleForm.role_scope.trim() || "SYSTEM",
    status: roleForm.status,
    remark: roleForm.remark,
    permission_codes: roleForm.permission_codes
  };

  try {
    if (editingRole.value) {
      await putResource(`/system-permissions/roles/${editingRole.value.role_id}`, payload);
    } else {
      await postResource("/system-permissions/roles", {
        role_code: roleForm.role_code.trim(),
        ...payload
      });
    }
    notifySuccess("角色已保存");
    showRoleDrawer.value = false;
    await loadAll();
  } catch (error) {
    notifyError(error.message || "角色保存失败");
  }
}

watch(
  [permissionMainTab, orgViewMode],
  ([mainTab, viewMode]) => {
    if (mainTab === "org" && viewMode === "mindmap") {
      requestMindMapFitToScreen();
    }
  }
);

onMounted(async () => {
  await loadAll();
  await requestMindMapFitToScreen();
});
</script>

<style scoped>
.system-permission-page {
  display: flex;
  flex-direction: column;
  gap: 18px;
  position: relative;
}

.system-permission-hero,
.system-permission-map-card,
.system-permission-side-card {
  border: 1px solid rgba(15, 23, 42, 0.08);
  border-radius: 28px;
  background: rgba(255, 255, 255, 0.88);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.08);
}

.system-permission-hero {
  padding: 20px 24px;
  background:
    radial-gradient(circle at 12% 20%, rgba(96, 165, 250, 0.2), transparent 28%),
    linear-gradient(135deg, #f8fafc, #eff6ff);
}

.compact-hero {
  min-height: unset;
}

.system-permission-hero h2,
.section-head h3,
.drawer-header h2 {
  margin: 0;
  color: #0f172a;
}

.system-permission-hero p {
  margin: 8px 0 0;
  color: #475569;
}

.system-permission-title-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  min-width: 0;
}

.system-permission-title-row .system-permission-main-tabs {
  display: inline-flex;
  width: auto;
  max-width: 100%;
  grid-template-columns: none;
  gap: 4px;
  padding: 4px;
}

.system-permission-title-row .system-permission-main-tabs button {
  min-width: clamp(58px, 8vw, 132px);
  padding: 7px clamp(6px, 0.9vw, 12px);
  font-size: clamp(13px, 0.8vw, 14px);
  line-height: 1.15;
  white-space: nowrap;
}

.system-permission-main-tabs {
  display: inline-grid;
  grid-template-columns: repeat(2, minmax(180px, 1fr));
  gap: 8px;
  align-self: flex-start;
  padding: 6px;
  border: 1px solid rgba(37, 99, 235, 0.12);
  border-radius: 18px;
  background: #eef6ff;
}

.system-permission-main-tabs button {
  border: 0;
  border-radius: 14px;
  padding: 12px 18px;
  background: transparent;
  color: #475569;
  font-weight: 800;
  cursor: pointer;
}

.system-permission-main-tabs button.active {
  background: #ffffff;
  color: #1d4ed8;
  box-shadow: 0 12px 24px rgba(37, 99, 235, 0.14);
}

.system-permission-maintenance-card {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.maintenance-table-panel {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.full-width-card,
.system-permission-side-card {
  padding: 22px;
}

.section-head,
.drawer-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 16px;
}

.section-head.compact {
  margin-bottom: 12px;
}

.eyebrow {
  margin: 0 0 6px;
  color: #2563eb;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.status-pill {
  display: inline-flex;
  align-items: center;
  border-radius: 999px;
  padding: 6px 10px;
  background: #dbeafe;
  color: #1d4ed8;
  font-size: 12px;
  font-weight: 700;
  white-space: nowrap;
}

.permission-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.permission-list li {
  display: flex;
  flex-direction: column;
  gap: 10px;
  border: 1px solid rgba(15, 23, 42, 0.08);
  border-radius: 16px;
  padding: 12px;
  background: #f8fafc;
}

.permission-list li > div:first-child {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.permission-list span,
.permission-note,
.empty-state {
  color: #64748b;
  font-size: 13px;
}

.row-actions,
.drawer-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.drawer-actions {
  justify-content: flex-end;
  margin-top: 18px;
}

.primary-button,
.ghost-button {
  border: 0;
  border-radius: 999px;
  padding: 10px 16px;
  font-weight: 700;
  cursor: pointer;
}

.primary-button {
  background: #2563eb;
  color: #ffffff;
}

.ghost-button {
  background: #eff6ff;
  color: #1d4ed8;
}

.mindmap-card-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 10px;
}

.org-view-switch {
  display: inline-flex;
  gap: 6px;
  padding: 6px;
  border: 1px solid rgba(37, 99, 235, 0.12);
  border-radius: 999px;
  background: rgba(239, 246, 255, 0.92);
}

.org-view-switch button {
  border: 0;
  border-radius: 999px;
  padding: 8px 12px;
  background: transparent;
  color: #475569;
  font-size: 13px;
  font-weight: 800;
  cursor: pointer;
}

.org-view-switch button.active {
  background: #ffffff;
  color: #1d4ed8;
  box-shadow: 0 10px 20px rgba(37, 99, 235, 0.14);
}

.mindmap-toolbar {
  display: inline-flex;
  gap: 6px;
  padding: 6px;
  border: 1px solid rgba(37, 99, 235, 0.12);
  border-radius: 999px;
  background: rgba(239, 246, 255, 0.92);
  box-shadow: 0 12px 28px rgba(37, 99, 235, 0.12);
}

.mindmap-toolbar button {
  border: 0;
  border-radius: 999px;
  padding: 8px 12px;
  background: #ffffff;
  color: #1d4ed8;
  font-size: 13px;
  font-weight: 800;
  cursor: pointer;
}

.mindmap-toolbar button:hover {
  background: #2563eb;
  color: #ffffff;
}

.org-context-menu {
  position: fixed;
  z-index: 120;
  display: flex;
  flex-direction: column;
  min-width: 180px;
  padding: 8px;
  border: 1px solid rgba(15, 23, 42, 0.1);
  border-radius: 16px;
  background: rgba(255, 255, 255, 0.98);
  box-shadow: 0 18px 42px rgba(15, 23, 42, 0.18);
}

.org-context-menu button {
  border: 0;
  border-radius: 10px;
  padding: 10px 12px;
  background: transparent;
  color: #0f172a;
  text-align: left;
  font-weight: 700;
  cursor: pointer;
}

.org-context-menu button:hover {
  background: #eff6ff;
  color: #1d4ed8;
}

.system-permission-drawer-mask {
  z-index: 90;
}

.system-permission-drawer {
  display: flex;
  flex-direction: column;
  gap: 14px;
  width: min(520px, calc(100vw - 32px));
  max-height: calc(100vh - 32px);
  overflow-y: auto;
  padding: 24px;
  background: #ffffff;
}

.authorize-drawer {
  width: min(760px, calc(100vw - 32px));
  gap: 16px;
}

.authorize-drawer-header {
  align-items: flex-start;
}

.authorize-header-note {
  margin: 6px 0 0;
  color: #64748b;
  font-size: 13px;
  font-weight: 700;
}

.authorize-close-button {
  min-width: 108px;
}

.authorize-profile-card,
.authorize-section,
.authorize-save-summary {
  border: 1px solid rgba(190, 205, 224, 0.95);
  border-radius: 20px;
  background: rgba(255, 255, 255, 0.9);
  box-shadow: 0 10px 22px rgba(15, 23, 42, 0.05);
}

.authorize-profile-card {
  display: grid;
  grid-template-columns: 58px minmax(0, 1fr) minmax(220px, 0.72fr);
  align-items: center;
  gap: 14px;
  padding: 16px;
  background:
    linear-gradient(135deg, rgba(239, 246, 255, 0.96), rgba(255, 255, 255, 0.92));
}

.authorize-avatar {
  display: grid;
  place-items: center;
  width: 54px;
  height: 54px;
  border-radius: 18px;
  background: linear-gradient(135deg, #2563eb, #38bdf8);
  color: #ffffff;
  font-size: 24px;
  font-weight: 900;
  box-shadow: 0 12px 26px rgba(37, 99, 235, 0.24);
}

.authorize-profile-main,
.authorize-profile-meta {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 6px;
}

.authorize-profile-main strong {
  color: #0f172a;
  font-size: 22px;
  font-weight: 900;
}

.authorize-profile-main span,
.authorize-profile-meta span {
  overflow: hidden;
  color: #475569;
  font-size: 13px;
  font-weight: 750;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.authorize-section {
  display: grid;
  gap: 12px;
  padding: 16px;
}

.authorize-section-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
}

.authorize-section-head h3 {
  margin: 0;
  color: #0f172a;
  font-size: 18px;
}

.authorize-selected-count {
  flex: 0 0 auto;
  border-radius: 999px;
  padding: 6px 10px;
  background: #dbeafe;
  color: #1d4ed8;
  font-size: 12px;
  font-weight: 850;
}

.authorize-selected-strip {
  min-height: 36px;
  border: 1px dashed rgba(96, 165, 250, 0.5);
  border-radius: 14px;
  padding: 9px 12px;
  background: #f8fbff;
  color: #475569;
  font-size: 13px;
  font-weight: 750;
}

.authorize-role-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 10px;
}

.authorize-role-card {
  position: relative;
  display: grid;
  grid-template-columns: 26px minmax(0, 1fr);
  align-items: flex-start;
  gap: 10px;
  min-height: 96px;
  border: 1px solid rgba(190, 205, 224, 0.95);
  border-radius: 18px;
  padding: 14px;
  background: linear-gradient(180deg, #ffffff, #f8fafc);
  color: #0f172a;
  text-align: left;
  cursor: pointer;
  transition: border-color 0.16s ease, box-shadow 0.16s ease, transform 0.16s ease, background 0.16s ease;
}

.authorize-role-card:hover {
  border-color: rgba(37, 99, 235, 0.42);
  box-shadow: 0 12px 26px rgba(15, 23, 42, 0.08);
  transform: translateY(-1px);
}

.authorize-role-card.active {
  border-color: rgba(37, 99, 235, 0.78);
  background: linear-gradient(180deg, #eff6ff, #ffffff);
  box-shadow: inset 0 0 0 1px rgba(37, 99, 235, 0.18), 0 14px 28px rgba(37, 99, 235, 0.12);
}

.authorize-role-card.danger.active {
  border-color: rgba(249, 115, 22, 0.86);
  background: linear-gradient(180deg, #fff7ed, #ffffff);
  box-shadow: inset 0 0 0 1px rgba(249, 115, 22, 0.2), 0 14px 28px rgba(249, 115, 22, 0.12);
}

.authorize-role-check {
  display: inline-grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border: 1px solid rgba(148, 163, 184, 0.72);
  border-radius: 8px;
  background: #ffffff;
  color: #2563eb;
  font-size: 14px;
  font-weight: 950;
}

.authorize-role-card.active .authorize-role-check {
  border-color: #2563eb;
  background: #2563eb;
  color: #ffffff;
}

.authorize-role-card.danger.active .authorize-role-check {
  border-color: #f97316;
  background: #f97316;
}

.authorize-role-body {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 5px;
}

.authorize-role-body strong,
.authorize-role-body small,
.authorize-role-body em {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.authorize-role-body strong {
  color: #0f172a;
  font-size: 16px;
  font-style: normal;
  font-weight: 900;
}

.authorize-role-body small {
  color: #64748b;
  font-size: 12px;
  font-weight: 750;
}

.authorize-role-body em {
  width: fit-content;
  max-width: 100%;
  border-radius: 999px;
  padding: 3px 8px;
  background: #eef6ff;
  color: #2563eb;
  font-size: 11px;
  font-style: normal;
  font-weight: 850;
}

.authorize-role-card.danger .authorize-role-body em {
  background: #fff7ed;
  color: #c2410c;
}

.authorize-account-section {
  background:
    linear-gradient(135deg, rgba(248, 250, 252, 0.98), rgba(255, 255, 255, 0.92));
}

.authorize-password-field {
  margin: 0;
}

.authorize-account-note {
  border: 1px solid rgba(148, 163, 184, 0.26);
  border-radius: 14px;
  padding: 11px 12px;
  background: #f8fafc;
  color: #475569;
  font-size: 13px;
  font-weight: 750;
  line-height: 1.6;
}

.authorize-status-switch {
  display: inline-flex;
  width: fit-content;
  border: 1px solid rgba(190, 205, 224, 0.95);
  border-radius: 999px;
  padding: 4px;
  background: #f8fafc;
  gap: 4px;
}

.authorize-status-switch button {
  border: 0;
  border-radius: 999px;
  padding: 8px 16px;
  background: transparent;
  color: #64748b;
  font-weight: 850;
  cursor: pointer;
}

.authorize-status-switch button.active {
  background: #2563eb;
  color: #ffffff;
  box-shadow: 0 8px 18px rgba(37, 99, 235, 0.22);
}

.authorize-save-summary {
  padding: 13px 16px;
  color: #475569;
  font-size: 13px;
  font-weight: 750;
}

.authorize-save-summary strong {
  color: #0f172a;
  font-weight: 900;
}

.authorize-actions {
  justify-content: flex-end;
}

.permission-tree {
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-height: 260px;
  overflow-y: auto;
  border: 1px solid rgba(15, 23, 42, 0.08);
  border-radius: 16px;
  padding: 12px;
  background: #f8fafc;
}

.authorize-summary {
  display: grid;
  gap: 8px;
  border: 1px solid rgba(37, 99, 235, 0.12);
  border-radius: 16px;
  padding: 12px;
  background: #f8fbff;
  color: #475569;
  font-size: 13px;
  font-weight: 700;
}

.permission-check {
  display: flex;
  align-items: center;
  gap: 8px;
  color: #0f172a;
  font-size: 14px;
}

.permission-check.child {
  padding-left: 24px;
  color: #475569;
}

.selected-manager-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  min-height: 38px;
  padding: 8px;
  border: 1px dashed rgba(37, 99, 235, 0.24);
  border-radius: 14px;
  background: #f8fbff;
}

.selected-manager-tags em {
  color: #94a3b8;
  font-size: 13px;
  font-style: normal;
}

.selected-manager-tag {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border-radius: 999px;
  padding: 7px 10px;
  background: #dbeafe;
  color: #1d4ed8;
  font-size: 13px;
  font-weight: 800;
}

.selected-manager-tag button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border: 0;
  border-radius: 50%;
  background: #ffffff;
  color: #2563eb;
  cursor: pointer;
  font-weight: 900;
}

.manager-search-box {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin: 4px 0;
}

.manager-search-box span {
  color: #475569;
  font-size: 13px;
  font-weight: 800;
}

.manager-search-box input {
  width: 100%;
  border: 1px solid rgba(15, 23, 42, 0.1);
  border-radius: 14px;
  padding: 10px 12px;
  background: #ffffff;
  color: #0f172a;
  font-size: 14px;
  outline: none;
  transition: border-color 0.18s ease, box-shadow 0.18s ease;
}

.manager-search-box input:focus {
  border-color: rgba(37, 99, 235, 0.62);
  box-shadow: 0 0 0 4px rgba(37, 99, 235, 0.1);
}

.manager-option-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 10px;
  max-height: 280px;
  overflow-y: auto;
  padding: 4px;
}

.manager-option-grid button {
  display: flex;
  flex-direction: column;
  gap: 4px;
  border: 1px solid rgba(15, 23, 42, 0.08);
  border-radius: 16px;
  padding: 12px;
  background: #f8fafc;
  color: #0f172a;
  text-align: left;
  cursor: pointer;
}

.manager-option-grid button.active {
  border-color: rgba(37, 99, 235, 0.7);
  background: linear-gradient(135deg, #eff6ff, #dbeafe);
  box-shadow: inset 4px 0 0 #2563eb;
}

.manager-option-grid button strong {
  font-size: 14px;
}

.manager-option-grid button span {
  color: #64748b;
  font-size: 12px;
}

.manager-empty-state {
  margin: 0;
  border: 1px dashed rgba(148, 163, 184, 0.5);
  border-radius: 14px;
  padding: 12px;
  background: #f8fafc;
  color: #64748b;
  font-size: 13px;
  text-align: center;
}

@media (max-width: 980px) {
  .section-head,
  .mindmap-card-actions {
    align-items: flex-start;
    flex-direction: column;
  }

  .system-permission-main-tabs {
    width: 100%;
    grid-template-columns: 1fr;
  }
}
</style>
