com-angel-authorization 1.0.14 → 1.0.16

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.
@@ -41,19 +41,25 @@ __export(vue_exports, {
41
41
  ROOT_MENU_DEPTH: () => ROOT_MENU_DEPTH,
42
42
  ROOT_PARENT_ID: () => ROOT_PARENT_ID,
43
43
  ResourceManager: () => ResourceManager,
44
+ RoleManager: () => RoleManager,
44
45
  SYSTEM_ADMIN_DEFAULT_KEY: () => SYSTEM_ADMIN_DEFAULT_KEY,
45
46
  SYSTEM_ADMIN_MENU: () => SYSTEM_ADMIN_MENU,
46
47
  SystemAdmin: () => SystemAdmin,
47
48
  appendQueryParam: () => appendQueryParam,
48
49
  buildCreateBody: () => buildCreateBody,
49
50
  buildCreateMenuBody: () => buildCreateMenuBody,
51
+ buildCreateRoleBody: () => buildCreateRoleBody,
52
+ buildSavePermissionsBody: () => buildSavePermissionsBody,
50
53
  buildUpdateBody: () => buildUpdateBody,
51
54
  buildUpdateMenuBody: () => buildUpdateMenuBody,
55
+ buildUpdateRoleBody: () => buildUpdateRoleBody,
56
+ collectTreeResourceIds: () => collectTreeResourceIds,
52
57
  createAuthorizationResourceApi: () => createAuthorizationResourceApi,
53
58
  createDefaultResourceRequest: () => createDefaultResourceRequest,
54
59
  createMenuResourceApi: () => createMenuResourceApi,
55
60
  createPermissionPlugin: () => createPermissionPlugin,
56
61
  createPermissionStore: () => createPermissionStore,
62
+ createSystemRoleApi: () => createSystemRoleApi,
57
63
  createVPermission: () => createVPermission,
58
64
  extractPagination: () => extractPagination,
59
65
  extractRecords: () => extractRecords,
@@ -62,6 +68,9 @@ __export(vue_exports, {
62
68
  isMenuLeaf: () => isMenuLeaf,
63
69
  mapAuthorizationResource: () => mapAuthorizationResource,
64
70
  mapMenuResource: () => mapMenuResource,
71
+ mapPermissionTreeNode: () => mapPermissionTreeNode,
72
+ mapRolePermissions: () => mapRolePermissions,
73
+ mapSystemRole: () => mapSystemRole,
65
74
  resolveMenuDepth: () => resolveMenuDepth,
66
75
  snowyflake: () => snowyflake,
67
76
  useHasPermission: () => useHasPermission,
@@ -558,7 +567,7 @@ function toStringArray(value) {
558
567
  }).filter(Boolean);
559
568
  }
560
569
  if (typeof value === "string" && value.trim()) {
561
- return value.split(",").map((s4) => s4.trim()).filter(Boolean);
570
+ return value.split(",").map((s5) => s5.trim()).filter(Boolean);
562
571
  }
563
572
  return [];
564
573
  }
@@ -2395,8 +2404,985 @@ var MenuManager = (0, import_vue4.defineComponent)({
2395
2404
  }
2396
2405
  });
2397
2406
 
