com-angel-authorization 1.0.11 → 1.0.15

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