smart-admin-web 10.20.1 → 10.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. package/dist/api/index.d.ts +19 -1
  2. package/dist/api/index.js +85 -66
  3. package/dist/api/index.js.map +1 -1
  4. package/dist/api/schema.d.ts +448 -1
  5. package/dist/assets/icons/ph-subset.json.js +1 -1
  6. package/dist/components/FormContainer/index.vue.js +87 -75
  7. package/dist/components/FormContainer/index.vue.js.map +1 -1
  8. package/dist/components/UserPicker/UserAvatar.vue.d.ts +8 -0
  9. package/dist/components/UserPicker/UserAvatar.vue.js +8 -0
  10. package/dist/components/UserPicker/UserAvatar.vue.js.map +1 -0
  11. package/dist/components/UserPicker/UserAvatar2.vue.js +38 -0
  12. package/dist/components/UserPicker/UserAvatar2.vue.js.map +1 -0
  13. package/dist/components/UserPicker/index.vue.js +1 -1
  14. package/dist/components/UserPicker/index2.vue.js +328 -186
  15. package/dist/components/UserPicker/index2.vue.js.map +1 -1
  16. package/dist/index.js +248 -246
  17. package/dist/lib/runtime.js +1 -1
  18. package/dist/lib/watermark.d.ts +1 -1
  19. package/dist/locales/en-US.d.ts +62 -3
  20. package/dist/locales/en-US.js +65 -6
  21. package/dist/locales/en-US.js.map +1 -1
  22. package/dist/locales/kernelMenuTitles.js +1 -0
  23. package/dist/locales/kernelMenuTitles.js.map +1 -1
  24. package/dist/locales/zh-CN.d.ts +62 -3
  25. package/dist/locales/zh-CN.js +65 -6
  26. package/dist/locales/zh-CN.js.map +1 -1
  27. package/dist/router/viewRegistry.js +6 -6
  28. package/dist/router/viewRegistry.js.map +1 -1
  29. package/dist/style.css +1 -1
  30. package/dist/theme/naive-theme.js +80 -77
  31. package/dist/theme/naive-theme.js.map +1 -1
  32. package/dist/types/api.d.ts +91 -0
  33. package/dist/types/api.js +17 -15
  34. package/dist/types/api.js.map +1 -1
  35. package/dist/utils/shake.d.ts +1 -0
  36. package/dist/utils/shake.js +30 -0
  37. package/dist/utils/shake.js.map +1 -0
  38. package/dist/views/login/LoginForm.vue.js +2 -2
  39. package/dist/views/login/LoginForm2.vue.js +135 -135
  40. package/dist/views/login/LoginForm2.vue.js.map +1 -1
  41. package/dist/views/login/components/LoginDesk.vue.js +1 -1
  42. package/dist/views/login/components/LoginDesk2.vue.js +59 -47
  43. package/dist/views/login/components/LoginDesk2.vue.js.map +1 -1
  44. package/dist/views/personal/notice2.vue.js +1 -1
  45. package/dist/views/personal/notice2.vue.js.map +1 -1
  46. package/dist/views/personal/sessions.vue.js +2 -2
  47. package/dist/views/personal/sessions2.vue.js +41 -40
  48. package/dist/views/personal/sessions2.vue.js.map +1 -1
  49. package/dist/views/system/ai-usage/index.vue.js +3 -3
  50. package/dist/views/system/ai-usage/index2.vue.js +13 -12
  51. package/dist/views/system/ai-usage/index2.vue.js.map +1 -1
  52. package/dist/views/system/config/components/AdvancedSection.vue.js +3 -3
  53. package/dist/views/system/config/components/AdvancedSection2.vue.js +2 -1
  54. package/dist/views/system/config/components/AdvancedSection2.vue.js.map +1 -1
  55. package/dist/views/system/dict/index.vue.js +2 -2
  56. package/dist/views/system/dict/index2.vue.js +12 -1
  57. package/dist/views/system/dict/index2.vue.js.map +1 -1
  58. package/dist/views/system/file/index2.vue.js +1 -0
  59. package/dist/views/system/file/index2.vue.js.map +1 -1
  60. package/dist/views/system/job/index.vue.js +3 -3
  61. package/dist/views/system/job/index2.vue.js +182 -181
  62. package/dist/views/system/job/index2.vue.js.map +1 -1
  63. package/dist/views/system/job-log/components/AttemptTable2.vue.js +8 -3
  64. package/dist/views/system/job-log/components/AttemptTable2.vue.js.map +1 -1
  65. package/dist/views/system/job-log/index.vue.js +1 -1
  66. package/dist/views/system/job-log/index2.vue.js +5 -5
  67. package/dist/views/system/job-log/index2.vue.js.map +1 -1
  68. package/dist/views/system/log/exception/index.vue.js +2 -2
  69. package/dist/views/system/log/exception/index2.vue.js +8 -5
  70. package/dist/views/system/log/exception/index2.vue.js.map +1 -1
  71. package/dist/views/system/log/login/index2.vue.js +21 -12
  72. package/dist/views/system/log/login/index2.vue.js.map +1 -1
  73. package/dist/views/system/log/op/index.vue.js +2 -2
  74. package/dist/views/system/log/op/index2.vue.js +50 -40
  75. package/dist/views/system/log/op/index2.vue.js.map +1 -1
  76. package/dist/views/system/menu/components/ButtonManager.vue.js +2 -2
  77. package/dist/views/system/menu/components/ButtonManager2.vue.js +45 -36
  78. package/dist/views/system/menu/components/ButtonManager2.vue.js.map +1 -1
  79. package/dist/views/system/menu/index.vue.js +2 -2
  80. package/dist/views/system/menu/index2.vue.js +11 -11
  81. package/dist/views/system/menu/index2.vue.js.map +1 -1
  82. package/dist/views/system/module/index.vue.js +1 -1
  83. package/dist/views/system/module/index2.vue.js +171 -117
  84. package/dist/views/system/module/index2.vue.js.map +1 -1
  85. package/dist/views/system/notice/index.vue.js +3 -3
  86. package/dist/views/system/notice/index2.vue.js +1 -0
  87. package/dist/views/system/notice/index2.vue.js.map +1 -1
  88. package/dist/views/system/org/index.vue.js +2 -2
  89. package/dist/views/system/org/index2.vue.js +70 -67
  90. package/dist/views/system/org/index2.vue.js.map +1 -1
  91. package/dist/views/system/position/index.vue.js +2 -2
  92. package/dist/views/system/position/index2.vue.js +57 -48
  93. package/dist/views/system/position/index2.vue.js.map +1 -1
  94. package/dist/views/system/recycle/index.vue.js +1 -1
  95. package/dist/views/system/recycle/index2.vue.js +3 -1
  96. package/dist/views/system/recycle/index2.vue.js.map +1 -1
  97. package/dist/views/system/role/components/GrantMenuSheet.vue.d.ts +2 -0
  98. package/dist/views/system/role/components/GrantMenuSheet.vue.js +2 -2
  99. package/dist/views/system/role/components/GrantMenuSheet2.vue.js +54 -49
  100. package/dist/views/system/role/components/GrantMenuSheet2.vue.js.map +1 -1
  101. package/dist/views/system/role/components/GrantMenuTable.vue.js +1 -1
  102. package/dist/views/system/role/components/GrantMenuTable2.vue.js +159 -195
  103. package/dist/views/system/role/components/GrantMenuTable2.vue.js.map +1 -1
  104. package/dist/views/system/role/components/grantMenuGroups.d.ts +54 -0
  105. package/dist/views/system/role/components/grantMenuGroups.js +116 -76
  106. package/dist/views/system/role/components/grantMenuGroups.js.map +1 -1
  107. package/dist/views/system/role/index.vue.js +2 -2
  108. package/dist/views/system/role/index2.vue.js +152 -145
  109. package/dist/views/system/role/index2.vue.js.map +1 -1
  110. package/dist/views/system/session/index2.vue.js +39 -35
  111. package/dist/views/system/session/index2.vue.js.map +1 -1
  112. package/dist/views/system/user/components/UserGrantEffectiveTable.vue.d.ts +10 -0
  113. package/dist/views/system/user/components/UserGrantEffectiveTable.vue.js +5 -0
  114. package/dist/views/system/user/components/UserGrantEffectiveTable.vue.js.map +1 -0
  115. package/dist/views/system/user/components/UserGrantEffectiveTable2.vue.js +96 -0
  116. package/dist/views/system/user/components/UserGrantEffectiveTable2.vue.js.map +1 -0
  117. package/dist/views/system/user/components/UserGrantMenuSheet.vue.d.ts +13 -0
  118. package/dist/views/system/user/components/UserGrantMenuSheet.vue.js +8 -0
  119. package/dist/views/system/user/components/UserGrantMenuSheet.vue.js.map +1 -0
  120. package/dist/views/system/user/components/UserGrantMenuSheet2.vue.js +216 -0
  121. package/dist/views/system/user/components/UserGrantMenuSheet2.vue.js.map +1 -0
  122. package/dist/views/system/user/components/UserGrantMenuTable.vue.d.ts +13 -0
  123. package/dist/views/system/user/components/UserGrantMenuTable.vue.js +8 -0
  124. package/dist/views/system/user/components/UserGrantMenuTable.vue.js.map +1 -0
  125. package/dist/views/system/user/components/UserGrantMenuTable2.vue.js +186 -0
  126. package/dist/views/system/user/components/UserGrantMenuTable2.vue.js.map +1 -0
  127. package/dist/views/system/user/components/UserGrantNodeRow.vue.d.ts +31 -0
  128. package/dist/views/system/user/components/UserGrantNodeRow.vue.js +8 -0
  129. package/dist/views/system/user/components/UserGrantNodeRow.vue.js.map +1 -0
  130. package/dist/views/system/user/components/UserGrantNodeRow2.vue.js +171 -0
  131. package/dist/views/system/user/components/UserGrantNodeRow2.vue.js.map +1 -0
  132. package/dist/views/system/user/components/UserGrantOverviewDrawer.vue.d.ts +21 -0
  133. package/dist/views/system/user/components/UserGrantOverviewDrawer.vue.js +5 -0
  134. package/dist/views/system/user/components/UserGrantOverviewDrawer.vue.js.map +1 -0
  135. package/dist/views/system/user/components/UserGrantOverviewDrawer2.vue.js +178 -0
  136. package/dist/views/system/user/components/UserGrantOverviewDrawer2.vue.js.map +1 -0
  137. package/dist/views/system/user/components/userGrantState.d.ts +64 -0
  138. package/dist/views/system/user/components/userGrantState.js +117 -0
  139. package/dist/views/system/user/components/userGrantState.js.map +1 -0
  140. package/dist/views/system/user/index.vue.js +2 -2
  141. package/dist/views/system/user/index2.vue.js +250 -207
  142. package/dist/views/system/user/index2.vue.js.map +1 -1
  143. package/package.json +3 -3