2407
+ // src/vue/RoleManager.ts
2408
+ var import_vue5 = require("vue");
2409
+
2410
+ // src/roles/index.ts
2411
+ function mapSystemRole(item) {
2412
+ if (!item || typeof item !== "object") return null;
2413
+ const row = item;
2414
+ const roleId = row.roleId ?? row.role_id ?? row.id;
2415
+ if (roleId === void 0 || roleId === null || roleId === "") return null;
2416
+ return {
2417
+ roleId: String(roleId),
2418
+ name: String(row.name ?? ""),
2419
+ description: String(row.description ?? row.desc ?? "")
2420
+ };
2421
+ }
2422
+ function mapPermissionTreeNode(item) {
2423
+ if (!item || typeof item !== "object") return null;
2424
+ const row = item;
2425
+ const resourceId = row.resourceId ?? row.resource_id ?? row.id;
2426
+ if (resourceId === void 0 || resourceId === null || resourceId === "") return null;
2427
+ const rawChildren = row.children ?? row.childList ?? row.child_list ?? [];
2428
+ const children = Array.isArray(rawChildren) ? rawChildren.map(mapPermissionTreeNode).filter((node) => node !== null) : [];
2429
+ return {
2430
+ resourceId: String(resourceId),
2431
+ name: String(row.name ?? ""),
2432
+ children
2433
+ };
2434
+ }
2435
+ function asObject(value) {
2436
+ return value && typeof value === "object" ? value : null;
2437
+ }
2438
+ function mapRolePermissions(payload) {
2439
+ const envelope = asObject(payload) ?? {};
2440
+ const data = asObject(envelope.data) ?? envelope;
2441
+ const rawIds = data.resourceIds ?? data.resource_ids ?? [];
2442
+ const resourceIds = Array.isArray(rawIds) ? rawIds.map((id) => id === void 0 || id === null ? "" : String(id)).filter(Boolean) : [];
2443
+ const rawTree = data.resourceTree ?? data.resource_tree ?? [];
2444
+ const resourceTree = Array.isArray(rawTree) ? rawTree.map(mapPermissionTreeNode).filter((node) => node !== null) : [];
2445
+ return { resourceIds, resourceTree };
2446
+ }
2447
+ function collectTreeResourceIds(node) {
2448
+ return [node.resourceId, ...node.children.flatMap(collectTreeResourceIds)];
2449
+ }
2450
+ function buildListUrl2(params) {
2451
+ const parts = [];
2452
+ appendQueryParam(parts, "keyword", params?.keyword ?? "");
2453
+ appendQueryParam(parts, "page-token", params?.pagination?.pageToken ?? "");
2454
+ appendQueryParam(parts, "page-size", params?.pagination?.pageSize ?? "20");
2455
+ appendQueryParam(parts, "page-direction", params?.pagination?.pageDirection ?? "current");
2456
+ return parts.length ? `/system/roles?${parts.join("&")}` : "/system/roles";
2457
+ }
2458
+ function buildCreateRoleBody(values) {
2459
+ return {
2460
+ name: values.name.trim(),
2461
+ description: values.description.trim()
2462
+ };
2463
+ }
2464
+ function buildUpdateRoleBody(values) {
2465
+ return {
2466
+ name: values.name.trim(),
2467
+ description: values.description.trim()
2468
+ };
2469
+ }
2470
+ function buildSavePermissionsBody(resourceIds) {
2471
+ return {
2472
+ resourceIds: [...new Set(resourceIds.map(String).filter(Boolean))]
2473
+ };
2474
+ }
2475
+ function createSystemRoleApi(request) {
2476
+ return {
2477
+ async list(params, signal) {
2478
+ const json = await request({
2479
+ method: "GET",
2480
+ url: buildListUrl2(params),
2481
+ signal
2482
+ });
2483
+ const records = extractRecords(json).map(mapSystemRole).filter((item) => item !== null);
2484
+ return {
2485
+ records,
2486
+ ...extractPagination(json)
2487
+ };
2488
+ },
2489
+ async create(values, signal) {
2490
+ return request({
2491
+ method: "POST",
2492
+ url: "/system/roles",
2493
+ body: buildCreateRoleBody(values),
2494
+ signal
2495
+ });
2496
+ },
2497
+ async update(roleId, values, signal) {
2498
+ return request({
2499
+ method: "PATCH",
2500
+ url: `/system/roles/${encodeURIComponent(roleId)}`,
2501
+ body: buildUpdateRoleBody(values),
2502
+ signal
2503
+ });
2504
+ },
2505
+ async remove(roleId, signal) {
2506
+ return request({
2507
+ method: "DELETE",
2508
+ url: `/system/roles/${encodeURIComponent(roleId)}`,
2509
+ signal
2510
+ });
2511
+ },
2512
+ async getPermissions(roleId, signal) {
2513
+ const json = await request({
2514
+ method: "GET",
2515
+ url: `/system/roles/${encodeURIComponent(roleId)}/permissions`,
2516
+ signal
2517
+ });
2518
+ return mapRolePermissions(json);
2519
+ },
2520
+ async savePermissions(roleId, resourceIds, signal) {
2521
+ return request({
2522
+ method: "POST",
2523
+ url: `/system/roles/${encodeURIComponent(roleId)}/permissions`,
2524
+ body: buildSavePermissionsBody(resourceIds),
2525
+ signal
2526
+ });
2527
+ }
2528
+ };
2529
+ }
2530
+
2531
+ // src/vue/RoleManager.ts
2532
+ var PAGE_SIZE_OPTIONS3 = ["10", "20", "50", "100"];
2533
+ function emptyForm3() {
2534
+ return {
2535
+ name: "",
2536
+ description: ""
2537
+ };
2538
+ }
2539
+ function countCheckedDescendants(node, checked) {
2540
+ let total = 0;
2541
+ let checkedCount = 0;
2542
+ const walk = (n) => {
2543
+ for (const child of n.children) {
2544
+ total += 1;
2545
+ if (checked.has(child.resourceId)) checkedCount += 1;
2546
+ walk(child);
2547
+ }
2548
+ };
2549
+ walk(node);
2550
+ return { total, checkedCount };
2551
+ }
2552
+ var s3 = {
2553
+ root: {
2554
+ display: "flex",
2555
+ flexDirection: "column",
2556
+ gap: "16px",
2557
+ padding: "16px",
2558
+ color: "#101828",
2559
+ fontFamily: '"PingFang SC", "Microsoft YaHei", -apple-system, BlinkMacSystemFont, sans-serif'
2560
+ },
2561
+ toolbar: {
2562
+ display: "flex",
2563
+ alignItems: "center",
2564
+ justifyContent: "space-between",
2565
+ gap: "12px"
2566
+ },
2567
+ title: { margin: "0", fontSize: "18px", fontWeight: "600" },
2568
+ toolbarRight: { display: "flex", alignItems: "center", gap: "8px" },
2569
+ searchBar: {
2570
+ display: "flex",
2571
+ alignItems: "center",
2572
+ gap: "8px",
2573
+ flexWrap: "wrap"
2574
+ },
2575
+ error: {
2576
+ padding: "10px 12px",
2577
+ borderRadius: "8px",
2578
+ background: "#fef3f2",
2579
+ color: "#b42318",
2580
+ fontSize: "13px"
2581
+ },
2582
+ tableWrap: {
2583
+ overflow: "auto",
2584
+ border: "1px solid #eaecf0",
2585
+ borderRadius: "10px",
2586
+ background: "#fff"
2587
+ },
2588
+ table: { width: "100%", borderCollapse: "collapse", minWidth: "560px" },
2589
+ th: {
2590
+ textAlign: "left",
2591
+ padding: "12px 14px",
2592
+ fontSize: "13px",
2593
+ fontWeight: "600",
2594
+ color: "#475467",
2595
+ background: "#f9fafb",
2596
+ borderBottom: "1px solid #eaecf0"
2597
+ },
2598
+ td: {
2599
+ padding: "12px 14px",
2600
+ fontSize: "14px",
2601
+ borderBottom: "1px solid #f2f4f7",
2602
+ verticalAlign: "middle"
2603
+ },
2604
+ empty: {
2605
+ padding: "28px",
2606
+ textAlign: "center",
2607
+ color: "#98a2b3",
2608
+ fontSize: "14px"
2609
+ },
2610
+ linkBtn: {
2611
+ border: "none",
2612
+ background: "transparent",
2613
+ color: "#049BAD",
2614
+ cursor: "pointer",
2615
+ padding: "0 8px 0 0",
2616
+ fontSize: "13px"
2617
+ },
2618
+ pagination: {
2619
+ display: "flex",
2620
+ alignItems: "center",
2621
+ justifyContent: "space-between",
2622
+ gap: "12px"
2623
+ },
2624
+ pageSize: {
2625
+ display: "flex",
2626
+ alignItems: "center",
2627
+ gap: "8px",
2628
+ fontSize: "13px",
2629
+ color: "#475467"
2630
+ },
2631
+ pageBtns: { display: "flex", gap: "8px" },
2632
+ primaryBtn: {
2633
+ border: "none",
2634
+ background: "#049BAD",
2635
+ color: "#fff",
2636
+ borderRadius: "8px",
2637
+ padding: "8px 14px",
2638
+ cursor: "pointer",
2639
+ fontSize: "14px"
2640
+ },
2641
+ secondaryBtn: {
2642
+ border: "1px solid #d0d5dd",
2643
+ background: "#fff",
2644
+ color: "#344054",
2645
+ borderRadius: "8px",
2646
+ padding: "8px 14px",
2647
+ cursor: "pointer",
2648
+ fontSize: "14px"
2649
+ },
2650
+ dangerBtn: {
2651
+ border: "none",
2652
+ background: "#d92d20",
2653
+ color: "#fff",
2654
+ borderRadius: "8px",
2655
+ padding: "8px 14px",
2656
+ cursor: "pointer",
2657
+ fontSize: "14px"
2658
+ },
2659
+ select: {
2660
+ border: "1px solid #d0d5dd",
2661
+ borderRadius: "6px",
2662
+ padding: "4px 8px",
2663
+ fontSize: "13px",
2664
+ backgroundColor: "#ffffff",
2665
+ color: "#101828"
2666
+ },
2667
+ mask: {
2668
+ position: "fixed",
2669
+ inset: "0",
2670
+ background: "rgba(16, 24, 40, 0.45)",
2671
+ display: "flex",
2672
+ alignItems: "center",
2673
+ justifyContent: "center",
2674
+ zIndex: "1000",
2675
+ padding: "16px"
2676
+ },
2677
+ dialog: {
2678
+ width: "100%",
2679
+ maxWidth: "480px",
2680
+ background: "#fff",
2681
+ borderRadius: "12px",
2682
+ boxShadow: "0 20px 40px rgba(16,24,40,0.18)"
2683
+ },
2684
+ dialogHeader: {
2685
+ display: "flex",
2686
+ alignItems: "center",
2687
+ justifyContent: "space-between",
2688
+ padding: "14px 16px",
2689
+ borderBottom: "1px solid #eaecf0"
2690
+ },
2691
+ dialogTitle: { margin: "0", fontSize: "16px", fontWeight: "600" },
2692
+ iconBtn: {
2693
+ border: "none",
2694
+ background: "transparent",
2695
+ fontSize: "22px",
2696
+ lineHeight: "1",
2697
+ cursor: "pointer",
2698
+ color: "#667085"
2699
+ },
2700
+ form: {
2701
+ display: "flex",
2702
+ flexDirection: "column",
2703
+ gap: "12px",
2704
+ padding: "16px"
2705
+ },
2706
+ confirmBody: {
2707
+ display: "flex",
2708
+ flexDirection: "column",
2709
+ gap: "16px",
2710
+ padding: "16px"
2711
+ },
2712
+ confirmText: {
2713
+ margin: "0",
2714
+ fontSize: "14px",
2715
+ color: "#344054",
2716
+ lineHeight: "1.6"
2717
+ },
2718
+ authBody: {
2719
+ display: "flex",
2720
+ flexDirection: "column",
2721
+ gap: "12px",
2722
+ padding: "16px"
2723
+ },
2724
+ treePanel: {
2725
+ maxHeight: "420px",
2726
+ overflow: "auto",
2727
+ border: "1px solid #eaecf0",
2728
+ borderRadius: "8px",
2729
+ padding: "8px 0",
2730
+ background: "#fff"
2731
+ },
2732
+ treeRow: {
2733
+ display: "flex",
2734
+ alignItems: "center",
2735
+ gap: "6px",
2736
+ minHeight: "32px",
2737
+ paddingRight: "12px"
2738
+ },
2739
+ treeToggle: {
2740
+ border: "none",
2741
+ background: "transparent",
2742
+ width: "20px",
2743
+ height: "20px",
2744
+ padding: "0",
2745
+ cursor: "pointer",
2746
+ color: "#667085",
2747
+ fontSize: "10px",
2748
+ flexShrink: "0"
2749
+ },
2750
+ treeSpacer: { width: "20px", flexShrink: "0" },
2751
+ treeLabel: {
2752
+ display: "inline-flex",
2753
+ alignItems: "center",
2754
+ gap: "8px",
2755
+ fontSize: "14px",
2756
+ color: "#101828",
2757
+ cursor: "pointer",
2758
+ userSelect: "none"
2759
+ },
2760
+ checkbox: {
2761
+ width: "16px",
2762
+ height: "16px",
2763
+ accentColor: "#049BAD",
2764
+ cursor: "pointer",
2765
+ colorScheme: "light",
2766
+ backgroundColor: "#ffffff"
2767
+ },
2768
+ field: { display: "flex", flexDirection: "column", gap: "6px" },
2769
+ label: { fontSize: "13px", color: "#344054", fontWeight: "500" },
2770
+ input: {
2771
+ border: "1px solid #d0d5dd",
2772
+ borderRadius: "8px",
2773
+ padding: "8px 10px",
2774
+ fontSize: "14px",
2775
+ outline: "none",
2776
+ backgroundColor: "#ffffff",
2777
+ color: "#101828",
2778
+ boxSizing: "border-box",
2779
+ width: "100%"
2780
+ },
2781
+ dialogFooter: {
2782
+ display: "flex",
2783
+ justifyContent: "flex-end",
2784
+ gap: "8px",
2785
+ paddingTop: "4px"
2786
+ }
2787
+ };
2788
+ var RoleManager = (0, import_vue5.defineComponent)({
2789
+ name: "RoleManager",
2790
+ props: {
2791
+ api: {
2792
+ type: Object,
2793
+ required: true
2794
+ },
2795
+ title: {
2796
+ type: String,
2797
+ default: "\u89D2\u8272\u7BA1\u7406"
2798
+ },
2799
+ pageSize: {
2800
+ type: String,
2801
+ default: "20"
2802
+ }
2803
+ },
2804
+ setup(props, { slots }) {
2805
+ const records = (0, import_vue5.ref)([]);
2806
+ const loading = (0, import_vue5.ref)(false);
2807
+ const error = (0, import_vue5.ref)("");
2808
+ const keyword = (0, import_vue5.ref)("");
2809
+ const keywordInput = (0, import_vue5.ref)("");
2810
+ const pageSize = (0, import_vue5.ref)(props.pageSize);
2811
+ const pageToken = (0, import_vue5.ref)("");
2812
+ const hasPreviousPage = (0, import_vue5.ref)(false);
2813
+ const hasNextPage = (0, import_vue5.ref)(false);
2814
+ const dialogOpen = (0, import_vue5.ref)(false);
2815
+ const editing = (0, import_vue5.ref)(null);
2816
+ const form = (0, import_vue5.reactive)(emptyForm3());
2817
+ const saving = (0, import_vue5.ref)(false);
2818
+ const deletingRow = (0, import_vue5.ref)(null);
2819
+ const deleting = (0, import_vue5.ref)(false);
2820
+ const authRole = (0, import_vue5.ref)(null);
2821
+ const authTree = (0, import_vue5.ref)([]);
2822
+ const authChecked = (0, import_vue5.ref)(/* @__PURE__ */ new Set());
2823
+ const authExpanded = (0, import_vue5.ref)({});
2824
+ const authLoading = (0, import_vue5.ref)(false);
2825
+ const authSaving = (0, import_vue5.ref)(false);
2826
+ const authError = (0, import_vue5.ref)("");
2827
+ async function loadList(direction = "current", token = pageToken.value) {
2828
+ loading.value = true;
2829
+ error.value = "";
2830
+ try {
2831
+ const result = await props.api.list({
2832
+ keyword: keyword.value,
2833
+ pagination: {
2834
+ pageToken: token,
2835
+ pageSize: pageSize.value,
2836
+ pageDirection: direction
2837
+ }
2838
+ });
2839
+ records.value = result.records;
2840
+ pageToken.value = result.pageToken;
2841
+ hasPreviousPage.value = result.hasPreviousPage;
2842
+ hasNextPage.value = result.hasNextPage;
2843
+ } catch (err) {
2844
+ error.value = err instanceof Error ? err.message : "\u52A0\u8F7D\u5931\u8D25";
2845
+ } finally {
2846
+ loading.value = false;
2847
+ }
2848
+ }
2849
+ function handleSearch() {
2850
+ pageToken.value = "";
2851
+ keyword.value = keywordInput.value.trim();
2852
+ }
2853
+ function handleReset() {
2854
+ keywordInput.value = "";
2855
+ keyword.value = "";
2856
+ pageToken.value = "";
2857
+ }
2858
+ function openCreate() {
2859
+ editing.value = null;
2860
+ Object.assign(form, emptyForm3());
2861
+ dialogOpen.value = true;
2862
+ }
2863
+ function openEdit(row) {
2864
+ editing.value = row;
2865
+ Object.assign(form, {
2866
+ name: row.name,
2867
+ description: row.description
2868
+ });
2869
+ dialogOpen.value = true;
2870
+ }
2871
+ function closeDialog() {
2872
+ if (!saving.value) dialogOpen.value = false;
2873
+ }
2874
+ async function handleSubmit(event) {
2875
+ event.preventDefault();
2876
+ if (!form.name.trim()) {
2877
+ error.value = "\u8BF7\u586B\u5199\u89D2\u8272\u540D\u79F0";
2878
+ return;
2879
+ }
2880
+ saving.value = true;
2881
+ error.value = "";
2882
+ try {
2883
+ if (editing.value) {
2884
+ await props.api.update(editing.value.roleId, { ...form });
2885
+ } else {
2886
+ await props.api.create({ ...form });
2887
+ }
2888
+ dialogOpen.value = false;
2889
+ await loadList("current", "");
2890
+ } catch (err) {
2891
+ error.value = err instanceof Error ? err.message : "\u4FDD\u5B58\u5931\u8D25";
2892
+ } finally {
2893
+ saving.value = false;
2894
+ }
2895
+ }
2896
+ function askDelete(row) {
2897
+ deletingRow.value = row;
2898
+ }
2899
+ function closeDeleteDialog() {
2900
+ if (!deleting.value) deletingRow.value = null;
2901
+ }
2902
+ async function confirmDelete() {
2903
+ if (!deletingRow.value) return;
2904
+ deleting.value = true;
2905
+ error.value = "";
2906
+ try {
2907
+ await props.api.remove(deletingRow.value.roleId);
2908
+ deletingRow.value = null;
2909
+ await loadList("current", "");
2910
+ } catch (err) {
2911
+ error.value = err instanceof Error ? err.message : "\u5220\u9664\u5931\u8D25";
2912
+ } finally {
2913
+ deleting.value = false;
2914
+ }
2915
+ }
2916
+ async function openAuthorize(row) {
2917
+ authRole.value = row;
2918
+ authTree.value = [];
2919
+ authChecked.value = /* @__PURE__ */ new Set();
2920
+ authExpanded.value = {};
2921
+ authError.value = "";
2922
+ authLoading.value = true;
2923
+ try {
2924
+ const result = await props.api.getPermissions(row.roleId);
2925
+ authTree.value = result.resourceTree;
2926
+ authChecked.value = new Set(result.resourceIds);
2927
+ const expanded = {};
2928
+ const walk = (nodes) => {
2929
+ for (const node of nodes) {
2930
+ if (node.children.length > 0) {
2931
+ expanded[node.resourceId] = true;
2932
+ walk(node.children);
2933
+ }
2934
+ }
2935
+ };
2936
+ walk(result.resourceTree);
2937
+ authExpanded.value = expanded;
2938
+ } catch (err) {
2939
+ authError.value = err instanceof Error ? err.message : "\u52A0\u8F7D\u6388\u6743\u6811\u5931\u8D25";
2940
+ } finally {
2941
+ authLoading.value = false;
2942
+ }
2943
+ }
2944
+ function closeAuthorize() {
2945
+ if (!authSaving.value) {
2946
+ authRole.value = null;
2947
+ authError.value = "";
2948
+ }
2949
+ }
2950
+ function toggleExpand(resourceId) {
2951
+ authExpanded.value = {
2952
+ ...authExpanded.value,
2953
+ [resourceId]: !authExpanded.value[resourceId]
2954
+ };
2955
+ }
2956
+ function toggleCheck(node) {
2957
+ const next = new Set(authChecked.value);
2958
+ const ids = collectTreeResourceIds(node);
2959
+ const shouldCheck = !authChecked.value.has(node.resourceId);
2960
+ if (shouldCheck) {
2961
+ ids.forEach((id) => next.add(id));
2962
+ } else {
2963
+ ids.forEach((id) => next.delete(id));
2964
+ }
2965
+ authChecked.value = next;
2966
+ }
2967
+ async function saveAuthorize() {
2968
+ if (!authRole.value) return;
2969
+ authSaving.value = true;
2970
+ authError.value = "";
2971
+ try {
2972
+ await props.api.savePermissions(
2973
+ authRole.value.roleId,
2974
+ Array.from(authChecked.value)
2975
+ );
2976
+ authRole.value = null;
2977
+ } catch (err) {
2978
+ authError.value = err instanceof Error ? err.message : "\u4FDD\u5B58\u6388\u6743\u5931\u8D25";
2979
+ } finally {
2980
+ authSaving.value = false;
2981
+ }
2982
+ }
2983
+ function renderTreeNodes(nodes, depth = 0) {
2984
+ return nodes.map((node) => {
2985
+ const hasChildren = node.children.length > 0;
2986
+ const expanded = Boolean(authExpanded.value[node.resourceId]);
2987
+ const checked = authChecked.value.has(node.resourceId);
2988
+ const { total, checkedCount } = countCheckedDescendants(
2989
+ node,
2990
+ authChecked.value
2991
+ );
2992
+ const indeterminate = hasChildren && checkedCount > 0 && checkedCount < total && !checked;
2993
+ return (0, import_vue5.h)("div", { key: node.resourceId }, [
2994
+ (0, import_vue5.h)(
2995
+ "div",
2996
+ {
2997
+ style: {
2998
+ ...s3.treeRow,
2999
+ paddingLeft: `${12 + depth * 20}px`
3000
+ }
3001
+ },
3002
+ [
3003
+ hasChildren ? (0, import_vue5.h)(
3004
+ "button",
3005
+ {
3006
+ type: "button",
3007
+ style: s3.treeToggle,
3008
+ "aria-label": expanded ? "\u6536\u8D77" : "\u5C55\u5F00",
3009
+ onClick: () => toggleExpand(node.resourceId)
3010
+ },
3011
+ expanded ? "\u25BC" : "\u25B6"
3012
+ ) : (0, import_vue5.h)("span", { style: s3.treeSpacer }),
3013
+ (0, import_vue5.h)("label", { style: s3.treeLabel }, [
3014
+ (0, import_vue5.h)("input", {
3015
+ type: "checkbox",
3016
+ style: s3.checkbox,
3017
+ checked,
3018
+ onChange: () => toggleCheck(node),
3019
+ onVnodeMounted: (vnode) => {
3020
+ const el = vnode.el;
3021
+ if (el) el.indeterminate = indeterminate;
3022
+ },
3023
+ onVnodeUpdated: (vnode) => {
3024
+ const el = vnode.el;
3025
+ if (el) el.indeterminate = indeterminate;
3026
+ }
3027
+ }),
3028
+ (0, import_vue5.h)("span", node.name || node.resourceId)
3029
+ ])
3030
+ ]
3031
+ ),
3032
+ hasChildren && expanded ? (0, import_vue5.h)("div", renderTreeNodes(node.children, depth + 1)) : null
3033
+ ]);
3034
+ });
3035
+ }
3036
+ (0, import_vue5.onMounted)(() => {
3037
+ void loadList("current", "");
3038
+ });
3039
+ (0, import_vue5.watch)(
3040
+ () => [props.api, pageSize.value, keyword.value],
3041
+ () => {
3042
+ pageToken.value = "";
3043
+ void loadList("current", "");
3044
+ }
3045
+ );
3046
+ return () => (0, import_vue5.h)("div", { style: s3.root }, [
3047
+ (0, import_vue5.h)("div", { style: s3.toolbar }, [
3048
+ (0, import_vue5.h)("h2", { style: s3.title }, props.title),
3049
+ (0, import_vue5.h)("div", { style: s3.toolbarRight }, [
3050
+ slots.toolbarExtra?.(),
3051
+ (0, import_vue5.h)(
3052
+ "button",
3053
+ { type: "button", style: s3.primaryBtn, onClick: openCreate },
3054
+ "\u65B0\u589E"
3055
+ )
3056
+ ])
3057
+ ]),
3058
+ (0, import_vue5.h)("div", { style: s3.searchBar }, [
3059
+ (0, import_vue5.h)("input", {
3060
+ style: { ...s3.input, maxWidth: "280px" },
3061
+ value: keywordInput.value,
3062
+ placeholder: "\u641C\u7D22\u89D2\u8272\u540D\u79F0 / \u63CF\u8FF0",
3063
+ onInput: (e) => {
3064
+ keywordInput.value = e.target.value;
3065
+ },
3066
+ onKeydown: (e) => {
3067
+ if (e.key === "Enter") handleSearch();
3068
+ }
3069
+ }),
3070
+ (0, import_vue5.h)(
3071
+ "button",
3072
+ { type: "button", style: s3.secondaryBtn, onClick: handleSearch },
3073
+ "\u67E5\u8BE2"
3074
+ ),
3075
+ (0, import_vue5.h)(
3076
+ "button",
3077
+ { type: "button", style: s3.secondaryBtn, onClick: handleReset },
3078
+ "\u91CD\u7F6E"
3079
+ )
3080
+ ]),
3081
+ error.value ? (0, import_vue5.h)("div", { style: s3.error }, error.value) : null,
3082
+ (0, import_vue5.h)("div", { style: s3.tableWrap }, [
3083
+ (0, import_vue5.h)("table", { style: s3.table }, [
3084
+ (0, import_vue5.h)("thead", [
3085
+ (0, import_vue5.h)("tr", [
3086
+ (0, import_vue5.h)("th", { style: s3.th }, "\u89D2\u8272\u540D\u79F0"),
3087
+ (0, import_vue5.h)("th", { style: s3.th }, "\u89D2\u8272\u63CF\u8FF0"),
3088
+ (0, import_vue5.h)("th", { style: { ...s3.th, width: "200px" } }, "\u64CD\u4F5C")
3089
+ ])
3090
+ ]),
3091
+ (0, import_vue5.h)(
3092
+ "tbody",
3093
+ loading.value ? [
3094
+ (0, import_vue5.h)("tr", [
3095
+ (0, import_vue5.h)("td", { colspan: 3, style: s3.empty }, "\u52A0\u8F7D\u4E2D\u2026")
3096
+ ])
3097
+ ] : records.value.length === 0 ? [
3098
+ (0, import_vue5.h)("tr", [
3099
+ (0, import_vue5.h)("td", { colspan: 3, style: s3.empty }, "\u6682\u65E0\u6570\u636E")
3100
+ ])
3101
+ ] : records.value.map(
3102
+ (row) => (0, import_vue5.h)("tr", { key: row.roleId }, [
3103
+ (0, import_vue5.h)("td", { style: s3.td }, row.name),
3104
+ (0, import_vue5.h)("td", { style: s3.td }, row.description || "\u2014"),
3105
+ (0, import_vue5.h)("td", { style: s3.td }, [
3106
+ (0, import_vue5.h)(
3107
+ "button",
3108
+ {
3109
+ type: "button",
3110
+ style: s3.linkBtn,
3111
+ onClick: () => openEdit(row)
3112
+ },
3113
+ "\u7F16\u8F91"
3114
+ ),
3115
+ (0, import_vue5.h)(
3116
+ "button",
3117
+ {
3118
+ type: "button",
3119
+ style: s3.linkBtn,
3120
+ onClick: () => void openAuthorize(row)
3121
+ },
3122
+ "\u6388\u6743"
3123
+ ),
3124
+ (0, import_vue5.h)(
3125
+ "button",
3126
+ {
3127
+ type: "button",
3128
+ style: { ...s3.linkBtn, color: "#d92d20" },
3129
+ onClick: () => askDelete(row)
3130
+ },
3131
+ "\u5220\u9664"
3132
+ )
3133
+ ])
3134
+ ])
3135
+ )
3136
+ )
3137
+ ])
3138
+ ]),
3139
+ (0, import_vue5.h)("div", { style: s3.pagination }, [
3140
+ (0, import_vue5.h)("label", { style: s3.pageSize }, [
3141
+ "\u6BCF\u9875",
3142
+ (0, import_vue5.h)(
3143
+ "select",
3144
+ {
3145
+ style: s3.select,
3146
+ value: pageSize.value,
3147
+ onChange: (e) => {
3148
+ pageSize.value = e.target.value;
3149
+ }
3150
+ },
3151
+ PAGE_SIZE_OPTIONS3.map(
3152
+ (size) => (0, import_vue5.h)("option", { key: size, value: size }, size)
3153
+ )
3154
+ )
3155
+ ]),
3156
+ (0, import_vue5.h)("div", { style: s3.pageBtns }, [
3157
+ (0, import_vue5.h)(
3158
+ "button",
3159
+ {
3160
+ type: "button",
3161
+ style: s3.secondaryBtn,
3162
+ disabled: !hasPreviousPage.value || loading.value,
3163
+ onClick: () => void loadList("previous")
3164
+ },
3165
+ "\u4E0A\u4E00\u9875"
3166
+ ),
3167
+ (0, import_vue5.h)(
3168
+ "button",
3169
+ {
3170
+ type: "button",
3171
+ style: s3.secondaryBtn,
3172
+ disabled: !hasNextPage.value || loading.value,
3173
+ onClick: () => void loadList("next")
3174
+ },
3175
+ "\u4E0B\u4E00\u9875"
3176
+ )
3177
+ ])
3178
+ ]),
3179
+ dialogOpen.value ? (0, import_vue5.h)("div", { style: s3.mask, onClick: closeDialog }, [
3180
+ (0, import_vue5.h)(
3181
+ "div",
3182
+ {
3183
+ style: s3.dialog,
3184
+ role: "dialog",
3185
+ "aria-modal": "true",
3186
+ onClick: (e) => e.stopPropagation()
3187
+ },
3188
+ [
3189
+ (0, import_vue5.h)("div", { style: s3.dialogHeader }, [
3190
+ (0, import_vue5.h)(
3191
+ "h3",
3192
+ { style: s3.dialogTitle },
3193
+ editing.value ? "\u7F16\u8F91\u89D2\u8272" : "\u65B0\u589E\u89D2\u8272"
3194
+ ),
3195
+ (0, import_vue5.h)(
3196
+ "button",
3197
+ {
3198
+ type: "button",
3199
+ style: s3.iconBtn,
3200
+ "aria-label": "\u5173\u95ED",
3201
+ onClick: closeDialog
3202
+ },
3203
+ "\xD7"
3204
+ )
3205
+ ]),
3206
+ (0, import_vue5.h)(
3207
+ "form",
3208
+ {
3209
+ style: s3.form,
3210
+ onSubmit: (e) => void handleSubmit(e)
3211
+ },
3212
+ [
3213
+ (0, import_vue5.h)("label", { style: s3.field }, [
3214
+ (0, import_vue5.h)("span", { style: s3.label }, "\u89D2\u8272\u540D\u79F0"),
3215
+ (0, import_vue5.h)("input", {
3216
+ style: s3.input,
3217
+ value: form.name,
3218
+ placeholder: "\u8BF7\u8F93\u5165\u89D2\u8272\u540D\u79F0",
3219
+ required: true,
3220
+ onInput: (e) => {
3221
+ form.name = e.target.value;
3222
+ }
3223
+ })
3224
+ ]),
3225
+ (0, import_vue5.h)("label", { style: s3.field }, [
3226
+ (0, import_vue5.h)("span", { style: s3.label }, "\u89D2\u8272\u63CF\u8FF0"),
3227
+ (0, import_vue5.h)("textarea", {
3228
+ style: {
3229
+ ...s3.input,
3230
+ minHeight: "88px",
3231
+ resize: "vertical"
3232
+ },
3233
+ value: form.description,
3234
+ placeholder: "\u8BF7\u8F93\u5165\u89D2\u8272\u63CF\u8FF0",
3235
+ onInput: (e) => {
3236
+ form.description = e.target.value;
3237
+ }
3238
+ })
3239
+ ]),
3240
+ (0, import_vue5.h)("div", { style: s3.dialogFooter }, [
3241
+ (0, import_vue5.h)(
3242
+ "button",
3243
+ {
3244
+ type: "button",
3245
+ style: s3.secondaryBtn,
3246
+ onClick: closeDialog
3247
+ },
3248
+ "\u53D6\u6D88"
3249
+ ),
3250
+ (0, import_vue5.h)(
3251
+ "button",
3252
+ {
3253
+ type: "submit",
3254
+ style: s3.primaryBtn,
3255
+ disabled: saving.value
3256
+ },
3257
+ saving.value ? "\u4FDD\u5B58\u4E2D\u2026" : "\u4FDD\u5B58"
3258
+ )
3259
+ ])
3260
+ ]
3261
+ )
3262
+ ]
3263
+ )
3264
+ ]) : null,
3265
+ deletingRow.value ? (0, import_vue5.h)("div", { style: s3.mask, onClick: closeDeleteDialog }, [
3266
+ (0, import_vue5.h)(
3267
+ "div",
3268
+ {
3269
+ style: { ...s3.dialog, maxWidth: "420px" },
3270
+ role: "dialog",
3271
+ "aria-modal": "true",
3272
+ onClick: (e) => e.stopPropagation()
3273
+ },
3274
+ [
3275
+ (0, import_vue5.h)("div", { style: s3.dialogHeader }, [
3276
+ (0, import_vue5.h)("h3", { style: s3.dialogTitle }, "\u786E\u8BA4\u5220\u9664"),
3277
+ (0, import_vue5.h)(
3278
+ "button",
3279
+ {
3280
+ type: "button",
3281
+ style: s3.iconBtn,
3282
+ "aria-label": "\u5173\u95ED",
3283
+ onClick: closeDeleteDialog
3284
+ },
3285
+ "\xD7"
3286
+ )
3287
+ ]),
3288
+ (0, import_vue5.h)("div", { style: s3.confirmBody }, [
3289
+ (0, import_vue5.h)("p", { style: s3.confirmText }, [
3290
+ "\u786E\u8BA4\u5220\u9664\u89D2\u8272\u300C",
3291
+ (0, import_vue5.h)("strong", deletingRow.value.name),
3292
+ "\u300D\u5417\uFF1F\u5220\u9664\u540E\u4E0D\u53EF\u6062\u590D\u3002"
3293
+ ]),
3294
+ (0, import_vue5.h)("div", { style: s3.dialogFooter }, [
3295
+ (0, import_vue5.h)(
3296
+ "button",
3297
+ {
3298
+ type: "button",
3299
+ style: s3.secondaryBtn,
3300
+ disabled: deleting.value,
3301
+ onClick: closeDeleteDialog
3302
+ },
3303
+ "\u53D6\u6D88"
3304
+ ),
3305
+ (0, import_vue5.h)(
3306
+ "button",
3307
+ {
3308
+ type: "button",
3309
+ style: s3.dangerBtn,
3310
+ disabled: deleting.value,
3311
+ onClick: () => void confirmDelete()
3312
+ },
3313
+ deleting.value ? "\u5220\u9664\u4E2D\u2026" : "\u786E\u8BA4\u5220\u9664"
3314
+ )
3315
+ ])
3316
+ ])
3317
+ ]
3318
+ )
3319
+ ]) : null,
3320
+ authRole.value ? (0, import_vue5.h)("div", { style: s3.mask, onClick: closeAuthorize }, [
3321
+ (0, import_vue5.h)(
3322
+ "div",
3323
+ {
3324
+ style: { ...s3.dialog, maxWidth: "560px" },
3325
+ role: "dialog",
3326
+ "aria-modal": "true",
3327
+ onClick: (e) => e.stopPropagation()
3328
+ },
3329
+ [
3330
+ (0, import_vue5.h)("div", { style: s3.dialogHeader }, [
3331
+ (0, import_vue5.h)(
3332
+ "h3",
3333
+ { style: s3.dialogTitle },
3334
+ `\u89D2\u8272\u6388\u6743 \u2014 ${authRole.value.name}`
3335
+ ),
3336
+ (0, import_vue5.h)(
3337
+ "button",
3338
+ {
3339
+ type: "button",
3340
+ style: s3.iconBtn,
3341
+ "aria-label": "\u5173\u95ED",
3342
+ onClick: closeAuthorize
3343
+ },
3344
+ "\xD7"
3345
+ )
3346
+ ]),
3347
+ (0, import_vue5.h)("div", { style: s3.authBody }, [
3348
+ authError.value ? (0, import_vue5.h)("div", { style: s3.error }, authError.value) : null,
3349
+ authLoading.value ? (0, import_vue5.h)("div", { style: s3.empty }, "\u52A0\u8F7D\u4E2D\u2026") : authTree.value.length === 0 ? (0, import_vue5.h)("div", { style: s3.empty }, "\u6682\u65E0\u53EF\u6388\u6743\u8D44\u6E90") : (0, import_vue5.h)(
3350
+ "div",
3351
+ { style: s3.treePanel },
3352
+ renderTreeNodes(authTree.value)
3353
+ ),
3354
+ (0, import_vue5.h)("div", { style: s3.dialogFooter }, [
3355
+ (0, import_vue5.h)(
3356
+ "button",
3357
+ {
3358
+ type: "button",
3359
+ style: s3.secondaryBtn,
3360
+ disabled: authSaving.value,
3361
+ onClick: closeAuthorize
3362
+ },
3363
+ "\u53D6\u6D88"
3364
+ ),
3365
+ (0, import_vue5.h)(
3366
+ "button",
3367
+ {
3368
+ type: "button",
3369
+ style: s3.primaryBtn,
3370
+ disabled: authLoading.value || authSaving.value,
3371
+ onClick: () => void saveAuthorize()
3372
+ },
3373
+ authSaving.value ? "\u4FDD\u5B58\u4E2D\u2026" : "\u4FDD\u5B58"
3374
+ )
3375
+ ])
3376
+ ])
3377
+ ]
3378
+ )
3379
+ ]) : null
3380
+ ]);
3381
+ }
3382
+ });
3383
+
2398
3384
  // src/vue/SystemAdmin.ts