@@ -1 +1 @@
1
- {"version":3,"file":"index2.vue.js","sources":["../../../../src/views/system/role/index.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// 角色管理 = SmartTable CRUD(照职位范式)+ 专属面板两个:授权菜单弹窗(GrantMenuSheet,勾选菜单树)、数据范围抽屉(选范围类型 + 自定义机构)。\n// 删角色会**物理**删掉用户↔角色关联(不可恢复)——所以删前先查一次持有人数当面告知,单删与批量删都盖到,\n// 只给行内按钮加警告的话,勾选 + 批量删就绕过去了。\nimport { computed, h, onMounted, reactive, ref, shallowRef } from 'vue'\nimport {\n NButton,\n NSpace,\n NInput,\n NInputNumber,\n NSwitch,\n NForm,\n NFormItem,\n NSelect,\n NDropdown,\n useMessage,\n type FormInst,\n type FormRules,\n} from 'naive-ui'\nimport { useI18n } from 'vue-i18n'\nimport { SmartTable, type SmartTableColumn, type SmartTableInst } from 'smart-naive-table'\nimport AppIcon from '#/components/AppIcon.vue'\nimport FormContainer from '#/components/FormContainer/index.vue'\nimport StatusSwitch from '#/components/StatusSwitch/index.vue'\nimport OrgTreeSelect from '#/components/OrgTreeSelect/index.vue'\nimport UserPicker from '#/components/UserPicker/index.vue'\nimport GrantMenuSheet from './components/GrantMenuSheet.vue'\nimport { useConfirm } from '#/composables/useConfirm'\nimport { useBatchDelete } from '#/composables/useBatchDelete'\nimport { roleApi, menuApi, moduleApi, userApi } from '#/api'\nimport { useAuthStore } from '#/stores/auth'\nimport { translateError } from '#/utils/error'\nimport { SEARCH_ACTIONS, deriveHeaderFilters } from '#/utils/tableFilter'\nimport { TABLE_MIN_ROW_HEIGHT, TABLE_TOOLBAR } from '#/utils/tableToolbar'\nimport TableTotal from '#/components/TableTotal/index.vue'\nimport { DataScopeType, type ModuleRow, type RoleInput, type SysRole } from '#/types/api'\nimport type { MenuTreeNode } from '#/types/menu'\n\nconst { t } = useI18n()\nconst message = useMessage()\nconst { confirm } = useConfirm()\nconst auth = useAuthStore()\nconst tableRef = ref<SmartTableInst<SysRole>>()\n\n/** 「未分配」哨兵:雪花 id 无 0,用它表示 moduleId==null 的顶级目录分组。 */\nconst UNASSIGNED = 0\n/** 授权弹窗的「所属应用」下拉数据源。 */\nconst modules = shallowRef<ModuleRow[]>([])\nonMounted(async () => {\n try {\n modules.value = await moduleApi.list()\n } catch {\n // 模块列表仅供授权弹窗的「所属应用」下拉;拉取失败不阻塞角色管理主流程。\n }\n})\n\n/**\n * 持有该角色的用户数。复用用户分页端点(Size=1 只要 total),不新开接口。\n * 查不到(如只有角色 CRUD、没有用户查询权限的管理员会 403)返回 null → 退回通用文案,不阻断删除:\n * 用户数只用来让删除者知情,不改变谁能删什么。\n */\nasync function countUsers(roleId: number): Promise<number | null> {\n try {\n const { total } = await userApi.page({ page: 1, pageSize: 1, roleId })\n return total\n } catch {\n return null\n }\n}\n\nconst { checkedKeys, run: batchDelete } = useBatchDelete({\n remove: roleApi.batchRemove,\n refresh: () => tableRef.value?.refresh(),\n successMsg: t('role.deleted'),\n content: async ids => {\n const counts = await Promise.all(ids.map(countUsers))\n if (counts.some(n => n === null)) return t('common.batchDeleteConfirm', { count: ids.length })\n const users = counts.reduce<number>((sum, n) => sum + n!, 0)\n return users === 0\n ? t('common.batchDeleteConfirm', { count: ids.length })\n : t('role.batchDeleteWithUsers', { count: ids.length, users })\n },\n})\n\nasync function askDelete(r: SysRole) {\n const n = await countUsers(r.id)\n const content =\n n === null\n ? t('role.deleteConfirm', { name: r.name })\n : n === 0\n ? t('role.deleteConfirmNoUsers', { name: r.name })\n : t('role.deleteConfirmWithUsers', { name: r.name, count: n })\n const ok = await confirm({\n content,\n type: 'error',\n action: () => roleApi.remove(r.id),\n successMsg: t('role.deleted'),\n })\n if (ok) tableRef.value?.refresh()\n}\n\nconst toInput = (r: SysRole): RoleInput => ({\n name: r.name,\n code: r.code,\n sort: r.sort,\n enabled: r.enabled,\n remark: r.remark ?? '',\n isDelegatable: r.isDelegatable ?? false,\n})\n\nconst columns: SmartTableColumn<SysRole>[] = [\n { type: 'selection' },\n\n { type: 'index', title: () => t('common.rowNo'), width: 64, align: 'center' },\n {\n key: 'code',\n title: () => t('role.code'),\n render: r => h('span', { class: 'mono muted' }, r.code),\n },\n {\n key: 'name',\n title: () => t('role.name'),\n card: 'title', // 窄档卡片以角色名称为标题,编码作为字段\n search: { actions: SEARCH_ACTIONS.fuzzy },\n },\n {\n key: 'sort',\n title: () => t('role.sort'),\n width: 80,\n render: r => h('span', { class: 'num muted' }, r.sort),\n },\n {\n key: 'enabled',\n title: () => t('common.status'),\n width: 90,\n render: r =>\n h(StatusSwitch, {\n value: r.enabled,\n disabled: !auth.isSuperAdmin || !auth.hasPerm('PUT:/api/v1/sys/role/{id}'),\n request: (next: boolean) => roleApi.update(r.id, { ...toInput(r), enabled: next }),\n 'onUpdate:value': (v: boolean) => {\n r.enabled = v\n },\n }),\n },\n {\n key: 'remark',\n title: () => t('role.remark'),\n ellipsis: { tooltip: true },\n render: r => r.remark || h('span', { class: 'faint' }, '—'),\n },\n {\n key: 'op',\n title: () => t('common.operation'),\n width: 240,\n fixed: 'right',\n hideInSetting: true,\n render: r => {\n // 角色定义(编辑/删除)与角色授权面(授权菜单/数据范围)为超管专属;\n // 仅\"授权用户\"(角色指派面)对普通管理员开放(经 RoleGrantPolicy 收口校验)。\n const dropdownOptions = [\n auth.isSuperAdmin && auth.hasPerm('PUT:/api/v1/sys/role/menu')\n ? { label: t('role.grantMenus'), key: 'menus' }\n : null,\n auth.isSuperAdmin && auth.hasPerm('PUT:/api/v1/sys/role/datascope')\n ? { label: t('role.dataScope'), key: 'scope' }\n : null,\n auth.hasPerm('PUT:/api/v1/sys/role/users')\n ? { label: t('role.grantUsers'), key: 'users' }\n : null,\n ].filter((o): o is { label: string; key: string } => o !== null)\n return h(NSpace, { size: 4, wrapItem: false }, () => [\n auth.isSuperAdmin && auth.hasPerm('PUT:/api/v1/sys/role/{id}')\n ? h(\n NButton,\n { size: 'small', quaternary: true, type: 'primary', onClick: () => openEdit(r) },\n () => t('common.edit'),\n )\n : null,\n auth.isSuperAdmin && auth.hasPerm('DELETE:/api/v1/sys/role/{id}')\n ? h(\n NButton,\n { size: 'small', quaternary: true, type: 'error', onClick: () => askDelete(r) },\n () => t('common.delete'),\n )\n : null,\n dropdownOptions.length\n ? h(\n NDropdown,\n {\n options: dropdownOptions,\n onSelect: (key: string) => {\n if (key === 'menus') openMenus(r)\n else if (key === 'scope') openScope(r)\n else openUsers(r)\n },\n },\n () => h(NButton, { size: 'small', quaternary: true }, () => t('common.more')),\n )\n : null,\n ])\n },\n },\n]\nderiveHeaderFilters(columns)\n\n// ── 新增/编辑弹窗 ──\nconst show = ref(false)\nconst formRef = ref<FormInst | null>(null)\nconst editingId = ref<number | null>(null)\nconst rules: FormRules = {\n code: {\n required: true,\n whitespace: true,\n message: () => t('role.codeRequired'),\n trigger: ['input', 'blur'],\n },\n name: {\n required: true,\n whitespace: true,\n message: () => t('role.nameRequired'),\n trigger: ['input', 'blur'],\n },\n}\nconst blank = (): RoleInput => ({\n name: '',\n code: '',\n sort: 0,\n enabled: true,\n remark: '',\n isDelegatable: false,\n})\nconst form = reactive<RoleInput>(blank())\n\nfunction openAdd() {\n editingId.value = null\n Object.assign(form, blank())\n show.value = true\n}\nfunction openEdit(r: SysRole) {\n editingId.value = r.id\n Object.assign(form, toInput(r))\n show.value = true\n}\nasync function save() {\n await formRef.value?.validate()\n try {\n if (editingId.value === null) await roleApi.add({ ...form })\n else await roleApi.update(editingId.value, { ...form })\n message.success(t('role.saved'))\n await tableRef.value?.refresh()\n } catch (e) {\n message.error(translateError(e))\n return false\n }\n}\n\n// ── 授权菜单弹窗(目录卡片列表 → 全量替换角色授权)──\nconst showMenus = ref(false)\n// 整份替换 + 只读(勾选态在 GrantMenuTable 自己的 reactive 里,改动经 GrantMenuSheet 带回 saveMenus),不需要深响应\nconst menuTree = shallowRef<MenuTreeNode[]>([])\nconst menuGranted = shallowRef<number[]>([])\nconst menuRole = ref<SysRole | null>(null)\nconst defaultModuleId = ref(UNASSIGNED)\n\nasync function openMenus(r: SysRole) {\n try {\n const [tree, granted] = await Promise.all([menuApi.tree(), roleApi.getMenus(r.id)])\n menuRole.value = r\n menuTree.value = tree\n menuGranted.value = granted\n defaultModuleId.value = auth.currentModuleId ?? modules.value[0]?.id ?? UNASSIGNED\n showMenus.value = true\n } catch (e) {\n message.error(translateError(e))\n }\n}\nasync function saveMenus(ids: number[]) {\n if (menuRole.value === null) return\n try {\n await roleApi.setMenus(menuRole.value.id, ids)\n message.success(t('role.grantSaved'))\n } catch (e) {\n message.error(translateError(e))\n return false\n }\n}\n\n// ── 授权用户(UserPicker) ──\nconst userPickerRef = ref<InstanceType<typeof UserPicker> | null>(null)\nconst userRoleId = ref<number | null>(null)\n\nasync function openUsers(r: SysRole) {\n userRoleId.value = r.id\n try {\n const ids = await roleApi.getUsers(r.id)\n userPickerRef.value?.open(ids)\n } catch (e) {\n message.error(translateError(e))\n }\n}\nasync function onUserConfirm(ids: number[]) {\n if (userRoleId.value === null) return\n try {\n await roleApi.setUsers(userRoleId.value, ids)\n message.success(t('role.grantUsersSaved'))\n } catch (e) {\n message.error(translateError(e))\n }\n}\n\n// ── 数据范围抽屉 ──\nconst showScope = ref(false)\nconst scopeRoleId = ref<number | null>(null)\nconst scopeRole = ref<SysRole | null>(null)\nconst scopeForm = reactive<{ scopeType: DataScopeType; customOrgIds: number[] }>({\n scopeType: DataScopeType.Org,\n customOrgIds: [],\n})\nconst isCustom = computed(() => scopeForm.scopeType === DataScopeType.Custom)\nconst scopeOptions = computed(() => [\n { label: t('role.scope.all'), value: DataScopeType.All },\n { label: t('role.scope.org'), value: DataScopeType.Org },\n { label: t('role.scope.orgAndChildren'), value: DataScopeType.OrgAndChildren },\n { label: t('role.scope.self'), value: DataScopeType.Self },\n { label: t('role.scope.custom'), value: DataScopeType.Custom },\n])\nasync function openScope(r: SysRole) {\n scopeRoleId.value = r.id\n scopeRole.value = r\n try {\n const cfg = await roleApi.getDataScope(r.id)\n scopeForm.scopeType = cfg?.scopeType ?? DataScopeType.Org\n scopeForm.customOrgIds = cfg?.customOrgIds\n ? cfg.customOrgIds.split(',').filter(Boolean).map(Number)\n : []\n showScope.value = true\n } catch (e) {\n message.error(translateError(e))\n }\n}\nasync function saveScope() {\n if (scopeRoleId.value === null) return\n try {\n await roleApi.setDataScope(\n scopeRoleId.value,\n scopeForm.scopeType,\n isCustom.value ? scopeForm.customOrgIds : undefined,\n )\n message.success(t('role.scopeSaved'))\n } catch (e) {\n message.error(translateError(e))\n return false\n }\n}\n</script>\n\n<template>\n <SmartTable\n :toolbar=\"TABLE_TOOLBAR\"\n ref=\"tableRef\"\n :columns=\"columns\"\n :fetcher=\"roleApi.page\"\n :search=\"{ container: 'table' }\"\n fill-height\n :min-row-height=\"TABLE_MIN_ROW_HEIGHT\"\n card-on-narrow\n storage-key=\"sys-role\"\n :checked-row-keys=\"checkedKeys\"\n @update:checked-row-keys=\"(keys: (string | number)[]) => (checkedKeys = keys)\"\n @error=\"e => message.error(translateError(e))\"\n >\n <template #pagination-prefix=\"{ itemCount }\">\n <TableTotal :count=\"itemCount\" />\n </template>\n <template #toolbar-right>\n <n-button\n v-if=\"auth.isSuperAdmin\"\n v-auth=\"'POST:/api/v1/sys/role/add'\"\n type=\"primary\"\n @click=\"openAdd\"\n >\n <template #icon><AppIcon icon=\"ph:plus\" :size=\"16\" /></template>\n {{ t('common.add') }}\n </n-button>\n </template>\n <!-- 勾选后工具栏换成批量栏(本页全选 + 已选 N 项 + 这里的按钮 + 取消选择),按钮出现即代表有勾选 -->\n <template #batch>\n <n-button\n v-if=\"auth.isSuperAdmin\"\n v-auth=\"'POST:/api/v1/sys/role/batch-delete'\"\n secondary\n type=\"error\"\n @click=\"batchDelete\"\n >\n <template #icon><AppIcon icon=\"ph:trash\" :size=\"16\" /></template>\n {{ t('common.batchDelete') }}\n </n-button>\n </template>\n </SmartTable>\n\n <!-- 新增/编辑 -->\n <FormContainer\n v-model:show=\"show\"\n :title=\"editingId === null ? t('role.addTitle') : t('role.editTitle')\"\n :width=\"480\"\n :on-confirm=\"save\"\n :confirm-text=\"t('common.save')\"\n >\n <n-form ref=\"formRef\" :model=\"form\" :rules=\"rules\" label-placement=\"left\" :label-width=\"80\">\n <n-form-item :label=\"t('role.code')\" path=\"code\">\n <n-input\n v-model:value=\"form.code\"\n :placeholder=\"t('role.code')\"\n :disabled=\"editingId !== null\"\n />\n </n-form-item>\n <n-form-item :label=\"t('role.name')\" path=\"name\">\n <n-input v-model:value=\"form.name\" :placeholder=\"t('role.name')\" />\n </n-form-item>\n <n-form-item :label=\"t('role.sort')\">\n <n-input-number v-model:value=\"form.sort\" :min=\"0\" style=\"width: 160px\" />\n </n-form-item>\n <n-form-item :label=\"t('role.remark')\">\n <n-input\n v-model:value=\"form.remark as string\"\n type=\"textarea\"\n :rows=\"2\"\n :placeholder=\"t('role.remark')\"\n />\n </n-form-item>\n <n-form-item :label=\"t('common.status')\">\n <n-switch v-model:value=\"form.enabled\" />\n </n-form-item>\n <n-form-item v-if=\"auth.isSuperAdmin\" :label=\"t('role.isDelegatable')\">\n <n-switch v-model:value=\"form.isDelegatable as boolean\" />\n <template #feedback>\n <span class=\"form-hint\">{{ t('role.isDelegatableHint') }}</span>\n </template>\n </n-form-item>\n </n-form>\n </FormContainer>\n\n <!-- 授权菜单 -->\n <GrantMenuSheet\n v-model:show=\"showMenus\"\n :tree=\"menuTree\"\n :granted=\"menuGranted\"\n :modules=\"modules\"\n :default-module-id=\"defaultModuleId\"\n :on-save=\"saveMenus\"\n />\n\n <!-- 授权用户 -->\n <UserPicker ref=\"userPickerRef\" @confirm=\"onUserConfirm\" />\n\n <!-- 数据范围 -->\n <FormContainer\n v-model:show=\"showScope\"\n :title=\"t('role.dataScope')\"\n :width=\"480\"\n :on-confirm=\"saveScope\"\n :confirm-text=\"t('common.save')\"\n >\n <div v-if=\"scopeRole\" class=\"scope-who\">{{ scopeRole.name }} · {{ scopeRole.code }}</div>\n <n-form :model=\"scopeForm\" label-placement=\"left\" :label-width=\"90\">\n <n-form-item :label=\"t('role.scopeType')\">\n <n-select v-model:value=\"scopeForm.scopeType\" :options=\"scopeOptions\" />\n </n-form-item>\n <n-form-item v-if=\"isCustom\" :label=\"t('role.customOrgs')\">\n <OrgTreeSelect\n v-model:value=\"scopeForm.customOrgIds\"\n multiple\n :placeholder=\"t('role.customOrgsHint')\"\n />\n </n-form-item>\n </n-form>\n </FormContainer>\n</template>\n\n<style scoped>\n/* 开关下方的说明文字 */\n.form-hint {\n font-size: 13px;\n color: var(--text-3);\n}\n\n/* 数据范围表单顶部:当前角色「名称 · 编码」 */\n.scope-who {\n margin: -4px 0 14px;\n font-size: 13px;\n color: var(--text-3);\n}\n</style>\n"],"names":["UNASSIGNED","useI18n","message","useMessage","confirm","useConfirm","auth","useAuthStore","tableRef","ref","modules","shallowRef","onMounted","moduleApi","countUsers","roleId","total","userApi","checkedKeys","batchDelete","useBatchDelete","roleApi","_a","ids","counts","n","users","sum","askDelete","r","content","toInput","columns","h","SEARCH_ACTIONS","StatusSwitch","next","v","dropdownOptions","o","NSpace","NButton","openEdit","NDropdown","key","openMenus","openScope","deriveHeaderFilters","show","formRef","editingId","rules","blank","form","reactive","openAdd","save","_b","e","translateError","showMenus","menuTree","menuGranted","menuRole","defaultModuleId","tree","granted","menuApi","saveMenus","userPickerRef","userRoleId","openUsers","onUserConfirm","showScope","scopeRoleId","scopeRole","scopeForm","DataScopeType","isCustom","computed","scopeOptions","cfg","saveScope","_createVNode","_unref","SmartTable","TABLE_TOOLBAR","TABLE_MIN_ROW_HEIGHT","_cache","keys","_withCtx","itemCount","TableTotal","_createBlock","AppIcon","_createTextVNode","FormContainer","$event","NForm","NFormItem","NInput","NInputNumber","NSwitch","_createElementVNode","_hoisted_1","_toDisplayString","GrantMenuSheet","UserPicker","_createElementBlock","_hoisted_2","NSelect","OrgTreeSelect"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;GA6CMA,KAAa;;;AAPnB,UAAM,EAAE,EAAA,IAAMC,GAAA,GACRC,IAAUC,GAAA,GACV,EAAE,SAAAC,GAAA,IAAYC,GAAA,GACdC,IAAOC,GAAA,GACPC,IAAWC,EAAA,GAKXC,IAAUC,EAAwB,EAAE;AAC1C,IAAAC,GAAU,YAAY;AACpB,UAAI;AACF,QAAAF,EAAQ,QAAQ,MAAMG,GAAU,KAAA;AAAA,MAClC,QAAQ;AAAA,MAER;AAAA,IACF,CAAC;AAOD,mBAAeC,EAAWC,GAAwC;AAChE,UAAI;AACF,cAAM,EAAE,OAAAC,EAAA,IAAU,MAAMC,GAAQ,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,QAAAF,EAAA,CAAQ;AACrE,eAAOC;AAAA,MACT,QAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF;AAEA,UAAM,EAAE,aAAAE,GAAa,KAAKC,GAAA,IAAgBC,GAAe;AAAA,MACvD,QAAQC,EAAQ;AAAA,MAChB,SAAS,MAAA;;AAAM,gBAAAC,IAAAd,EAAS,UAAT,gBAAAc,EAAgB;AAAA;AAAA,MAC/B,YAAY,EAAE,cAAc;AAAA,MAC5B,SAAS,OAAMC,MAAO;AACpB,cAAMC,IAAS,MAAM,QAAQ,IAAID,EAAI,IAAIT,CAAU,CAAC;AACpD,YAAIU,EAAO,KAAK,CAAAC,MAAKA,MAAM,IAAI,EAAG,QAAO,EAAE,6BAA6B,EAAE,OAAOF,EAAI,QAAQ;AAC7F,cAAMG,IAAQF,EAAO,OAAe,CAACG,GAAKF,MAAME,IAAMF,GAAI,CAAC;AAC3D,eAAOC,MAAU,IACb,EAAE,6BAA6B,EAAE,OAAOH,EAAI,OAAA,CAAQ,IACpD,EAAE,6BAA6B,EAAE,OAAOA,EAAI,QAAQ,OAAAG,GAAO;AAAA,MACjE;AAAA,IAAA,CACD;AAED,mBAAeE,GAAUC,GAAY;;AACnC,YAAMJ,IAAI,MAAMX,EAAWe,EAAE,EAAE,GACzBC,IACJL,MAAM,OACF,EAAE,sBAAsB,EAAE,MAAMI,EAAE,KAAA,CAAM,IACxCJ,MAAM,IACJ,EAAE,6BAA6B,EAAE,MAAMI,EAAE,KAAA,CAAM,IAC/C,EAAE,+BAA+B,EAAE,MAAMA,EAAE,MAAM,OAAOJ,GAAG;AAOnE,MANW,MAAMrB,GAAQ;AAAA,QACvB,SAAA0B;AAAA,QACA,MAAM;AAAA,QACN,QAAQ,MAAMT,EAAQ,OAAOQ,EAAE,EAAE;AAAA,QACjC,YAAY,EAAE,cAAc;AAAA,MAAA,CAC7B,OACOP,IAAAd,EAAS,UAAT,QAAAc,EAAgB;AAAA,IAC1B;AAEA,UAAMS,IAAU,CAACF,OAA2B;AAAA,MAC1C,MAAMA,EAAE;AAAA,MACR,MAAMA,EAAE;AAAA,MACR,MAAMA,EAAE;AAAA,MACR,SAASA,EAAE;AAAA,MACX,QAAQA,EAAE,UAAU;AAAA,MACpB,eAAeA,EAAE,iBAAiB;AAAA,IAAA,IAG9BG,IAAuC;AAAA,MAC3C,EAAE,MAAM,YAAA;AAAA,MAER,EAAE,MAAM,SAAS,OAAO,MAAM,EAAE,cAAc,GAAG,OAAO,IAAI,OAAO,SAAA;AAAA,MACnE;AAAA,QACE,KAAK;AAAA,QACL,OAAO,MAAM,EAAE,WAAW;AAAA,QAC1B,QAAQ,OAAKC,EAAE,QAAQ,EAAE,OAAO,gBAAgBJ,EAAE,IAAI;AAAA,MAAA;AAAA,MAExD;AAAA,QACE,KAAK;AAAA,QACL,OAAO,MAAM,EAAE,WAAW;AAAA,QAC1B,MAAM;AAAA;AAAA,QACN,QAAQ,EAAE,SAASK,GAAe,MAAA;AAAA,MAAM;AAAA,MAE1C;AAAA,QACE,KAAK;AAAA,QACL,OAAO,MAAM,EAAE,WAAW;AAAA,QAC1B,OAAO;AAAA,QACP,QAAQ,OAAKD,EAAE,QAAQ,EAAE,OAAO,eAAeJ,EAAE,IAAI;AAAA,MAAA;AAAA,MAEvD;AAAA,QACE,KAAK;AAAA,QACL,OAAO,MAAM,EAAE,eAAe;AAAA,QAC9B,OAAO;AAAA,QACP,QAAQ,CAAAA,MACNI,EAAEE,IAAc;AAAA,UACd,OAAON,EAAE;AAAA,UACT,UAAU,CAACvB,EAAK,gBAAgB,CAACA,EAAK,QAAQ,2BAA2B;AAAA,UACzE,SAAS,CAAC8B,MAAkBf,EAAQ,OAAOQ,EAAE,IAAI,EAAE,GAAGE,EAAQF,CAAC,GAAG,SAASO,GAAM;AAAA,UACjF,kBAAkB,CAACC,MAAe;AAChC,YAAAR,EAAE,UAAUQ;AAAA,UACd;AAAA,QAAA,CACD;AAAA,MAAA;AAAA,MAEL;AAAA,QACE,KAAK;AAAA,QACL,OAAO,MAAM,EAAE,aAAa;AAAA,QAC5B,UAAU,EAAE,SAAS,GAAA;AAAA,QACrB,QAAQ,CAAAR,MAAKA,EAAE,UAAUI,EAAE,QAAQ,EAAE,OAAO,QAAA,GAAW,GAAG;AAAA,MAAA;AAAA,MAE5D;AAAA,QACE,KAAK;AAAA,QACL,OAAO,MAAM,EAAE,kBAAkB;AAAA,QACjC,OAAO;AAAA,QACP,OAAO;AAAA,QACP,eAAe;AAAA,QACf,QAAQ,CAAAJ,MAAK;AAGX,gBAAMS,IAAkB;AAAA,YACtBhC,EAAK,gBAAgBA,EAAK,QAAQ,2BAA2B,IACzD,EAAE,OAAO,EAAE,iBAAiB,GAAG,KAAK,YACpC;AAAA,YACJA,EAAK,gBAAgBA,EAAK,QAAQ,gCAAgC,IAC9D,EAAE,OAAO,EAAE,gBAAgB,GAAG,KAAK,YACnC;AAAA,YACJA,EAAK,QAAQ,4BAA4B,IACrC,EAAE,OAAO,EAAE,iBAAiB,GAAG,KAAK,YACpC;AAAA,UAAA,EACJ,OAAO,CAACiC,MAA2CA,MAAM,IAAI;AAC/D,iBAAON,EAAEO,IAAQ,EAAE,MAAM,GAAG,UAAU,GAAA,GAAS,MAAM;AAAA,YACnDlC,EAAK,gBAAgBA,EAAK,QAAQ,2BAA2B,IACzD2B;AAAA,cACEQ;AAAA,cACA,EAAE,MAAM,SAAS,YAAY,IAAM,MAAM,WAAW,SAAS,MAAMC,GAASb,CAAC,EAAA;AAAA,cAC7E,MAAM,EAAE,aAAa;AAAA,YAAA,IAEvB;AAAA,YACJvB,EAAK,gBAAgBA,EAAK,QAAQ,8BAA8B,IAC5D2B;AAAA,cACEQ;AAAA,cACA,EAAE,MAAM,SAAS,YAAY,IAAM,MAAM,SAAS,SAAS,MAAMb,GAAUC,CAAC,EAAA;AAAA,cAC5E,MAAM,EAAE,eAAe;AAAA,YAAA,IAEzB;AAAA,YACJS,EAAgB,SACZL;AAAA,cACEU;AAAA,cACA;AAAA,gBACE,SAASL;AAAA,gBACT,UAAU,CAACM,MAAgB;AACzB,kBAAIA,MAAQ,UAASC,GAAUhB,CAAC,IACvBe,MAAQ,UAASE,GAAUjB,CAAC,OACtBA,CAAC;AAAA,gBAClB;AAAA,cAAA;AAAA,cAEF,MAAMI,EAAEQ,GAAS,EAAE,MAAM,SAAS,YAAY,GAAA,GAAQ,MAAM,EAAE,aAAa,CAAC;AAAA,YAAA,IAE9E;AAAA,UAAA,CACL;AAAA,QACH;AAAA,MAAA;AAAA,IACF;AAEF,IAAAM,GAAoBf,CAAO;AAG3B,UAAMgB,IAAOvC,EAAI,EAAK,GAChBwC,IAAUxC,EAAqB,IAAI,GACnCyC,IAAYzC,EAAmB,IAAI,GACnC0C,KAAmB;AAAA,MACvB,MAAM;AAAA,QACJ,UAAU;AAAA,QACV,YAAY;AAAA,QACZ,SAAS,MAAM,EAAE,mBAAmB;AAAA,QACpC,SAAS,CAAC,SAAS,MAAM;AAAA,MAAA;AAAA,MAE3B,MAAM;AAAA,QACJ,UAAU;AAAA,QACV,YAAY;AAAA,QACZ,SAAS,MAAM,EAAE,mBAAmB;AAAA,QACpC,SAAS,CAAC,SAAS,MAAM;AAAA,MAAA;AAAA,IAC3B,GAEIC,IAAQ,OAAkB;AAAA,MAC9B,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,eAAe;AAAA,IAAA,IAEXC,IAAOC,EAAoBF,GAAO;AAExC,aAASG,KAAU;AACjB,MAAAL,EAAU,QAAQ,MAClB,OAAO,OAAOG,GAAMD,GAAO,GAC3BJ,EAAK,QAAQ;AAAA,IACf;AACA,aAASN,GAASb,GAAY;AAC5B,MAAAqB,EAAU,QAAQrB,EAAE,IACpB,OAAO,OAAOwB,GAAMtB,EAAQF,CAAC,CAAC,GAC9BmB,EAAK,QAAQ;AAAA,IACf;AACA,mBAAeQ,KAAO;;AACpB,cAAMlC,IAAA2B,EAAQ,UAAR,gBAAA3B,EAAe;AACrB,UAAI;AACF,QAAI4B,EAAU,UAAU,OAAM,MAAM7B,EAAQ,IAAI,EAAE,GAAGgC,GAAM,IACtD,MAAMhC,EAAQ,OAAO6B,EAAU,OAAO,EAAE,GAAGG,GAAM,GACtDnD,EAAQ,QAAQ,EAAE,YAAY,CAAC,GAC/B,QAAMuD,IAAAjD,EAAS,UAAT,gBAAAiD,EAAgB;AAAA,MACxB,SAASC,GAAG;AACV,eAAAxD,EAAQ,MAAMyD,EAAeD,CAAC,CAAC,GACxB;AAAA,MACT;AAAA,IACF;AAGA,UAAME,IAAYnD,EAAI,EAAK,GAErBoD,IAAWlD,EAA2B,EAAE,GACxCmD,IAAcnD,EAAqB,EAAE,GACrCoD,IAAWtD,EAAoB,IAAI,GACnCuD,IAAkBvD,EAAIT,EAAU;AAEtC,mBAAe6C,GAAUhB,GAAY;;AACnC,UAAI;AACF,cAAM,CAACoC,GAAMC,CAAO,IAAI,MAAM,QAAQ,IAAI,CAACC,GAAQ,KAAA,GAAQ9C,EAAQ,SAASQ,EAAE,EAAE,CAAC,CAAC;AAClF,QAAAkC,EAAS,QAAQlC,GACjBgC,EAAS,QAAQI,GACjBH,EAAY,QAAQI,GACpBF,EAAgB,QAAQ1D,EAAK,qBAAmBgB,IAAAZ,EAAQ,MAAM,CAAC,MAAf,gBAAAY,EAAkB,OAAMtB,IACxE4D,EAAU,QAAQ;AAAA,MACpB,SAASF,GAAG;AACV,QAAAxD,EAAQ,MAAMyD,EAAeD,CAAC,CAAC;AAAA,MACjC;AAAA,IACF;AACA,mBAAeU,GAAU7C,GAAe;AACtC,UAAIwC,EAAS,UAAU;AACvB,YAAI;AACF,gBAAM1C,EAAQ,SAAS0C,EAAS,MAAM,IAAIxC,CAAG,GAC7CrB,EAAQ,QAAQ,EAAE,iBAAiB,CAAC;AAAA,QACtC,SAAS,GAAG;AACV,iBAAAA,EAAQ,MAAMyD,EAAe,CAAC,CAAC,GACxB;AAAA,QACT;AAAA,IACF;AAGA,UAAMU,IAAgB5D,EAA4C,IAAI,GAChE6D,IAAa7D,EAAmB,IAAI;AAE1C,mBAAe8D,GAAU1C,GAAY;;AACnC,MAAAyC,EAAW,QAAQzC,EAAE;AACrB,UAAI;AACF,cAAMN,IAAM,MAAMF,EAAQ,SAASQ,EAAE,EAAE;AACvC,SAAAP,IAAA+C,EAAc,UAAd,QAAA/C,EAAqB,KAAKC;AAAA,MAC5B,SAASmC,GAAG;AACV,QAAAxD,EAAQ,MAAMyD,EAAeD,CAAC,CAAC;AAAA,MACjC;AAAA,IACF;AACA,mBAAec,GAAcjD,GAAe;AAC1C,UAAI+C,EAAW,UAAU;AACzB,YAAI;AACF,gBAAMjD,EAAQ,SAASiD,EAAW,OAAO/C,CAAG,GAC5CrB,EAAQ,QAAQ,EAAE,sBAAsB,CAAC;AAAA,QAC3C,SAAS,GAAG;AACV,UAAAA,EAAQ,MAAMyD,EAAe,CAAC,CAAC;AAAA,QACjC;AAAA,IACF;AAGA,UAAMc,IAAYhE,EAAI,EAAK,GACrBiE,IAAcjE,EAAmB,IAAI,GACrCkE,IAAYlE,EAAoB,IAAI,GACpCmE,IAAYtB,EAA+D;AAAA,MAC/E,WAAWuB,EAAc;AAAA,MACzB,cAAc,CAAA;AAAA,IAAC,CAChB,GACKC,IAAWC,EAAS,MAAMH,EAAU,cAAcC,EAAc,MAAM,GACtEG,KAAeD,EAAS,MAAM;AAAA,MAClC,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAOF,EAAc,IAAA;AAAA,MACnD,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAOA,EAAc,IAAA;AAAA,MACnD,EAAE,OAAO,EAAE,2BAA2B,GAAG,OAAOA,EAAc,eAAA;AAAA,MAC9D,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAOA,EAAc,KAAA;AAAA,MACpD,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAOA,EAAc,OAAA;AAAA,IAAO,CAC9D;AACD,mBAAe/B,GAAUjB,GAAY;AACnC,MAAA6C,EAAY,QAAQ7C,EAAE,IACtB8C,EAAU,QAAQ9C;AAClB,UAAI;AACF,cAAMoD,IAAM,MAAM5D,EAAQ,aAAaQ,EAAE,EAAE;AAC3C,QAAA+C,EAAU,aAAYK,KAAA,gBAAAA,EAAK,cAAaJ,EAAc,KACtDD,EAAU,eAAeK,KAAA,QAAAA,EAAK,eAC1BA,EAAI,aAAa,MAAM,GAAG,EAAE,OAAO,OAAO,EAAE,IAAI,MAAM,IACtD,CAAA,GACJR,EAAU,QAAQ;AAAA,MACpB,SAAS,GAAG;AACV,QAAAvE,EAAQ,MAAMyD,EAAe,CAAC,CAAC;AAAA,MACjC;AAAA,IACF;AACA,mBAAeuB,KAAY;AACzB,UAAIR,EAAY,UAAU;AAC1B,YAAI;AACF,gBAAMrD,EAAQ;AAAA,YACZqD,EAAY;AAAA,YACZE,EAAU;AAAA,YACVE,EAAS,QAAQF,EAAU,eAAe;AAAA,UAAA,GAE5C1E,EAAQ,QAAQ,EAAE,iBAAiB,CAAC;AAAA,QACtC,SAASwD,GAAG;AACV,iBAAAxD,EAAQ,MAAMyD,EAAeD,CAAC,CAAC,GACxB;AAAA,QACT;AAAA,IACF;;;;QAIEyB,EAyCaC,EAAAC,EAAA,GAAA;AAAA,UAxCV,SAASD,EAAAE,EAAA;AAAA,mBACN;AAAA,UAAJ,KAAI9E;AAAA,UACH,SAAAwB;AAAA,UACA,SAASoD,EAAA/D,CAAA,EAAQ;AAAA,UACjB,QAAQ,EAAA,WAAA,QAAA;AAAA,UACT,eAAA;AAAA,UACC,kBAAgB+D,EAAAG,EAAA;AAAA,UACjB,kBAAA;AAAA,UACA,eAAY;AAAA,UACX,oBAAkBH,EAAAlE,CAAA;AAAA,UAClB,2BAAuBsE,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA,CAAGC,MAA+BvE,EAAA,QAAcuE;AAAA,UACvE,SAAKD,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAE,CAAA9B,MAAK0B,EAAAlF,CAAA,EAAQ,MAAMkF,EAAAzB,CAAA,EAAeD,CAAC,CAAA;AAAA,QAAA;UAEhC,qBAAiBgC,EAC1B,CAAiC,EADH,WAAAC,QAAS;AAAA,YACvCR,EAAiCS,IAAA,EAApB,OAAOD,EAAA,GAAS,MAAA,GAAA,CAAA,OAAA,CAAA;AAAA,UAAA;UAEpB,mBACT,MAQW;AAAA,YAPHP,EAAA9E,CAAA,EAAK,uBADbuF,EAQWT,EAAA3C,CAAA,GAAA;AAAA;cALT,MAAK;AAAA,cACJ,SAAOc;AAAA,YAAA;cAEG,QAAK,MAAqC;AAAA,gBAArC4B,EAAqCW,IAAA;AAAA,kBAA5B,MAAK;AAAA,kBAAW,MAAM;AAAA,gBAAA;;yBAAiB,MAChE;AAAA,gBADgEC,EAAA,QAC7DX,EAAA,CAAA,EAAC,YAAA,CAAA,GAAA,CAAA;AAAA,cAAA;;;kBALI,2BAA2B;AAAA,YAAA;;UAS5B,SACT,MASW;AAAA,YARHA,EAAA9E,CAAA,EAAK,uBADbuF,EASWT,EAAA3C,CAAA,GAAA;AAAA;cANT,WAAA;AAAA,cACA,MAAK;AAAA,cACJ,SAAO2C,EAAAjE,EAAA;AAAA,YAAA;cAEG,QAAK,MAAsC;AAAA,gBAAtCgE,EAAsCW,IAAA;AAAA,kBAA7B,MAAK;AAAA,kBAAY,MAAM;AAAA,gBAAA;;yBAAiB,MACjE;AAAA,gBADiEC,EAAA,QAC9DX,EAAA,CAAA,EAAC,oBAAA,CAAA,GAAA,CAAA;AAAA,cAAA;;;kBANI,oCAAoC;AAAA,YAAA;;;;QAYlDD,EAuCgBa,IAAA;AAAA,UAtCN,MAAMhD,EAAA;AAAA,kDAAAA,EAAI,QAAAiD;AAAA,UACjB,OAAO/C,EAAA,UAAS,OAAYkC,EAAA,CAAA,qBAAqBA,EAAA,CAAA,EAAC,gBAAA;AAAA,UAClD,OAAO;AAAA,UACP,cAAY5B;AAAA,UACZ,gBAAc4B,EAAA,CAAA,EAAC,aAAA;AAAA,QAAA;qBAEhB,MA+BS;AAAA,YA/BTD,EA+BSC,EAAAc,CAAA,GAAA;AAAA,uBA/BG;AAAA,cAAJ,KAAIjD;AAAA,cAAW,OAAOI;AAAA,cAAO,OAAAF;AAAA,cAAc,mBAAgB;AAAA,cAAQ,eAAa;AAAA,YAAA;yBACtF,MAMc;AAAA,gBANdgC,EAMcC,EAAAe,CAAA,GAAA;AAAA,kBANA,OAAOf,EAAA,CAAA,EAAC,WAAA;AAAA,kBAAe,MAAK;AAAA,gBAAA;6BACxC,MAIE;AAAA,oBAJFD,EAIEC,EAAAgB,CAAA,GAAA;AAAA,sBAHQ,OAAO/C,EAAK;AAAA,sBAAL,kBAAAmC,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA,CAAAS,MAAA5C,EAAK,OAAI4C;AAAA,sBACvB,aAAab,EAAA,CAAA,EAAC,WAAA;AAAA,sBACd,UAAUlC,EAAA,UAAS;AAAA,oBAAA;;;;gBAGxBiC,EAEcC,EAAAe,CAAA,GAAA;AAAA,kBAFA,OAAOf,EAAA,CAAA,EAAC,WAAA;AAAA,kBAAe,MAAK;AAAA,gBAAA;6BACxC,MAAmE;AAAA,oBAAnED,EAAmEC,EAAAgB,CAAA,GAAA;AAAA,sBAAlD,OAAO/C,EAAK;AAAA,sBAAL,kBAAAmC,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA,CAAAS,MAAA5C,EAAK,OAAI4C;AAAA,sBAAG,aAAab,EAAA,CAAA,EAAC,WAAA;AAAA,oBAAA;;;;gBAEpDD,EAEcC,EAAAe,CAAA,GAAA;AAAA,kBAFA,OAAOf,EAAA,CAAA,EAAC,WAAA;AAAA,gBAAA;6BACpB,MAA0E;AAAA,oBAA1ED,EAA0EC,EAAAiB,EAAA,GAAA;AAAA,sBAAlD,OAAOhD,EAAK;AAAA,sBAAL,kBAAAmC,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA,CAAAS,MAAA5C,EAAK,OAAI4C;AAAA,sBAAG,KAAK;AAAA,sBAAG,OAAA,EAAA,OAAA,QAAA;AAAA,oBAAA;;;;gBAErDd,EAOcC,EAAAe,CAAA,GAAA;AAAA,kBAPA,OAAOf,EAAA,CAAA,EAAC,aAAA;AAAA,gBAAA;6BACpB,MAKE;AAAA,oBALFD,EAKEC,EAAAgB,CAAA,GAAA;AAAA,sBAJQ,OAAO/C,EAAK;AAAA,sBAAL,kBAAAmC,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA,CAAAS,MAAA5C,EAAK,SAAM4C;AAAA,sBAC1B,MAAK;AAAA,sBACJ,MAAM;AAAA,sBACN,aAAab,EAAA,CAAA,EAAC,aAAA;AAAA,oBAAA;;;;gBAGnBD,EAEcC,EAAAe,CAAA,GAAA;AAAA,kBAFA,OAAOf,EAAA,CAAA,EAAC,eAAA;AAAA,gBAAA;6BACpB,MAAyC;AAAA,oBAAzCD,EAAyCC,EAAAkB,CAAA,GAAA;AAAA,sBAAvB,OAAOjD,EAAK;AAAA,sBAAL,kBAAAmC,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA,CAAAS,MAAA5C,EAAK,UAAO4C;AAAA,oBAAA;;;;gBAEpBb,EAAA9E,CAAA,EAAK,qBAAxBuF,EAKcT,EAAAe,CAAA,GAAA;AAAA;kBALyB,OAAOf,EAAA,CAAA,EAAC,oBAAA;AAAA,gBAAA;kBAElC,YACT,MAAgE;AAAA,oBAAhEmB,GAAgE,QAAhEC,IAAgEC,EAArCrB,EAAA,CAAA,EAAC,wBAAA,CAAA,GAAA,CAAA;AAAA,kBAAA;6BAF9B,MAA0D;AAAA,oBAA1DD,EAA0DC,EAAAkB,CAAA,GAAA;AAAA,sBAAxC,OAAOjD,EAAK;AAAA,sBAAL,kBAAAmC,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA,CAAAS,MAAA5C,EAAK,gBAAa4C;AAAA,oBAAA;;;;;;;;;;QASjDd,EAOEuB,IAAA;AAAA,UANQ,MAAM9C,EAAA;AAAA,kDAAAA,EAAS,QAAAqC;AAAA,UACtB,MAAMpC,EAAA;AAAA,UACN,SAASC,EAAA;AAAA,UACT,SAASpD,EAAA;AAAA,UACT,qBAAmBsD,EAAA;AAAA,UACnB,WAASI;AAAA,QAAA;QAIZe,EAA2DwB,IAAA;AAAA,mBAA3C;AAAA,UAAJ,KAAItC;AAAA,UAAiB,WAASG;AAAA,QAAA;QAG1CW,EAoBgBa,IAAA;AAAA,UAnBN,MAAMvB,EAAA;AAAA,oDAAAA,EAAS,QAAAwB;AAAA,UACtB,OAAOb,EAAA,CAAA,EAAC,gBAAA;AAAA,UACR,OAAO;AAAA,UACP,cAAYF;AAAA,UACZ,gBAAcE,EAAA,CAAA,EAAC,aAAA;AAAA,QAAA;qBAEhB,MAAyF;AAAA,YAA9ET,EAAA,cAAXiC,EAAyF,OAAzFC,IAAyFJ,EAA9C9B,EAAA,MAAU,IAAI,IAAG,QAAG8B,EAAG9B,EAAA,MAAU,IAAI,GAAA,CAAA;YAChFQ,EAWSC,EAAAc,CAAA,GAAA;AAAA,cAXA,OAAOtB;AAAA,cAAW,mBAAgB;AAAA,cAAQ,eAAa;AAAA,YAAA;yBAC9D,MAEc;AAAA,gBAFdO,EAEcC,EAAAe,CAAA,GAAA;AAAA,kBAFA,OAAOf,EAAA,CAAA,EAAC,gBAAA;AAAA,gBAAA;6BACpB,MAAwE;AAAA,oBAAxED,EAAwEC,EAAA0B,EAAA,GAAA;AAAA,sBAAtD,OAAOlC,EAAU;AAAA,sBAAV,kBAAAY,EAAA,EAAA,MAAAA,EAAA,EAAA,IAAA,CAAAS,MAAArB,EAAU,YAASqB;AAAA,sBAAG,SAASjB,GAAA;AAAA,oBAAA;;;;gBAEvCF,EAAA,cAAnBe,EAMcT,EAAAe,CAAA,GAAA;AAAA;kBANgB,OAAOf,EAAA,CAAA,EAAC,iBAAA;AAAA,gBAAA;6BACpC,MAIE;AAAA,oBAJFD,EAIE4B,IAAA;AAAA,sBAHQ,OAAOnC,EAAU;AAAA,sBAAV,kBAAAY,EAAA,EAAA,MAAAA,EAAA,EAAA,IAAA,CAAAS,MAAArB,EAAU,eAAYqB;AAAA,sBACrC,UAAA;AAAA,sBACC,aAAab,EAAA,CAAA,EAAC,qBAAA;AAAA,oBAAA;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index2.vue.js","sources":["../../../../src/views/system/role/index.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// 角色管理 = SmartTable CRUD(照职位范式)+ 专属面板两个:授权菜单弹窗(GrantMenuSheet,勾选菜单树)、数据范围抽屉(选范围类型 + 自定义机构)。\n// 删角色会**物理**删掉用户↔角色关联(不可恢复)——所以删前先查一次持有人数当面告知,单删与批量删都盖到,\n// 只给行内按钮加警告的话,勾选 + 批量删就绕过去了。\nimport { computed, h, onMounted, reactive, ref, shallowRef } from 'vue'\nimport {\n NButton,\n NSpace,\n NInput,\n NInputNumber,\n NSwitch,\n NForm,\n NFormItem,\n NSelect,\n NDropdown,\n useMessage,\n type FormInst,\n type FormRules,\n} from 'naive-ui'\nimport { useI18n } from 'vue-i18n'\nimport { SmartTable, type SmartTableColumn, type SmartTableInst } from 'smart-naive-table'\nimport AppIcon from '#/components/AppIcon.vue'\nimport FormContainer from '#/components/FormContainer/index.vue'\nimport StatusSwitch from '#/components/StatusSwitch/index.vue'\nimport OrgTreeSelect from '#/components/OrgTreeSelect/index.vue'\nimport UserPicker from '#/components/UserPicker/index.vue'\nimport GrantMenuSheet from './components/GrantMenuSheet.vue'\nimport { isBuiltinRole, grantScopeForRole } from './components/grantMenuGroups'\nimport { useConfirm } from '#/composables/useConfirm'\nimport { useBatchDelete } from '#/composables/useBatchDelete'\nimport { roleApi, menuApi, moduleApi, userApi } from '#/api'\nimport { useAuthStore } from '#/stores/auth'\nimport { translateError } from '#/utils/error'\nimport { SEARCH_ACTIONS, deriveHeaderFilters } from '#/utils/tableFilter'\nimport { TABLE_MIN_ROW_HEIGHT, TABLE_TOOLBAR } from '#/utils/tableToolbar'\nimport TableTotal from '#/components/TableTotal/index.vue'\nimport { DataScopeType, type ModuleRow, type RoleInput, type SysRole } from '#/types/api'\nimport type { MenuTreeNode } from '#/types/menu'\n\nconst { t } = useI18n()\nconst message = useMessage()\nconst { confirm } = useConfirm()\nconst auth = useAuthStore()\nconst tableRef = ref<SmartTableInst<SysRole>>()\n\n/** 「未分配」哨兵:雪花 id 无 0,用它表示 moduleId==null 的顶级目录分组。 */\nconst UNASSIGNED = 0\n/** 授权弹窗的「所属应用」下拉数据源。 */\nconst modules = shallowRef<ModuleRow[]>([])\nonMounted(async () => {\n try {\n modules.value = await moduleApi.list()\n } catch {\n // 模块列表仅供授权弹窗的「所属应用」下拉;拉取失败不阻塞角色管理主流程。\n }\n})\n\n/**\n * 持有该角色的用户数。复用用户分页端点(Size=1 只要 total),不新开接口。\n * 查不到(如只有角色 CRUD、没有用户查询权限的管理员会 403)返回 null → 退回通用文案,不阻断删除:\n * 用户数只用来让删除者知情,不改变谁能删什么。\n */\nasync function countUsers(roleId: number): Promise<number | null> {\n try {\n const { total } = await userApi.page({ page: 1, pageSize: 1, roleId })\n return total\n } catch {\n return null\n }\n}\n\nconst { checkedKeys, run: batchDelete } = useBatchDelete({\n remove: roleApi.batchRemove,\n refresh: () => tableRef.value?.refresh(),\n successMsg: t('role.deleted'),\n content: async ids => {\n const counts = await Promise.all(ids.map(countUsers))\n if (counts.some(n => n === null)) return t('common.batchDeleteConfirm', { count: ids.length })\n const users = counts.reduce<number>((sum, n) => sum + n!, 0)\n return users === 0\n ? t('common.batchDeleteConfirm', { count: ids.length })\n : t('role.batchDeleteWithUsers', { count: ids.length, users })\n },\n})\n\nasync function askDelete(r: SysRole) {\n const n = await countUsers(r.id)\n const content =\n n === null\n ? t('role.deleteConfirm', { name: r.name })\n : n === 0\n ? t('role.deleteConfirmNoUsers', { name: r.name })\n : t('role.deleteConfirmWithUsers', { name: r.name, count: n })\n const ok = await confirm({\n content,\n type: 'error',\n action: () => roleApi.remove(r.id),\n successMsg: t('role.deleted'),\n })\n if (ok) tableRef.value?.refresh()\n}\n\nconst toInput = (r: SysRole): RoleInput => ({\n name: r.name,\n code: r.code,\n sort: r.sort,\n enabled: r.enabled,\n remark: r.remark ?? '',\n isDelegatable: r.isDelegatable ?? false,\n})\n\nconst columns: SmartTableColumn<SysRole>[] = [\n { type: 'selection' },\n\n { type: 'index', title: () => t('common.rowNo'), width: 64, align: 'center' },\n {\n key: 'code',\n width: 180,\n ellipsis: { tooltip: true },\n title: () => t('role.code'),\n render: r => h('span', { class: 'mono muted' }, r.code),\n },\n {\n key: 'name',\n ellipsis: { tooltip: true },\n title: () => t('role.name'),\n card: 'title', // 窄档卡片以角色名称为标题,编码作为字段\n search: { actions: SEARCH_ACTIONS.fuzzy },\n },\n {\n key: 'sort',\n title: () => t('role.sort'),\n width: 80,\n render: r => h('span', { class: 'num muted' }, r.sort),\n },\n {\n key: 'enabled',\n title: () => t('common.status'),\n width: 90,\n render: r =>\n h(StatusSwitch, {\n value: r.enabled,\n disabled: !auth.isSuperAdmin || !auth.hasPerm('PUT:/api/v1/sys/role/{id}'),\n request: (next: boolean) => roleApi.update(r.id, { ...toInput(r), enabled: next }),\n 'onUpdate:value': (v: boolean) => {\n r.enabled = v\n },\n }),\n },\n {\n key: 'remark',\n title: () => t('role.remark'),\n ellipsis: { tooltip: true },\n render: r => r.remark || h('span', { class: 'faint' }, '—'),\n },\n {\n key: 'op',\n title: () => t('common.operation'),\n width: 240,\n fixed: 'right',\n hideInSetting: true,\n render: r => {\n // 角色定义(编辑/删除)与角色授权面(授权菜单/数据范围)为超管专属;\n // 仅\"授权用户\"(角色指派面)对普通管理员开放(经 RoleGrantPolicy 收口校验)。\n const dropdownOptions = [\n auth.isSuperAdmin && auth.hasPerm('PUT:/api/v1/sys/role/menu')\n ? { label: t('role.grantMenus'), key: 'menus' }\n : null,\n auth.isSuperAdmin && auth.hasPerm('PUT:/api/v1/sys/role/datascope')\n ? { label: t('role.dataScope'), key: 'scope' }\n : null,\n auth.hasPerm('PUT:/api/v1/sys/role/users')\n ? { label: t('role.grantUsers'), key: 'users' }\n : null,\n ].filter((o): o is { label: string; key: string } => o !== null)\n return h(NSpace, { size: 4, wrapItem: false }, () => [\n auth.isSuperAdmin && auth.hasPerm('PUT:/api/v1/sys/role/{id}')\n ? h(\n NButton,\n { size: 'small', quaternary: true, type: 'primary', onClick: () => openEdit(r) },\n () => t('common.edit'),\n )\n : null,\n auth.isSuperAdmin && auth.hasPerm('DELETE:/api/v1/sys/role/{id}')\n ? h(\n NButton,\n { size: 'small', quaternary: true, type: 'error', onClick: () => askDelete(r) },\n () => t('common.delete'),\n )\n : null,\n dropdownOptions.length\n ? h(\n NDropdown,\n {\n options: dropdownOptions,\n onSelect: (key: string) => {\n if (key === 'menus') openMenus(r)\n else if (key === 'scope') openScope(r)\n else openUsers(r)\n },\n },\n () => h(NButton, { size: 'small', quaternary: true }, () => t('common.more')),\n )\n : null,\n ])\n },\n },\n]\nderiveHeaderFilters(columns)\n\n// ── 新增/编辑弹窗 ──\nconst show = ref(false)\nconst formRef = ref<FormInst | null>(null)\nconst editingId = ref<number | null>(null)\nconst rules: FormRules = {\n code: {\n required: true,\n whitespace: true,\n message: () => t('role.codeRequired'),\n trigger: ['input', 'blur'],\n },\n name: {\n required: true,\n whitespace: true,\n message: () => t('role.nameRequired'),\n trigger: ['input', 'blur'],\n },\n}\nconst blank = (): RoleInput => ({\n name: '',\n code: '',\n sort: 0,\n enabled: true,\n remark: '',\n isDelegatable: false,\n})\nconst form = reactive<RoleInput>(blank())\n\nfunction openAdd() {\n editingId.value = null\n Object.assign(form, blank())\n show.value = true\n}\nfunction openEdit(r: SysRole) {\n editingId.value = r.id\n Object.assign(form, toInput(r))\n show.value = true\n}\nasync function save() {\n await formRef.value?.validate()\n try {\n if (editingId.value === null) await roleApi.add({ ...form })\n else await roleApi.update(editingId.value, { ...form })\n message.success(t('role.saved'))\n await tableRef.value?.refresh()\n } catch (e) {\n message.error(translateError(e))\n return false\n }\n}\n\n// ── 授权菜单弹窗(目录卡片列表 → 全量替换角色授权)──\nconst showMenus = ref(false)\n// 整份替换 + 只读(勾选态在 GrantMenuTable 自己的 reactive 里,改动经 GrantMenuSheet 带回 saveMenus),不需要深响应\nconst menuTree = shallowRef<MenuTreeNode[]>([])\nconst menuGranted = shallowRef<number[]>([])\nconst menuRole = ref<SysRole | null>(null)\nconst defaultModuleId = ref(UNASSIGNED)\n// 授权弹窗实际展示的应用:非内置角色不含系统应用(除非它下面还有消费者自建的目录)\nconst menuModules = shallowRef<ModuleRow[]>([])\n\nasync function openMenus(r: SysRole) {\n try {\n const [tree, granted] = await Promise.all([menuApi.tree(), roleApi.getMenus(r.id)])\n // 系统菜单只能授给内置角色:非内置角色的弹窗里不出现系统自带的目录(后端同样拒绝),\n // 角色身上看不见的系统菜单授权也不带进弹窗,保存时它们就不会被回传而得到 41009\n const scope = grantScopeForRole(r, tree, modules.value, granted)\n menuRole.value = r\n menuTree.value = scope.tree\n menuModules.value = scope.modules\n menuGranted.value = scope.granted\n const preferred = auth.currentModuleId ?? menuModules.value[0]?.id ?? UNASSIGNED\n defaultModuleId.value = menuModules.value.some(m => m.id === preferred)\n ? preferred\n : (menuModules.value[0]?.id ?? UNASSIGNED)\n showMenus.value = true\n } catch (e) {\n message.error(translateError(e))\n }\n}\nasync function saveMenus(ids: number[]) {\n if (menuRole.value === null) return\n try {\n await roleApi.setMenus(menuRole.value.id, ids)\n message.success(t('role.grantSaved'))\n } catch (e) {\n message.error(translateError(e))\n return false\n }\n}\n\n// ── 授权用户(UserPicker) ──\nconst userPickerRef = ref<InstanceType<typeof UserPicker> | null>(null)\nconst userRoleId = ref<number | null>(null)\n\nasync function openUsers(r: SysRole) {\n userRoleId.value = r.id\n try {\n const ids = await roleApi.getUsers(r.id)\n userPickerRef.value?.open(ids)\n } catch (e) {\n message.error(translateError(e))\n }\n}\nasync function onUserConfirm(ids: number[]) {\n if (userRoleId.value === null) return\n try {\n await roleApi.setUsers(userRoleId.value, ids)\n message.success(t('role.grantUsersSaved'))\n } catch (e) {\n message.error(translateError(e))\n }\n}\n\n// ── 数据范围抽屉 ──\nconst showScope = ref(false)\nconst scopeRoleId = ref<number | null>(null)\nconst scopeRole = ref<SysRole | null>(null)\nconst scopeForm = reactive<{ scopeType: DataScopeType; customOrgIds: number[] }>({\n scopeType: DataScopeType.Org,\n customOrgIds: [],\n})\nconst isCustom = computed(() => scopeForm.scopeType === DataScopeType.Custom)\nconst scopeOptions = computed(() => [\n { label: t('role.scope.all'), value: DataScopeType.All },\n { label: t('role.scope.org'), value: DataScopeType.Org },\n { label: t('role.scope.orgAndChildren'), value: DataScopeType.OrgAndChildren },\n { label: t('role.scope.self'), value: DataScopeType.Self },\n { label: t('role.scope.custom'), value: DataScopeType.Custom },\n])\nasync function openScope(r: SysRole) {\n scopeRoleId.value = r.id\n scopeRole.value = r\n try {\n const cfg = await roleApi.getDataScope(r.id)\n scopeForm.scopeType = cfg?.scopeType ?? DataScopeType.Org\n scopeForm.customOrgIds = cfg?.customOrgIds\n ? cfg.customOrgIds.split(',').filter(Boolean).map(Number)\n : []\n showScope.value = true\n } catch (e) {\n message.error(translateError(e))\n }\n}\nasync function saveScope() {\n if (scopeRoleId.value === null) return\n try {\n await roleApi.setDataScope(\n scopeRoleId.value,\n scopeForm.scopeType,\n isCustom.value ? scopeForm.customOrgIds : undefined,\n )\n message.success(t('role.scopeSaved'))\n } catch (e) {\n message.error(translateError(e))\n return false\n }\n}\n</script>\n\n<template>\n <SmartTable\n :toolbar=\"TABLE_TOOLBAR\"\n ref=\"tableRef\"\n :columns=\"columns\"\n :fetcher=\"roleApi.page\"\n :search=\"{ container: 'table' }\"\n fill-height\n :min-row-height=\"TABLE_MIN_ROW_HEIGHT\"\n card-on-narrow\n storage-key=\"sys-role\"\n :checked-row-keys=\"checkedKeys\"\n @update:checked-row-keys=\"(keys: (string | number)[]) => (checkedKeys = keys)\"\n @error=\"e => message.error(translateError(e))\"\n >\n <template #pagination-prefix=\"{ itemCount }\">\n <TableTotal :count=\"itemCount\" />\n </template>\n <template #toolbar-right>\n <n-button\n v-if=\"auth.isSuperAdmin\"\n v-auth=\"'POST:/api/v1/sys/role/add'\"\n type=\"primary\"\n @click=\"openAdd\"\n >\n <template #icon><AppIcon icon=\"ph:plus\" :size=\"16\" /></template>\n {{ t('common.add') }}\n </n-button>\n </template>\n <!-- 勾选后工具栏换成批量栏(本页全选 + 已选 N 项 + 这里的按钮 + 取消选择),按钮出现即代表有勾选 -->\n <template #batch>\n <n-button\n v-if=\"auth.isSuperAdmin\"\n v-auth=\"'POST:/api/v1/sys/role/batch-delete'\"\n secondary\n type=\"error\"\n @click=\"batchDelete\"\n >\n <template #icon><AppIcon icon=\"ph:trash\" :size=\"16\" /></template>\n {{ t('common.batchDelete') }}\n </n-button>\n </template>\n </SmartTable>\n\n <!-- 新增/编辑 -->\n <FormContainer\n v-model:show=\"show\"\n :title=\"editingId === null ? t('role.addTitle') : t('role.editTitle')\"\n :width=\"480\"\n :on-confirm=\"save\"\n :confirm-text=\"t('common.save')\"\n >\n <n-form ref=\"formRef\" :model=\"form\" :rules=\"rules\" label-placement=\"left\" :label-width=\"80\">\n <n-form-item :label=\"t('role.code')\" path=\"code\">\n <n-input\n v-model:value=\"form.code\"\n :placeholder=\"t('role.code')\"\n :disabled=\"editingId !== null\"\n />\n </n-form-item>\n <n-form-item :label=\"t('role.name')\" path=\"name\">\n <n-input v-model:value=\"form.name\" :placeholder=\"t('role.name')\" />\n </n-form-item>\n <n-form-item :label=\"t('role.sort')\">\n <n-input-number v-model:value=\"form.sort\" :min=\"0\" style=\"width: 160px\" />\n </n-form-item>\n <n-form-item :label=\"t('role.remark')\">\n <n-input\n v-model:value=\"form.remark as string\"\n type=\"textarea\"\n :rows=\"2\"\n :placeholder=\"t('role.remark')\"\n />\n </n-form-item>\n <n-form-item :label=\"t('common.status')\">\n <n-switch v-model:value=\"form.enabled\" />\n </n-form-item>\n <n-form-item v-if=\"auth.isSuperAdmin\" :label=\"t('role.isDelegatable')\">\n <n-switch v-model:value=\"form.isDelegatable as boolean\" />\n <template #feedback>\n <span class=\"form-hint\">{{ t('role.isDelegatableHint') }}</span>\n </template>\n </n-form-item>\n </n-form>\n </FormContainer>\n\n <!-- 授权菜单 -->\n <GrantMenuSheet\n v-model:show=\"showMenus\"\n :tree=\"menuTree\"\n :granted=\"menuGranted\"\n :modules=\"menuModules\"\n :default-module-id=\"defaultModuleId\"\n :hint=\"menuRole && !isBuiltinRole(menuRole) ? t('role.systemMenusBuiltinOnly') : undefined\"\n :on-save=\"saveMenus\"\n />\n\n <!-- 授权用户 -->\n <UserPicker ref=\"userPickerRef\" @confirm=\"onUserConfirm\" />\n\n <!-- 数据范围 -->\n <FormContainer\n v-model:show=\"showScope\"\n :title=\"t('role.dataScope')\"\n :width=\"480\"\n :on-confirm=\"saveScope\"\n :confirm-text=\"t('common.save')\"\n >\n <div v-if=\"scopeRole\" class=\"scope-who\">{{ scopeRole.name }} · {{ scopeRole.code }}</div>\n <n-form :model=\"scopeForm\" label-placement=\"left\" :label-width=\"90\">\n <n-form-item :label=\"t('role.scopeType')\">\n <n-select v-model:value=\"scopeForm.scopeType\" :options=\"scopeOptions\" />\n </n-form-item>\n <n-form-item v-if=\"isCustom\" :label=\"t('role.customOrgs')\">\n <OrgTreeSelect\n v-model:value=\"scopeForm.customOrgIds\"\n multiple\n :placeholder=\"t('role.customOrgsHint')\"\n />\n </n-form-item>\n </n-form>\n </FormContainer>\n</template>\n\n<style scoped>\n/* 开关下方的说明文字 */\n.form-hint {\n font-size: 13px;\n color: var(--text-3);\n}\n\n/* 数据范围表单顶部:当前角色「名称 · 编码」 */\n.scope-who {\n margin: -4px 0 14px;\n font-size: 13px;\n color: var(--text-3);\n}\n</style>\n"],"names":["UNASSIGNED","useI18n","message","useMessage","confirm","useConfirm","auth","useAuthStore","tableRef","ref","modules","shallowRef","onMounted","moduleApi","countUsers","roleId","total","userApi","checkedKeys","batchDelete","useBatchDelete","roleApi","_a","ids","counts","n","users","sum","askDelete","r","content","toInput","columns","h","SEARCH_ACTIONS","StatusSwitch","next","v","dropdownOptions","o","NSpace","NButton","openEdit","NDropdown","key","openMenus","openScope","deriveHeaderFilters","show","formRef","editingId","rules","blank","form","reactive","openAdd","save","_b","e","translateError","showMenus","menuTree","menuGranted","menuRole","defaultModuleId","menuModules","tree","granted","menuApi","scope","grantScopeForRole","preferred","m","saveMenus","userPickerRef","userRoleId","openUsers","onUserConfirm","showScope","scopeRoleId","scopeRole","scopeForm","DataScopeType","isCustom","computed","scopeOptions","cfg","saveScope","_createVNode","_unref","SmartTable","TABLE_TOOLBAR","TABLE_MIN_ROW_HEIGHT","_cache","keys","_withCtx","itemCount","TableTotal","_createBlock","AppIcon","_createTextVNode","FormContainer","$event","NForm","NFormItem","NInput","NInputNumber","NSwitch","_createElementVNode","_hoisted_1","_toDisplayString","GrantMenuSheet","isBuiltinRole","UserPicker","_createElementBlock","_hoisted_2","NSelect","OrgTreeSelect"],"mappings":"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"}
@@ -1,70 +1,74 @@
1
- import { defineComponent as g, ref as y, computed as w, openBlock as T, createBlock as _, unref as s, withCtx as x, createVNode as S, h as i } from "vue";
1
+ import { defineComponent as g, ref as y, computed as w, openBlock as T, createBlock as _, unref as i, withCtx as x, createVNode as S, h as s } from "vue";
2
2
  import { useMessage as A, NButton as I } from "naive-ui";
3
3
  import { useI18n as b } from "vue-i18n";
4
4
  import { SmartTable as E } from "smart-naive-table";
5
5
  import { useConfirm as v } from "../../../composables/useConfirm.js";
6
6
  import { useAuthStore as C } from "../../../stores/auth.js";
7
7
  import { useUserStore as B } from "../../../stores/user.js";
8
- import { sessionApi as l } from "../../../api/index.js";
8
+ import { sessionApi as m } from "../../../api/index.js";
9
9
  import { translateError as z } from "../../../utils/error.js";
10
- import { fmtDateTime as u } from "../../../utils/format.js";
10
+ import { fmtDateTime as p } from "../../../utils/format.js";
11
11
  import { jwtClaim as F } from "../../../utils/jwt.js";
12
12
  import { TABLE_MIN_ROW_HEIGHT as L, TABLE_TOOLBAR as N } from "../../../utils/tableToolbar.js";
13
13
  import R from "../../../components/TableTotal/index.vue.js";
14
14
  import { createClientFilterFetcher as H, deriveHeaderFilters as M, passthroughFilterSerializer as O } from "../../../utils/tableFilter.js";
15
15
  import { uaSummary as D } from "../../../utils/ua.js";
16
- const te = /* @__PURE__ */ g({
16
+ const re = /* @__PURE__ */ g({
17
17
  __name: "index",
18
18
  setup(j) {
19
- const { t: r } = b(), p = A(), { confirm: f } = v(), d = C(), n = B(), a = y(), h = H(l.online, ["account", "ip"]);
19
+ const { t } = b(), u = A(), { confirm: f } = v(), d = C(), n = B(), a = y(), h = H(m.online, ["account", "ip"]);
20
20
  function k(e) {
21
21
  f({
22
22
  type: "warning",
23
- content: r("session.kickConfirm", { account: e.account }),
24
- action: () => l.kick(e.sessionId),
25
- successMsg: r("session.kicked")
23
+ content: t("session.kickConfirm", { account: e.account }),
24
+ action: () => m.kick(e.sessionId),
25
+ successMsg: t("session.kicked")
26
26
  }).then((o) => {
27
- var t;
28
- o && ((t = a.value) == null || t.refresh());
27
+ var r;
28
+ o && ((r = a.value) == null || r.refresh());
29
29
  });
30
30
  }
31
- const c = w(() => F(n.accessToken, "sid")), m = [
32
- { type: "index", title: () => r("common.rowNo"), width: 64, align: "center" },
33
- { key: "account", title: () => r("session.account"), search: {} },
31
+ const c = w(() => F(n.accessToken, "sid")), l = [
32
+ { type: "index", title: () => t("common.rowNo"), width: 64, align: "center" },
33
+ { key: "account", ellipsis: { tooltip: !0 }, title: () => t("session.account"), search: {} },
34
34
  {
35
35
  key: "ip",
36
- title: () => r("session.ip"),
36
+ width: 140,
37
+ ellipsis: { tooltip: !0 },
38
+ title: () => t("session.ip"),
37
39
  search: {},
38
- render: (e) => i("span", { class: "mono muted" }, e.ip || "—")
40
+ render: (e) => s("span", { class: "mono muted" }, e.ip || "—")
39
41
  },
40
42
  // 设备:同一账号多端在线时靠它分辨要踢哪台(UA 解析成「浏览器 · 系统」)
41
43
  {
42
44
  key: "device",
43
- title: () => r("session.device"),
45
+ title: () => t("session.device"),
44
46
  ellipsis: { tooltip: !0 },
45
47
  render: (e) => D(e.userAgent)
46
48
  },
47
49
  {
48
50
  key: "loginTime",
49
- title: () => r("session.loginTime"),
50
- render: (e) => i("span", { class: "num muted", style: "white-space: nowrap" }, u(e.loginTime))
51
+ width: 170,
52
+ title: () => t("session.loginTime"),
53
+ render: (e) => s("span", { class: "num muted", style: "white-space: nowrap" }, p(e.loginTime))
51
54
  },
52
55
  {
53
56
  key: "expiresAt",
54
- title: () => r("session.expiresAt"),
55
- render: (e) => i("span", { class: "num muted", style: "white-space: nowrap" }, u(e.expiresAt))
57
+ width: 170,
58
+ title: () => t("session.expiresAt"),
59
+ render: (e) => s("span", { class: "num muted", style: "white-space: nowrap" }, p(e.expiresAt))
56
60
  },
57
61
  {
58
62
  key: "op",
59
- title: () => r("common.operation"),
63
+ title: () => t("common.operation"),
60
64
  width: 120,
61
65
  fixed: "right",
62
66
  hideInSetting: !0,
63
67
  render: (e) => {
64
- var t;
68
+ var r;
65
69
  if (!d.hasPerm("DELETE:/api/v1/sys/session/{sessionid}")) return null;
66
- const o = c.value ? e.sessionId === c.value : e.userId === ((t = n.userInfo) == null ? void 0 : t.userId);
67
- return i(
70
+ const o = c.value ? e.sessionId === c.value : e.userId === ((r = n.userInfo) == null ? void 0 : r.userId);
71
+ return s(
68
72
  I,
69
73
  {
70
74
  size: "small",
@@ -74,33 +78,33 @@ const te = /* @__PURE__ */ g({
74
78
  disabled: o,
75
79
  onClick: () => k(e)
76
80
  },
77
- () => r(o ? "session.self" : "session.kick")
81
+ () => t(o ? "session.self" : "session.kick")
78
82
  );
79
83
  }
80
84
  }
81
85
  ];
82
- return M(m), (e, o) => (T(), _(s(E), {
86
+ return M(l), (e, o) => (T(), _(i(E), {
83
87
  ref_key: "tableRef",
84
88
  ref: a,
85
- columns: m,
86
- fetcher: s(h),
87
- toolbar: s(N),
89
+ columns: l,
90
+ fetcher: i(h),
91
+ toolbar: i(N),
88
92
  search: { container: "table" },
89
- "filter-serializer": s(O),
93
+ "filter-serializer": i(O),
90
94
  "fill-height": "",
91
- "min-row-height": s(L),
95
+ "min-row-height": i(L),
92
96
  "card-on-narrow": "",
93
97
  "storage-key": "sys-session",
94
- onError: o[0] || (o[0] = (t) => s(p).error(s(z)(t)))
98
+ onError: o[0] || (o[0] = (r) => i(u).error(i(z)(r)))
95
99
  }, {
96
- "pagination-prefix": x(({ itemCount: t }) => [
97
- S(R, { count: t }, null, 8, ["count"])
100
+ "pagination-prefix": x(({ itemCount: r }) => [
101
+ S(R, { count: r }, null, 8, ["count"])
98
102
  ]),
99
103
  _: 1
100
104
  }, 8, ["fetcher", "toolbar", "filter-serializer", "min-row-height"]));
101
105
  }
102
106
  });
103
107
  export {
104
- te as default
108
+ re as default
105
109
  };
106
110
  //# sourceMappingURL=index2.vue.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index2.vue.js","sources":["../../../../src/views/system/session/index.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// 在线会话 = 只读 SmartTable + 行内「强制下线」。无表单。踢人走 useConfirm 二次确认(warning),\n// 踢「当前这一条」会话置灰(防误踢自己下线)。后端仅按 UserId 过滤、没有条件搜索能力,\n// 所以搜索由前端求值:无条件时仍走服务端分页,有条件时取全量再在前端过滤(见 createClientFilterFetcher)。\nimport { computed, h, ref } from 'vue'\nimport { NButton, useMessage } from 'naive-ui'\nimport { useI18n } from 'vue-i18n'\nimport { SmartTable, type SmartTableColumn, type SmartTableInst } from 'smart-naive-table'\nimport { useConfirm } from '#/composables/useConfirm'\nimport { useAuthStore } from '#/stores/auth'\nimport { useUserStore } from '#/stores/user'\nimport { sessionApi } from '#/api'\nimport { translateError } from '#/utils/error'\nimport { fmtDateTime } from '#/utils/format'\nimport { jwtClaim } from '#/utils/jwt'\nimport { TABLE_MIN_ROW_HEIGHT, TABLE_TOOLBAR } from '#/utils/tableToolbar'\nimport TableTotal from '#/components/TableTotal/index.vue'\nimport {\n createClientFilterFetcher,\n passthroughFilterSerializer,\n deriveHeaderFilters,\n} from '#/utils/tableFilter'\nimport { uaSummary } from '#/utils/ua'\nimport type { OnlineSessionItem } from '#/types/api'\n\nconst { t } = useI18n()\nconst message = useMessage()\nconst { confirm } = useConfirm()\nconst authStore = useAuthStore()\nconst userStore = useUserStore()\nconst tableRef = ref<SmartTableInst<OnlineSessionItem>>()\n// fields 要与下面声明了 search 的列 key 一致\nconst fetcher = createClientFilterFetcher(sessionApi.online, ['account', 'ip'])\n\nfunction kick(r: OnlineSessionItem) {\n confirm({\n type: 'warning',\n content: t('session.kickConfirm', { account: r.account }),\n action: () => sessionApi.kick(r.sessionId),\n successMsg: t('session.kicked'),\n }).then(ok => {\n if (ok) tableRef.value?.refresh()\n })\n}\n\n// computed:令牌会变(Cookie 会话 F5 后要等静默刷新完成才有 access,刷新后也会换新令牌),sid 要跟着读\nconst currentSid = computed(() => jwtClaim(userStore.accessToken, 'sid'))\n\nconst columns: SmartTableColumn<OnlineSessionItem>[] = [\n { type: 'index', title: () => t('common.rowNo'), width: 64, align: 'center' },\n { key: 'account', title: () => t('session.account'), search: {} },\n {\n key: 'ip',\n title: () => t('session.ip'),\n search: {},\n render: r => h('span', { class: 'mono muted' }, r.ip || '—'),\n },\n // 设备:同一账号多端在线时靠它分辨要踢哪台(UA 解析成「浏览器 · 系统」)\n {\n key: 'device',\n title: () => t('session.device'),\n ellipsis: { tooltip: true },\n render: r => uaSummary(r.userAgent),\n },\n {\n key: 'loginTime',\n title: () => t('session.loginTime'),\n render: r =>\n h('span', { class: 'num muted', style: 'white-space: nowrap' }, fmtDateTime(r.loginTime)),\n },\n {\n key: 'expiresAt',\n title: () => t('session.expiresAt'),\n render: r =>\n h('span', { class: 'num muted', style: 'white-space: nowrap' }, fmtDateTime(r.expiresAt)),\n },\n {\n key: 'op',\n title: () => t('common.operation'),\n width: 120,\n fixed: 'right',\n hideInSetting: true,\n render: r => {\n if (!authStore.hasPerm('DELETE:/api/v1/sys/session/{sessionid}')) return null\n // 只置灰当前这一条会话:同一账号在别的设备上的会话是可以(也经常需要)被踢掉的。\n // 当前会话 id 取自访问令牌的 sid 声明。极少数读不到时(比如 F5 后 Cookie 会话还没静默刷新完、令牌还没回来),\n // 退回保守规则(同账号的会话一律置灰),宁可少踢也不误踢自己。\n const isSelf = currentSid.value\n ? r.sessionId === currentSid.value\n : r.userId === userStore.userInfo?.userId\n return h(\n NButton,\n {\n size: 'small',\n quaternary: true,\n type: 'error',\n // 踢自己的会话置灰:防误把自己下线\n disabled: isSelf,\n onClick: () => kick(r),\n },\n () => (isSelf ? t('session.self') : t('session.kick')),\n )\n },\n },\n]\nderiveHeaderFilters(columns)\n</script>\n\n<template>\n <SmartTable\n ref=\"tableRef\"\n :columns=\"columns\"\n :fetcher=\"fetcher\"\n :toolbar=\"TABLE_TOOLBAR\"\n :search=\"{ container: 'table' }\"\n :filter-serializer=\"passthroughFilterSerializer\"\n fill-height\n :min-row-height=\"TABLE_MIN_ROW_HEIGHT\"\n card-on-narrow\n storage-key=\"sys-session\"\n @error=\"e => message.error(translateError(e))\"\n >\n <template #pagination-prefix=\"{ itemCount }\">\n <TableTotal :count=\"itemCount\" />\n </template>\n </SmartTable>\n</template>\n"],"names":["t","useI18n","message","useMessage","confirm","useConfirm","authStore","useAuthStore","userStore","useUserStore","tableRef","ref","fetcher","createClientFilterFetcher","sessionApi","kick","r","ok","_a","currentSid","computed","jwtClaim","columns","h","uaSummary","fmtDateTime","isSelf","NButton","deriveHeaderFilters","_createBlock","_unref","SmartTable","TABLE_TOOLBAR","passthroughFilterSerializer","TABLE_MIN_ROW_HEIGHT","_cache","e","translateError","_withCtx","itemCount","_createVNode","TableTotal"],"mappings":"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"}
1
+ {"version":3,"file":"index2.vue.js","sources":["../../../../src/views/system/session/index.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// 在线会话 = 只读 SmartTable + 行内「强制下线」。无表单。踢人走 useConfirm 二次确认(warning),\n// 踢「当前这一条」会话置灰(防误踢自己下线)。后端仅按 UserId 过滤、没有条件搜索能力,\n// 所以搜索由前端求值:无条件时仍走服务端分页,有条件时取全量再在前端过滤(见 createClientFilterFetcher)。\nimport { computed, h, ref } from 'vue'\nimport { NButton, useMessage } from 'naive-ui'\nimport { useI18n } from 'vue-i18n'\nimport { SmartTable, type SmartTableColumn, type SmartTableInst } from 'smart-naive-table'\nimport { useConfirm } from '#/composables/useConfirm'\nimport { useAuthStore } from '#/stores/auth'\nimport { useUserStore } from '#/stores/user'\nimport { sessionApi } from '#/api'\nimport { translateError } from '#/utils/error'\nimport { fmtDateTime } from '#/utils/format'\nimport { jwtClaim } from '#/utils/jwt'\nimport { TABLE_MIN_ROW_HEIGHT, TABLE_TOOLBAR } from '#/utils/tableToolbar'\nimport TableTotal from '#/components/TableTotal/index.vue'\nimport {\n createClientFilterFetcher,\n passthroughFilterSerializer,\n deriveHeaderFilters,\n} from '#/utils/tableFilter'\nimport { uaSummary } from '#/utils/ua'\nimport type { OnlineSessionItem } from '#/types/api'\n\nconst { t } = useI18n()\nconst message = useMessage()\nconst { confirm } = useConfirm()\nconst authStore = useAuthStore()\nconst userStore = useUserStore()\nconst tableRef = ref<SmartTableInst<OnlineSessionItem>>()\n// fields 要与下面声明了 search 的列 key 一致\nconst fetcher = createClientFilterFetcher(sessionApi.online, ['account', 'ip'])\n\nfunction kick(r: OnlineSessionItem) {\n confirm({\n type: 'warning',\n content: t('session.kickConfirm', { account: r.account }),\n action: () => sessionApi.kick(r.sessionId),\n successMsg: t('session.kicked'),\n }).then(ok => {\n if (ok) tableRef.value?.refresh()\n })\n}\n\n// computed:令牌会变(Cookie 会话 F5 后要等静默刷新完成才有 access,刷新后也会换新令牌),sid 要跟着读\nconst currentSid = computed(() => jwtClaim(userStore.accessToken, 'sid'))\n\nconst columns: SmartTableColumn<OnlineSessionItem>[] = [\n { type: 'index', title: () => t('common.rowNo'), width: 64, align: 'center' },\n { key: 'account', ellipsis: { tooltip: true }, title: () => t('session.account'), search: {} },\n {\n key: 'ip',\n width: 140,\n ellipsis: { tooltip: true },\n title: () => t('session.ip'),\n search: {},\n render: r => h('span', { class: 'mono muted' }, r.ip || '—'),\n },\n // 设备:同一账号多端在线时靠它分辨要踢哪台(UA 解析成「浏览器 · 系统」)\n {\n key: 'device',\n title: () => t('session.device'),\n ellipsis: { tooltip: true },\n render: r => uaSummary(r.userAgent),\n },\n {\n key: 'loginTime',\n width: 170,\n title: () => t('session.loginTime'),\n render: r =>\n h('span', { class: 'num muted', style: 'white-space: nowrap' }, fmtDateTime(r.loginTime)),\n },\n {\n key: 'expiresAt',\n width: 170,\n title: () => t('session.expiresAt'),\n render: r =>\n h('span', { class: 'num muted', style: 'white-space: nowrap' }, fmtDateTime(r.expiresAt)),\n },\n {\n key: 'op',\n title: () => t('common.operation'),\n width: 120,\n fixed: 'right',\n hideInSetting: true,\n render: r => {\n if (!authStore.hasPerm('DELETE:/api/v1/sys/session/{sessionid}')) return null\n // 只置灰当前这一条会话:同一账号在别的设备上的会话是可以(也经常需要)被踢掉的。\n // 当前会话 id 取自访问令牌的 sid 声明。极少数读不到时(比如 F5 后 Cookie 会话还没静默刷新完、令牌还没回来),\n // 退回保守规则(同账号的会话一律置灰),宁可少踢也不误踢自己。\n const isSelf = currentSid.value\n ? r.sessionId === currentSid.value\n : r.userId === userStore.userInfo?.userId\n return h(\n NButton,\n {\n size: 'small',\n quaternary: true,\n type: 'error',\n // 踢自己的会话置灰:防误把自己下线\n disabled: isSelf,\n onClick: () => kick(r),\n },\n () => (isSelf ? t('session.self') : t('session.kick')),\n )\n },\n },\n]\nderiveHeaderFilters(columns)\n</script>\n\n<template>\n <SmartTable\n ref=\"tableRef\"\n :columns=\"columns\"\n :fetcher=\"fetcher\"\n :toolbar=\"TABLE_TOOLBAR\"\n :search=\"{ container: 'table' }\"\n :filter-serializer=\"passthroughFilterSerializer\"\n fill-height\n :min-row-height=\"TABLE_MIN_ROW_HEIGHT\"\n card-on-narrow\n storage-key=\"sys-session\"\n @error=\"e => message.error(translateError(e))\"\n >\n <template #pagination-prefix=\"{ itemCount }\">\n <TableTotal :count=\"itemCount\" />\n </template>\n </SmartTable>\n</template>\n"],"names":["useI18n","message","useMessage","confirm","useConfirm","authStore","useAuthStore","userStore","useUserStore","tableRef","ref","fetcher","createClientFilterFetcher","sessionApi","kick","r","ok","_a","currentSid","computed","jwtClaim","columns","h","uaSummary","fmtDateTime","isSelf","NButton","deriveHeaderFilters","_createBlock","_unref","SmartTable","TABLE_TOOLBAR","passthroughFilterSerializer","TABLE_MIN_ROW_HEIGHT","_cache","e","translateError","_withCtx","itemCount","_createVNode","TableTotal"],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { MenuTreeNode } from '../../../../types/menu';
2
+ import { UserMenuEffective, UserMenuGrantItem } from '../../../../types/api';
3
+ type __VLS_Props = {
4
+ tree: MenuTreeNode[];
5
+ effective: UserMenuEffective;
6
+ grants: UserMenuGrantItem[];
7
+ };
8
+ declare const __VLS_export: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
9
+ declare const _default: typeof __VLS_export;
10
+ export default _default;
@@ -0,0 +1,5 @@
1
+ import f from "./UserGrantEffectiveTable2.vue.js";
2
+ export {
3
+ f as default
4
+ };
5
+ //# sourceMappingURL=UserGrantEffectiveTable.vue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UserGrantEffectiveTable.vue.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
@@ -0,0 +1,96 @@
1
+ import { defineComponent as h, computed as k, openBlock as T, createBlock as v, unref as y, h as m } from "vue";
2
+ import { NTag as w } from "naive-ui";
3
+ import { useI18n as x } from "vue-i18n";
4
+ import { SmartTable as I } from "smart-naive-table";
5
+ import { translateMenuTitle as _ } from "../../../../locales/menuTitle.js";
6
+ import { UserMenuEffect as f } from "../../../../types/api.js";
7
+ const B = /* @__PURE__ */ h({
8
+ __name: "UserGrantEffectiveTable",
9
+ props: {
10
+ tree: {},
11
+ effective: {},
12
+ grants: {}
13
+ },
14
+ setup(p) {
15
+ const i = p, { t: n } = x(), d = k(() => {
16
+ const r = /* @__PURE__ */ new Map();
17
+ let s = 0;
18
+ const u = (e, t) => {
19
+ for (const a of e) {
20
+ const o = t + _(a.title, a.path || void 0);
21
+ r.set(a.id, { path: o, order: s++ }), u(a.children, `${o} / `);
22
+ }
23
+ };
24
+ u(i.tree, "");
25
+ const c = (e) => {
26
+ var t;
27
+ return ((t = r.get(e)) == null ? void 0 : t.order) ?? Number.MAX_SAFE_INTEGER;
28
+ }, g = new Map(i.grants.map((e) => [e.menuId, e]));
29
+ return i.effective.nodes.filter((e) => e.effective || e.grant != null).map((e) => {
30
+ var o;
31
+ const t = g.get(e.menuId), a = [
32
+ ...e.roles,
33
+ e.grant === f.Allow ? n("userGrant.allow") : e.grant === f.Deny ? n("userGrant.deny") : null,
34
+ e.expired ? n("userGrant.expired") : null,
35
+ e.deniedByAncestor ? n("userGrant.deniedByAncestor") : null
36
+ ].filter(Boolean).join(" · ");
37
+ return {
38
+ menuId: e.menuId,
39
+ path: ((o = r.get(e.menuId)) == null ? void 0 : o.path) ?? String(e.menuId),
40
+ effective: e.effective,
41
+ source: a || "—",
42
+ grant: e.grant,
43
+ grantorName: t == null ? void 0 : t.grantorName,
44
+ grantTime: t == null ? void 0 : t.grantTime,
45
+ expireTime: t == null ? void 0 : t.expireTime,
46
+ remark: t == null ? void 0 : t.remark
47
+ };
48
+ }).toSorted((e, t) => c(e.menuId) - c(t.menuId));
49
+ }), l = () => m("span", { class: "faint" }, "—"), G = [
50
+ { key: "path", title: () => n("userGrant.colMenu"), ellipsis: { tooltip: !0 } },
51
+ {
52
+ key: "effective",
53
+ title: () => n("userGrant.colState"),
54
+ width: 90,
55
+ render: (r) => m(
56
+ w,
57
+ { size: "small", bordered: !1, type: r.effective ? "success" : "default" },
58
+ () => n(r.effective ? "userGrant.effective" : "userGrant.ineffective")
59
+ )
60
+ },
61
+ { key: "source", title: () => n("userGrant.colSource"), ellipsis: { tooltip: !0 } },
62
+ {
63
+ key: "grantorName",
64
+ title: () => n("userGrant.colGrantor"),
65
+ width: 120,
66
+ ellipsis: { tooltip: !0 },
67
+ render: (r) => r.grantorName || l()
68
+ },
69
+ { key: "grantTime", title: () => n("userGrant.colGrantTime"), width: 170, format: "datetime" },
70
+ {
71
+ key: "expireTime",
72
+ title: () => n("userGrant.colExpire"),
73
+ width: 170,
74
+ render: (r) => r.grant == null ? l() : r.expireTime ? r.expireTime.replace("T", " ") : n("userGrant.expireLongTerm")
75
+ },
76
+ {
77
+ key: "remark",
78
+ title: () => n("userGrant.colRemark"),
79
+ ellipsis: { tooltip: !0 },
80
+ render: (r) => r.remark || l()
81
+ }
82
+ ];
83
+ return (r, s) => (T(), v(y(I), {
84
+ columns: G,
85
+ data: d.value,
86
+ "row-key": "menuId",
87
+ toolbar: !1,
88
+ pagination: !1,
89
+ "fill-height": ""
90
+ }, null, 8, ["data"]));
91
+ }
92
+ });
93
+ export {
94
+ B as default
95
+ };
96
+ //# sourceMappingURL=UserGrantEffectiveTable2.vue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UserGrantEffectiveTable2.vue.js","sources":["../../../../../src/views/system/user/components/UserGrantEffectiveTable.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// 「有效权限」页签:只读列出有效的节点和有单独授权记录的节点,说清来源;单独授权带上授权人、时间、到期、理由。\n// 嵌在弹窗里的小表,不套整页列表标准(登记在 listSearch.spec.ts 的 EMBEDDED)。\nimport { computed, h } from 'vue'\nimport { NTag } from 'naive-ui'\nimport { useI18n } from 'vue-i18n'\nimport { SmartTable, type SmartTableColumn } from 'smart-naive-table'\nimport { translateMenuTitle } from '#/locales/menuTitle'\nimport type { MenuTreeNode } from '#/types/menu'\nimport { UserMenuEffect, type UserMenuEffective, type UserMenuGrantItem } from '#/types/api'\n\nconst props = defineProps<{\n tree: MenuTreeNode[]\n effective: UserMenuEffective\n grants: UserMenuGrantItem[]\n}>()\nconst { t } = useI18n()\n\ninterface Row {\n menuId: number\n path: string\n effective: boolean\n source: string\n grant?: UserMenuEffect | null\n grantorName?: string | null\n grantTime?: string\n expireTime?: string | null\n remark?: string | null\n}\n\nconst rows = computed<Row[]>(() => {\n // 按树的先序排:同一目录下的节点挨在一起,路径带上目录 / 页面前缀\n const paths = new Map<number, { path: string; order: number }>()\n let order = 0\n const walk = (nodes: MenuTreeNode[], prefix: string) => {\n for (const n of nodes) {\n const path = prefix + translateMenuTitle(n.title, n.path || undefined)\n paths.set(n.id, { path, order: order++ })\n walk(n.children, `${path} / `)\n }\n }\n walk(props.tree, '')\n // 不在菜单树里的节点(树已被收窄或节点已删)排到最后,不打乱树的先序\n const orderOf = (menuId: number) => paths.get(menuId)?.order ?? Number.MAX_SAFE_INTEGER\n const grantOf = new Map(props.grants.map(g => [g.menuId, g]))\n return props.effective.nodes\n .filter(n => n.effective || n.grant != null)\n .map(n => {\n const g = grantOf.get(n.menuId)\n const source = [\n ...n.roles,\n n.grant === UserMenuEffect.Allow\n ? t('userGrant.allow')\n : n.grant === UserMenuEffect.Deny\n ? t('userGrant.deny')\n : null,\n n.expired ? t('userGrant.expired') : null,\n n.deniedByAncestor ? t('userGrant.deniedByAncestor') : null,\n ]\n .filter(Boolean)\n .join(' · ')\n return {\n menuId: n.menuId,\n path: paths.get(n.menuId)?.path ?? String(n.menuId),\n effective: n.effective,\n source: source || '—',\n grant: n.grant,\n grantorName: g?.grantorName,\n grantTime: g?.grantTime,\n expireTime: g?.expireTime,\n remark: g?.remark,\n }\n })\n .toSorted((a, b) => orderOf(a.menuId) - orderOf(b.menuId))\n})\n\nconst dash = () => h('span', { class: 'faint' }, '—')\nconst columns: SmartTableColumn<Row>[] = [\n { key: 'path', title: () => t('userGrant.colMenu'), ellipsis: { tooltip: true } },\n {\n key: 'effective',\n title: () => t('userGrant.colState'),\n width: 90,\n render: r =>\n h(NTag, { size: 'small', bordered: false, type: r.effective ? 'success' : 'default' }, () =>\n t(r.effective ? 'userGrant.effective' : 'userGrant.ineffective'),\n ),\n },\n { key: 'source', title: () => t('userGrant.colSource'), ellipsis: { tooltip: true } },\n {\n key: 'grantorName',\n title: () => t('userGrant.colGrantor'),\n width: 120,\n ellipsis: { tooltip: true },\n render: r => r.grantorName || dash(),\n },\n { key: 'grantTime', title: () => t('userGrant.colGrantTime'), width: 170, format: 'datetime' },\n {\n key: 'expireTime',\n title: () => t('userGrant.colExpire'),\n width: 170,\n render: r =>\n r.grant == null\n ? dash()\n : r.expireTime\n ? r.expireTime.replace('T', ' ')\n : t('userGrant.expireLongTerm'),\n },\n {\n key: 'remark',\n title: () => t('userGrant.colRemark'),\n ellipsis: { tooltip: true },\n render: r => r.remark || dash(),\n },\n]\n</script>\n\n<template>\n <SmartTable\n :columns=\"columns\"\n :data=\"rows\"\n row-key=\"menuId\"\n :toolbar=\"false\"\n :pagination=\"false\"\n fill-height\n />\n</template>\n"],"names":["props","__props","t","useI18n","rows","computed","paths","order","walk","nodes","prefix","n","path","translateMenuTitle","orderOf","menuId","_a","grantOf","g","source","UserMenuEffect","a","b","dash","h","columns","NTag","_createBlock","_unref","SmartTable"],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ declare function open(target: {
2
+ id: number;
3
+ name: string;
4
+ }): Promise<void>;
5
+ declare const __VLS_export: import('vue').DefineComponent<{}, {
6
+ open: typeof open;
7
+ }, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {} & {
8
+ saved: () => any;
9
+ }, string, import('vue').PublicProps, Readonly<{}> & Readonly<{
10
+ onSaved?: (() => any) | undefined;
11
+ }>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
12
+ declare const _default: typeof __VLS_export;
13
+ export default _default;
@@ -0,0 +1,8 @@
1
+ import t from "./UserGrantMenuSheet2.vue.js";
2
+ /* empty css */
3
+ import e from "../../../../_virtual/_plugin-vue_export-helper.js";
4
+ const m = /* @__PURE__ */ e(t, [["__scopeId", "data-v-638e4471"]]);
5
+ export {
6
+ m as default
7
+ };
8
+ //# sourceMappingURL=UserGrantMenuSheet.vue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UserGrantMenuSheet.vue.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}