2399
- var import_vue5 = require("vue");
3385
+ var import_vue6 = require("vue");
2400
3386
 
2401
3387
  // src/admin/menu.ts
2402
3388
  var SYSTEM_ADMIN_MENU = {
@@ -2404,13 +3390,14 @@ var SYSTEM_ADMIN_MENU = {
2404
3390
  label: "\u7CFB\u7EDF\u7BA1\u7406",
2405
3391
  children: [
2406
3392
  { key: "menu", label: "\u83DC\u5355\u7BA1\u7406" },
2407
- { key: "resource", label: "\u6743\u9650\u70B9\u7BA1\u7406" }
3393
+ { key: "resource", label: "\u6743\u9650\u70B9\u7BA1\u7406" },
3394
+ { key: "role", label: "\u89D2\u8272\u7BA1\u7406" }
2408
3395
  ]
2409
3396
  };
2410
3397
  var SYSTEM_ADMIN_DEFAULT_KEY = "menu";
2411
3398
 
2412
3399
  // src/vue/SystemAdmin.ts
2413
- var s3 = {
3400
+ var s4 = {
2414
3401
  root: {
2415
3402
  display: "flex",
2416
3403
  minHeight: "560px",
@@ -2484,7 +3471,7 @@ var s3 = {
2484
3471
  overflow: "auto"
2485
3472
  }
2486
3473
  };
2487
- var SystemAdmin = (0, import_vue5.defineComponent)({
3474
+ var SystemAdmin = (0, import_vue6.defineComponent)({
2488
3475
  name: "SystemAdmin",
2489
3476
  props: {
2490
3477
  menuApi: {
@@ -2495,6 +3482,10 @@ var SystemAdmin = (0, import_vue5.defineComponent)({
2495
3482
  type: Object,
2496
3483
  required: true
2497
3484
  },
3485
+ roleApi: {
3486
+ type: Object,
3487
+ required: true
3488
+ },
2498
3489
  defaultActiveKey: {
2499
3490
  type: String,
2500
3491
  default: SYSTEM_ADMIN_DEFAULT_KEY
@@ -2513,17 +3504,17 @@ var SystemAdmin = (0, import_vue5.defineComponent)({
2513
3504
  activeKeyChange: (_key) => true
2514
3505
  },
2515
3506
  setup(props, { emit, slots }) {
2516
- const innerKey = (0, import_vue5.ref)(props.defaultActiveKey);
2517
- (0, import_vue5.watch)(
3507
+ const innerKey = (0, import_vue6.ref)(props.defaultActiveKey);
3508
+ (0, import_vue6.watch)(
2518
3509
  () => props.defaultActiveKey,
2519
3510
  (value) => {
2520
3511
  if (props.activeKey === void 0) innerKey.value = value;
2521
3512
  }
2522
3513
  );
2523
- const activeKey = (0, import_vue5.computed)(
3514
+ const activeKey = (0, import_vue6.computed)(
2524
3515
  () => props.activeKey ?? innerKey.value
2525
3516
  );
2526
- const activeLabel = (0, import_vue5.computed)(
3517
+ const activeLabel = (0, import_vue6.computed)(
2527
3518
  () => SYSTEM_ADMIN_MENU.children.find((item) => item.key === activeKey.value)?.label ?? ""
2528
3519
  );
2529
3520
  function setActiveKey(key) {
@@ -2531,22 +3522,22 @@ var SystemAdmin = (0, import_vue5.defineComponent)({
2531
3522
  emit("update:activeKey", key);
2532
3523
  emit("activeKeyChange", key);
2533
3524
  }
2534
- return () => (0, import_vue5.h)("div", { style: s3.root }, [
2535
- (0, import_vue5.h)("aside", { style: s3.sidebar }, [
2536
- (0, import_vue5.h)("div", { style: s3.sidebarTitle }, props.title),
2537
- (0, import_vue5.h)(
3525
+ return () => (0, import_vue6.h)("div", { style: s4.root }, [
3526
+ (0, import_vue6.h)("aside", { style: s4.sidebar }, [
3527
+ (0, import_vue6.h)("div", { style: s4.sidebarTitle }, props.title),
3528
+ (0, import_vue6.h)(
2538
3529
  "nav",
2539
- { style: s3.nav },
3530
+ { style: s4.nav },
2540
3531
  SYSTEM_ADMIN_MENU.children.map((item) => {
2541
3532
  const active = item.key === activeKey.value;
2542
- return (0, import_vue5.h)(
3533
+ return (0, import_vue6.h)(
2543
3534
  "button",
2544
3535
  {
2545
3536
  key: item.key,
2546
3537
  type: "button",
2547
3538
  style: {
2548
- ...s3.navItem,
2549
- ...active ? s3.navItemActive : {}
3539
+ ...s4.navItem,
3540
+ ...active ? s4.navItemActive : {}
2550
3541
  },
2551
3542
  onClick: () => setActiveKey(item.key)
2552
3543
  },
@@ -2555,20 +3546,20 @@ var SystemAdmin = (0, import_vue5.defineComponent)({
2555
3546
  })
2556
3547
  )
2557
3548
  ]),
2558
- (0, import_vue5.h)("main", { style: s3.content }, [
2559
- (0, import_vue5.h)("div", { style: s3.contentHeader }, [
2560
- (0, import_vue5.h)("div", { style: s3.breadcrumb }, [
2561
- (0, import_vue5.h)("span", { style: s3.breadcrumbParent }, props.title),
2562
- (0, import_vue5.h)("span", { style: s3.breadcrumbSep }, "/"),
2563
- (0, import_vue5.h)("span", { style: s3.breadcrumbCurrent }, activeLabel.value)
3549
+ (0, import_vue6.h)("main", { style: s4.content }, [
3550
+ (0, import_vue6.h)("div", { style: s4.contentHeader }, [
3551
+ (0, import_vue6.h)("div", { style: s4.breadcrumb }, [
3552
+ (0, import_vue6.h)("span", { style: s4.breadcrumbParent }, props.title),
3553
+ (0, import_vue6.h)("span", { style: s4.breadcrumbSep }, "/"),
3554
+ (0, import_vue6.h)("span", { style: s4.breadcrumbCurrent }, activeLabel.value)
2564
3555
  ]),
2565
3556
  slots.toolbarExtra?.()
2566
3557
  ]),
2567
- (0, import_vue5.h)("div", { style: s3.panel }, [
2568
- activeKey.value === "menu" ? (0, import_vue5.h)(MenuManager, { api: props.menuApi, title: "\u83DC\u5355\u7BA1\u7406" }) : (0, import_vue5.h)(ResourceManager, {
3558
+ (0, import_vue6.h)("div", { style: s4.panel }, [
3559
+ activeKey.value === "menu" ? (0, import_vue6.h)(MenuManager, { api: props.menuApi, title: "\u83DC\u5355\u7BA1\u7406" }) : activeKey.value === "resource" ? (0, import_vue6.h)(ResourceManager, {
2569
3560
  api: props.resourceApi,
2570
3561
  title: "\u6743\u9650\u70B9\u7BA1\u7406"
2571
- })
3562
+ }) : (0, import_vue6.h)(RoleManager, { api: props.roleApi, title: "\u89D2\u8272\u7BA1\u7406" })
2572
3563
  ])
2573
3564
  ])
2574
3565
  ]);
@@ -2597,19 +3588,25 @@ var SystemAdmin = (0, import_vue5.defineComponent)({
2597
3588
  ROOT_MENU_DEPTH,
2598
3589
  ROOT_PARENT_ID,
2599
3590
  ResourceManager,
3591
+ RoleManager,
2600
3592
  SYSTEM_ADMIN_DEFAULT_KEY,
2601
3593
  SYSTEM_ADMIN_MENU,
2602
3594
  SystemAdmin,
2603
3595
  appendQueryParam,
2604
3596
  buildCreateBody,
2605
3597
  buildCreateMenuBody,
3598
+ buildCreateRoleBody,
3599
+ buildSavePermissionsBody,
2606
3600
  buildUpdateBody,
2607
3601
  buildUpdateMenuBody,
3602
+ buildUpdateRoleBody,
3603
+ collectTreeResourceIds,
2608
3604
  createAuthorizationResourceApi,
2609
3605
  createDefaultResourceRequest,
2610
3606
  createMenuResourceApi,
2611
3607
  createPermissionPlugin,
2612
3608
  createPermissionStore,
3609
+ createSystemRoleApi,
2613
3610
  createVPermission,
2614
3611
  extractPagination,
2615
3612
  extractRecords,
@@ -2618,6 +3615,9 @@ var SystemAdmin = (0, import_vue5.defineComponent)({
2618
3615
  isMenuLeaf,
2619
3616
  mapAuthorizationResource,
2620
3617
  mapMenuResource,
3618
+ mapPermissionTreeNode,
3619
+ mapRolePermissions,
3620
+ mapSystemRole,
2621
3621
  resolveMenuDepth,
2622
3622
  snowyflake,
2623
3623
  useHasPermission,