com-angel-authorization 1.0.16 → 1.0.18

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.
@@ -45,37 +45,50 @@ __export(vue_exports, {
45
45
  SYSTEM_ADMIN_DEFAULT_KEY: () => SYSTEM_ADMIN_DEFAULT_KEY,
46
46
  SYSTEM_ADMIN_MENU: () => SYSTEM_ADMIN_MENU,
47
47
  SystemAdmin: () => SystemAdmin,
48
+ UserManager: () => UserManager,
48
49
  appendQueryParam: () => appendQueryParam,
49
50
  buildCreateBody: () => buildCreateBody,
50
51
  buildCreateMenuBody: () => buildCreateMenuBody,
51
52
  buildCreateRoleBody: () => buildCreateRoleBody,
53
+ buildCreateUserBody: () => buildCreateUserBody,
54
+ buildPermissionTreeIndex: () => buildPermissionTreeIndex,
52
55
  buildSavePermissionsBody: () => buildSavePermissionsBody,
53
56
  buildUpdateBody: () => buildUpdateBody,
54
57
  buildUpdateMenuBody: () => buildUpdateMenuBody,
55
58
  buildUpdateRoleBody: () => buildUpdateRoleBody,
59
+ buildUpdateUserBody: () => buildUpdateUserBody,
56
60
  collectTreeResourceIds: () => collectTreeResourceIds,
61
+ countCheckedDescendants: () => countCheckedDescendants,
57
62
  createAuthorizationResourceApi: () => createAuthorizationResourceApi,
58
63
  createDefaultResourceRequest: () => createDefaultResourceRequest,
59
64
  createMenuResourceApi: () => createMenuResourceApi,
60
65
  createPermissionPlugin: () => createPermissionPlugin,
61
66
  createPermissionStore: () => createPermissionStore,
62
67
  createSystemRoleApi: () => createSystemRoleApi,
68
+ createSystemUserApi: () => createSystemUserApi,
63
69
  createVPermission: () => createVPermission,
64
70
  extractPagination: () => extractPagination,
65
71
  extractRecords: () => extractRecords,
66
72
  getAppClientId: () => getAppClientId,
67
73
  getDeviceWorkerId: () => getDeviceWorkerId,
74
+ hasCheckedDescendant: () => hasCheckedDescendant,
68
75
  isMenuLeaf: () => isMenuLeaf,
76
+ isPermissionNodeIndeterminate: () => isPermissionNodeIndeterminate,
69
77
  mapAuthorizationResource: () => mapAuthorizationResource,
70
78
  mapMenuResource: () => mapMenuResource,
71
79
  mapPermissionTreeNode: () => mapPermissionTreeNode,
72
80
  mapRolePermissions: () => mapRolePermissions,
81
+ mapSystemGroupOption: () => mapSystemGroupOption,
73
82
  mapSystemRole: () => mapSystemRole,
83
+ mapSystemRoleOption: () => mapSystemRoleOption,
84
+ mapSystemUser: () => mapSystemUser,
74
85
  resolveMenuDepth: () => resolveMenuDepth,
75
86
  snowyflake: () => snowyflake,
87
+ togglePermissionCheck: () => togglePermissionCheck,
76
88
  useHasPermission: () => useHasPermission,
77
89
  useHasRole: () => useHasRole,
78
- usePermission: () => usePermission
90
+ usePermission: () => usePermission,
91
+ validateUsername: () => validateUsername
79
92
  });
80
93
  module.exports = __toCommonJS(vue_exports);
81
94
 
@@ -567,7 +580,7 @@ function toStringArray(value) {
567
580
  }).filter(Boolean);
568
581
  }
569
582
  if (typeof value === "string" && value.trim()) {
570
- return value.split(",").map((s5) => s5.trim()).filter(Boolean);
583
+ return value.split(",").map((s6) => s6.trim()).filter(Boolean);
571
584
  }
572
585
  return [];
573
586
  }
@@ -2447,6 +2460,72 @@ function mapRolePermissions(payload) {
2447
2460
  function collectTreeResourceIds(node) {
2448
2461
  return [node.resourceId, ...node.children.flatMap(collectTreeResourceIds)];
2449
2462
  }
2463
+ function buildPermissionTreeIndex(tree) {
2464
+ const parentMap = /* @__PURE__ */ new Map();
2465
+ const nodeMap = /* @__PURE__ */ new Map();
2466
+ const walk = (nodes, parentId) => {
2467
+ for (const node of nodes) {
2468
+ parentMap.set(node.resourceId, parentId);
2469
+ nodeMap.set(node.resourceId, node);
2470
+ if (node.children.length > 0) {
2471
+ walk(node.children, node.resourceId);
2472
+ }
2473
+ }
2474
+ };
2475
+ walk(tree, null);
2476
+ return { parentMap, nodeMap };
2477
+ }
2478
+ function togglePermissionCheck(tree, checked, node) {
2479
+ const next = new Set(checked);
2480
+ const ids = collectTreeResourceIds(node);
2481
+ const shouldCheck = !checked.has(node.resourceId);
2482
+ if (shouldCheck) {
2483
+ ids.forEach((id) => next.add(id));
2484
+ } else {
2485
+ ids.forEach((id) => next.delete(id));
2486
+ }
2487
+ const { parentMap, nodeMap } = buildPermissionTreeIndex(tree);
2488
+ let parentId = parentMap.get(node.resourceId) ?? null;
2489
+ while (parentId) {
2490
+ const parent = nodeMap.get(parentId);
2491
+ if (!parent) break;
2492
+ const allChildrenChecked = parent.children.every(
2493
+ (child) => next.has(child.resourceId)
2494
+ );
2495
+ if (allChildrenChecked && parent.children.length > 0) {
2496
+ next.add(parentId);
2497
+ } else {
2498
+ next.delete(parentId);
2499
+ }
2500
+ parentId = parentMap.get(parentId) ?? null;
2501
+ }
2502
+ return next;
2503
+ }
2504
+ function countCheckedDescendants(node, checked) {
2505
+ let total = 0;
2506
+ let checkedCount = 0;
2507
+ const walk = (n) => {
2508
+ for (const child of n.children) {
2509
+ total += 1;
2510
+ if (checked.has(child.resourceId)) checkedCount += 1;
2511
+ walk(child);
2512
+ }
2513
+ };
2514
+ walk(node);
2515
+ return { total, checkedCount };
2516
+ }
2517
+ function hasCheckedDescendant(node, checked) {
2518
+ for (const child of node.children) {
2519
+ if (checked.has(child.resourceId) || hasCheckedDescendant(child, checked)) {
2520
+ return true;
2521
+ }
2522
+ }
2523
+ return false;
2524
+ }
2525
+ function isPermissionNodeIndeterminate(node, checked) {
2526
+ if (checked.has(node.resourceId) || node.children.length === 0) return false;
2527
+ return hasCheckedDescendant(node, checked);
2528
+ }
2450
2529
  function buildListUrl2(params) {
2451
2530
  const parts = [];
2452
2531
  appendQueryParam(parts, "keyword", params?.keyword ?? "");
@@ -2536,19 +2615,6 @@ function emptyForm3() {
2536
2615
  description: ""
2537
2616
  };
2538
2617
  }
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
2618
  var s3 = {
2553
2619
  root: {
2554
2620
  display: "flex",
@@ -2954,15 +3020,11 @@ var RoleManager = (0, import_vue5.defineComponent)({
2954
3020
  };
2955
3021
  }
2956
3022
  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;
3023
+ authChecked.value = togglePermissionCheck(
3024
+ authTree.value,
3025
+ authChecked.value,
3026
+ node
3027
+ );
2966
3028
  }
2967
3029
  async function saveAuthorize() {
2968
3030
  if (!authRole.value) return;
@@ -2985,11 +3047,10 @@ var RoleManager = (0, import_vue5.defineComponent)({
2985
3047
  const hasChildren = node.children.length > 0;
2986
3048
  const expanded = Boolean(authExpanded.value[node.resourceId]);
2987
3049
  const checked = authChecked.value.has(node.resourceId);
2988
- const { total, checkedCount } = countCheckedDescendants(
3050
+ const indeterminate = isPermissionNodeIndeterminate(
2989
3051
  node,
2990
3052
  authChecked.value
2991
3053
  );
2992
- const indeterminate = hasChildren && checkedCount > 0 && checkedCount < total && !checked;
2993
3054
  return (0, import_vue5.h)("div", { key: node.resourceId }, [
2994
3055
  (0, import_vue5.h)(
2995
3056
  "div",
@@ -3381,98 +3442,1140 @@ var RoleManager = (0, import_vue5.defineComponent)({
3381
3442
  }
3382
3443
  });
3383
3444
 
3384
- // src/vue/SystemAdmin.ts
3445
+ // src/vue/UserManager.ts
3385
3446
  var import_vue6 = require("vue");
3386
3447
 
3387
- // src/admin/menu.ts
3388
- var SYSTEM_ADMIN_MENU = {
3389
- key: "system",
3390
- label: "\u7CFB\u7EDF\u7BA1\u7406",
3391
- children: [
3392
- { key: "menu", label: "\u83DC\u5355\u7BA1\u7406" },
3393
- { key: "resource", label: "\u6743\u9650\u70B9\u7BA1\u7406" },
3394
- { key: "role", label: "\u89D2\u8272\u7BA1\u7406" }
3395
- ]
3396
- };
3397
- var SYSTEM_ADMIN_DEFAULT_KEY = "menu";
3448
+ // src/users/index.ts
3449
+ function asIdList(value) {
3450
+ if (!Array.isArray(value)) return [];
3451
+ return value.map((item) => {
3452
+ if (item === void 0 || item === null || item === "") return "";
3453
+ if (typeof item === "object") {
3454
+ const row = item;
3455
+ const id = row.groupId ?? row.roleId ?? row.id;
3456
+ return id === void 0 || id === null ? "" : String(id);
3457
+ }
3458
+ return String(item);
3459
+ }).filter(Boolean);
3460
+ }
3461
+ function asNameList(value) {
3462
+ if (!Array.isArray(value)) return void 0;
3463
+ const names = value.map((item) => {
3464
+ if (item === void 0 || item === null) return "";
3465
+ if (typeof item === "object") {
3466
+ return String(item.name ?? "");
3467
+ }
3468
+ return String(item);
3469
+ }).filter(Boolean);
3470
+ return names.length ? names : void 0;
3471
+ }
3472
+ function mapSystemUser(item) {
3473
+ if (!item || typeof item !== "object") return null;
3474
+ const row = item;
3475
+ const userId = row.userId ?? row.user_id ?? row.id;
3476
+ if (userId === void 0 || userId === null || userId === "") return null;
3477
+ return {
3478
+ userId: String(userId),
3479
+ username: String(row.username ?? row.account ?? ""),
3480
+ name: String(row.name ?? ""),
3481
+ groupIds: asIdList(row.groupIds ?? row.group_ids ?? row.groups),
3482
+ roleIds: asIdList(row.roleIds ?? row.role_ids ?? row.roles),
3483
+ groupNames: asNameList(row.groupNames ?? row.group_names ?? row.groups),
3484
+ roleNames: asNameList(row.roleNames ?? row.role_names ?? row.roles),
3485
+ enabled: Boolean(row.enabled ?? row.enable ?? true)
3486
+ };
3487
+ }
3488
+ function mapSystemGroupOption(item) {
3489
+ if (!item || typeof item !== "object") return null;
3490
+ const row = item;
3491
+ const groupId = row.groupId ?? row.group_id ?? row.id;
3492
+ if (groupId === void 0 || groupId === null || groupId === "") return null;
3493
+ return {
3494
+ groupId: String(groupId),
3495
+ name: String(row.name ?? "")
3496
+ };
3497
+ }
3498
+ function mapSystemRoleOption(item) {
3499
+ if (!item || typeof item !== "object") return null;
3500
+ const row = item;
3501
+ const roleId = row.roleId ?? row.role_id ?? row.id;
3502
+ if (roleId === void 0 || roleId === null || roleId === "") return null;
3503
+ return {
3504
+ roleId: String(roleId),
3505
+ name: String(row.name ?? "")
3506
+ };
3507
+ }
3508
+ function validateUsername(username) {
3509
+ const value = username.trim();
3510
+ if (value.length < 6) return "\u8D26\u53F7\u957F\u5EA6\u4E0D\u5C11\u4E8E 6 \u4E2A\u5B57\u7B26";
3511
+ if (!/[A-Za-z]/.test(value) || !/[0-9]/.test(value)) {
3512
+ return "\u8D26\u53F7\u9700\u540C\u65F6\u5305\u542B\u5B57\u6BCD\u548C\u6570\u5B57";
3513
+ }
3514
+ return null;
3515
+ }
3516
+ function buildListUrl3(params) {
3517
+ const parts = [];
3518
+ appendQueryParam(parts, "keyword", params?.keyword ?? "");
3519
+ if (params?.enabled !== void 0) {
3520
+ appendQueryParam(parts, "enabled", String(params.enabled));
3521
+ }
3522
+ appendQueryParam(parts, "page-token", params?.pagination?.pageToken ?? "");
3523
+ appendQueryParam(parts, "page-size", params?.pagination?.pageSize ?? "20");
3524
+ appendQueryParam(parts, "page-direction", params?.pagination?.pageDirection ?? "current");
3525
+ return parts.length ? `/system/users?${parts.join("&")}` : "/system/users";
3526
+ }
3527
+ function buildKeywordUrl(base, keyword) {
3528
+ const parts = [];
3529
+ appendQueryParam(parts, "keyword", keyword ?? "");
3530
+ return parts.length ? `${base}?${parts.join("&")}` : base;
3531
+ }
3532
+ function buildCreateUserBody(values) {
3533
+ return {
3534
+ username: values.username.trim(),
3535
+ name: values.name.trim(),
3536
+ password: values.password,
3537
+ groupIds: [...new Set(values.groupIds.map(String))],
3538
+ roleIds: [...new Set(values.roleIds.map(String))],
3539
+ enabled: Boolean(values.enabled)
3540
+ };
3541
+ }
3542
+ function buildUpdateUserBody(values) {
3543
+ const body = {
3544
+ username: values.username.trim(),
3545
+ name: values.name.trim(),
3546
+ groupIds: [...new Set(values.groupIds.map(String))],
3547
+ roleIds: [...new Set(values.roleIds.map(String))],
3548
+ enabled: Boolean(values.enabled)
3549
+ };
3550
+ if (values.password.trim()) {
3551
+ body.password = values.password;
3552
+ }
3553
+ return body;
3554
+ }
3555
+ function createSystemUserApi(request) {
3556
+ return {
3557
+ async list(params, signal) {
3558
+ const json = await request({
3559
+ method: "GET",
3560
+ url: buildListUrl3(params),
3561
+ signal
3562
+ });
3563
+ const records = extractRecords(json).map(mapSystemUser).filter((item) => item !== null);
3564
+ return {
3565
+ records,
3566
+ ...extractPagination(json)
3567
+ };
3568
+ },
3569
+ async create(values, signal) {
3570
+ return request({
3571
+ method: "POST",
3572
+ url: "/system/users",
3573
+ body: buildCreateUserBody(values),
3574
+ signal
3575
+ });
3576
+ },
3577
+ async update(userId, values, signal) {
3578
+ return request({
3579
+ method: "PATCH",
3580
+ url: `/system/users/${encodeURIComponent(userId)}`,
3581
+ body: buildUpdateUserBody(values),
3582
+ signal
3583
+ });
3584
+ },
3585
+ async remove(userId, signal) {
3586
+ return request({
3587
+ method: "DELETE",
3588
+ url: `/system/users/${encodeURIComponent(userId)}`,
3589
+ signal
3590
+ });
3591
+ },
3592
+ async listGroups(params, signal) {
3593
+ const json = await request({
3594
+ method: "GET",
3595
+ url: buildKeywordUrl("/system/groups", params?.keyword),
3596
+ signal
3597
+ });
3598
+ return extractRecords(json).map(mapSystemGroupOption).filter((item) => item !== null);
3599
+ },
3600
+ async listRoleOptions(params, signal) {
3601
+ const json = await request({
3602
+ method: "GET",
3603
+ url: buildKeywordUrl("/system/roles", params?.keyword),
3604
+ signal
3605
+ });
3606
+ return extractRecords(json).map(mapSystemRoleOption).filter((item) => item !== null);
3607
+ }
3608
+ };
3609
+ }
3398
3610
 
3399
- // src/vue/SystemAdmin.ts
3611
+ // src/vue/UserManager.ts
3612
+ var PAGE_SIZE_OPTIONS4 = ["10", "20", "50", "100"];
3613
+ function emptyForm4() {
3614
+ return {
3615
+ username: "",
3616
+ name: "",
3617
+ password: "",
3618
+ groupIds: [],
3619
+ roleIds: [],
3620
+ enabled: true
3621
+ };
3622
+ }
3400
3623
  var s4 = {
3401
3624
  root: {
3402
3625
  display: "flex",
3403
- minHeight: "560px",
3626
+ flexDirection: "column",
3627
+ gap: "16px",
3628
+ padding: "16px",
3629
+ color: "#101828",
3630
+ fontFamily: '"PingFang SC", "Microsoft YaHei", -apple-system, BlinkMacSystemFont, sans-serif'
3631
+ },
3632
+ toolbar: {
3633
+ display: "flex",
3634
+ alignItems: "center",
3635
+ justifyContent: "space-between",
3636
+ gap: "12px"
3637
+ },
3638
+ title: { margin: "0", fontSize: "18px", fontWeight: "600" },
3639
+ toolbarRight: { display: "flex", alignItems: "center", gap: "8px" },
3640
+ searchBar: {
3641
+ display: "flex",
3642
+ alignItems: "center",
3643
+ gap: "8px",
3644
+ flexWrap: "wrap"
3645
+ },
3646
+ error: {
3647
+ padding: "10px 12px",
3648
+ borderRadius: "8px",
3649
+ background: "#fef3f2",
3650
+ color: "#b42318",
3651
+ fontSize: "13px"
3652
+ },
3653
+ tableWrap: {
3654
+ overflow: "auto",
3404
3655
  border: "1px solid #eaecf0",
3405
- borderRadius: "12px",
3406
- overflow: "hidden",
3407
- background: "#fff",
3408
- fontFamily: '"PingFang SC", "Microsoft YaHei", -apple-system, BlinkMacSystemFont, sans-serif',
3409
- color: "#101828"
3656
+ borderRadius: "10px",
3657
+ background: "#fff"
3410
3658
  },
3411
- sidebar: {
3412
- width: "200px",
3413
- flexShrink: "0",
3414
- borderRight: "1px solid #eaecf0",
3659
+ table: { width: "100%", borderCollapse: "collapse", minWidth: "720px" },
3660
+ th: {
3661
+ textAlign: "left",
3662
+ padding: "12px 14px",
3663
+ fontSize: "13px",
3664
+ fontWeight: "600",
3665
+ color: "#475467",
3415
3666
  background: "#f9fafb",
3416
- padding: "16px 12px"
3667
+ borderBottom: "1px solid #eaecf0"
3417
3668
  },
3418
- sidebarTitle: {
3669
+ td: {
3670
+ padding: "12px 14px",
3419
3671
  fontSize: "14px",
3420
- fontWeight: "600",
3421
- color: "#344054",
3422
- padding: "4px 10px 12px"
3672
+ borderBottom: "1px solid #f2f4f7",
3673
+ verticalAlign: "middle"
3423
3674
  },
3424
- nav: {
3425
- display: "flex",
3426
- flexDirection: "column",
3427
- gap: "4px"
3675
+ empty: {
3676
+ padding: "28px",
3677
+ textAlign: "center",
3678
+ color: "#98a2b3",
3679
+ fontSize: "14px"
3428
3680
  },
3429
- navItem: {
3681
+ linkBtn: {
3430
3682
  border: "none",
3431
3683
  background: "transparent",
3432
- textAlign: "left",
3433
- padding: "10px 12px",
3434
- borderRadius: "8px",
3435
- fontSize: "14px",
3436
- color: "#475467",
3437
- cursor: "pointer"
3438
- },
3439
- navItemActive: {
3440
- background: "#e6f7f9",
3441
3684
  color: "#049BAD",
3442
- fontWeight: "600"
3685
+ cursor: "pointer",
3686
+ padding: "0 8px 0 0",
3687
+ fontSize: "13px"
3443
3688
  },
3444
- content: {
3445
- flex: "1",
3446
- minWidth: "0",
3447
- display: "flex",
3448
- flexDirection: "column",
3449
- background: "#fff"
3689
+ badge: {
3690
+ display: "inline-block",
3691
+ padding: "2px 8px",
3692
+ borderRadius: "999px",
3693
+ fontSize: "12px",
3694
+ fontWeight: "500"
3450
3695
  },
3451
- contentHeader: {
3696
+ badgeOn: { background: "#ecfdf3", color: "#027a48" },
3697
+ badgeOff: { background: "#f2f4f7", color: "#667085" },
3698
+ pagination: {
3452
3699
  display: "flex",
3453
3700
  alignItems: "center",
3454
3701
  justifyContent: "space-between",
3455
- gap: "12px",
3456
- padding: "12px 16px",
3457
- borderBottom: "1px solid #f2f4f7"
3702
+ gap: "12px"
3458
3703
  },
3459
- breadcrumb: {
3704
+ pageSize: {
3460
3705
  display: "flex",
3461
3706
  alignItems: "center",
3462
3707
  gap: "8px",
3463
- fontSize: "13px"
3708
+ fontSize: "13px",
3709
+ color: "#475467"
3464
3710
  },
3465
- breadcrumbParent: { color: "#98a2b3" },
3466
- breadcrumbSep: { color: "#d0d5dd" },
3467
- breadcrumbCurrent: { color: "#344054", fontWeight: "600" },
3468
- panel: {
3469
- flex: "1",
3470
- minHeight: "0",
3471
- overflow: "auto"
3472
- }
3473
- };
3474
- var SystemAdmin = (0, import_vue6.defineComponent)({
3475
- name: "SystemAdmin",
3711
+ pageBtns: { display: "flex", gap: "8px" },
3712
+ primaryBtn: {
3713
+ border: "none",
3714
+ background: "#049BAD",
3715
+ color: "#fff",
3716
+ borderRadius: "8px",
3717
+ padding: "8px 14px",
3718
+ cursor: "pointer",
3719
+ fontSize: "14px"
3720
+ },
3721
+ secondaryBtn: {
3722
+ border: "1px solid #d0d5dd",
3723
+ background: "#fff",
3724
+ color: "#344054",
3725
+ borderRadius: "8px",
3726
+ padding: "8px 14px",
3727
+ cursor: "pointer",
3728
+ fontSize: "14px"
3729
+ },
3730
+ dangerBtn: {
3731
+ border: "none",
3732
+ background: "#d92d20",
3733
+ color: "#fff",
3734
+ borderRadius: "8px",
3735
+ padding: "8px 14px",
3736
+ cursor: "pointer",
3737
+ fontSize: "14px"
3738
+ },
3739
+ select: {
3740
+ border: "1px solid #d0d5dd",
3741
+ borderRadius: "6px",
3742
+ padding: "4px 8px",
3743
+ fontSize: "13px",
3744
+ backgroundColor: "#ffffff",
3745
+ color: "#101828"
3746
+ },
3747
+ mask: {
3748
+ position: "fixed",
3749
+ inset: "0",
3750
+ background: "rgba(16, 24, 40, 0.45)",
3751
+ display: "flex",
3752
+ alignItems: "center",
3753
+ justifyContent: "center",
3754
+ zIndex: "1000",
3755
+ padding: "16px"
3756
+ },
3757
+ dialog: {
3758
+ width: "100%",
3759
+ maxWidth: "480px",
3760
+ background: "#fff",
3761
+ borderRadius: "12px",
3762
+ boxShadow: "0 20px 40px rgba(16,24,40,0.18)",
3763
+ maxHeight: "90vh",
3764
+ overflow: "auto"
3765
+ },
3766
+ dialogHeader: {
3767
+ display: "flex",
3768
+ alignItems: "center",
3769
+ justifyContent: "space-between",
3770
+ padding: "14px 16px",
3771
+ borderBottom: "1px solid #eaecf0",
3772
+ position: "sticky",
3773
+ top: "0",
3774
+ background: "#fff",
3775
+ zIndex: "1"
3776
+ },
3777
+ dialogTitle: { margin: "0", fontSize: "16px", fontWeight: "600" },
3778
+ iconBtn: {
3779
+ border: "none",
3780
+ background: "transparent",
3781
+ fontSize: "22px",
3782
+ lineHeight: "1",
3783
+ cursor: "pointer",
3784
+ color: "#667085"
3785
+ },
3786
+ form: {
3787
+ display: "flex",
3788
+ flexDirection: "column",
3789
+ gap: "12px",
3790
+ padding: "16px"
3791
+ },
3792
+ confirmBody: {
3793
+ display: "flex",
3794
+ flexDirection: "column",
3795
+ gap: "16px",
3796
+ padding: "16px"
3797
+ },
3798
+ confirmText: {
3799
+ margin: "0",
3800
+ fontSize: "14px",
3801
+ color: "#344054",
3802
+ lineHeight: "1.6"
3803
+ },
3804
+ field: { display: "flex", flexDirection: "column", gap: "6px" },
3805
+ fieldset: {
3806
+ border: "1px solid #eaecf0",
3807
+ borderRadius: "8px",
3808
+ margin: "0",
3809
+ padding: "10px 12px 12px"
3810
+ },
3811
+ label: { fontSize: "13px", color: "#344054", fontWeight: "500" },
3812
+ input: {
3813
+ border: "1px solid #d0d5dd",
3814
+ borderRadius: "8px",
3815
+ padding: "8px 10px",
3816
+ fontSize: "14px",
3817
+ outline: "none",
3818
+ backgroundColor: "#ffffff",
3819
+ color: "#101828",
3820
+ boxSizing: "border-box",
3821
+ width: "100%"
3822
+ },
3823
+ multiSelect: {
3824
+ display: "flex",
3825
+ flexDirection: "column",
3826
+ gap: "6px",
3827
+ maxHeight: "160px",
3828
+ overflow: "auto"
3829
+ },
3830
+ checkItem: {
3831
+ display: "flex",
3832
+ alignItems: "center",
3833
+ gap: "8px",
3834
+ fontSize: "14px",
3835
+ color: "#101828",
3836
+ cursor: "pointer"
3837
+ },
3838
+ control: {
3839
+ width: "16px",
3840
+ height: "16px",
3841
+ accentColor: "#049BAD",
3842
+ cursor: "pointer",
3843
+ colorScheme: "light",
3844
+ backgroundColor: "#ffffff"
3845
+ },
3846
+ hint: { fontSize: "13px", color: "#98a2b3", padding: "4px 0" },
3847
+ switchRow: {
3848
+ display: "flex",
3849
+ alignItems: "center",
3850
+ justifyContent: "space-between",
3851
+ gap: "12px"
3852
+ },
3853
+ switchTrack: {
3854
+ width: "44px",
3855
+ height: "24px",
3856
+ borderRadius: "999px",
3857
+ border: "none",
3858
+ padding: "2px",
3859
+ background: "#d0d5dd",
3860
+ cursor: "pointer",
3861
+ position: "relative",
3862
+ transition: "background 0.15s ease"
3863
+ },
3864
+ switchTrackOn: { background: "#049BAD" },
3865
+ switchThumb: {
3866
+ display: "block",
3867
+ width: "20px",
3868
+ height: "20px",
3869
+ borderRadius: "50%",
3870
+ background: "#fff",
3871
+ boxShadow: "0 1px 2px rgba(16,24,40,0.2)",
3872
+ transform: "translateX(0)",
3873
+ transition: "transform 0.15s ease"
3874
+ },
3875
+ switchThumbOn: { transform: "translateX(20px)" },
3876
+ dialogFooter: {
3877
+ display: "flex",
3878
+ justifyContent: "flex-end",
3879
+ gap: "8px",
3880
+ paddingTop: "4px"
3881
+ }
3882
+ };
3883
+ var UserManager = (0, import_vue6.defineComponent)({
3884
+ name: "UserManager",
3885
+ props: {
3886
+ api: {
3887
+ type: Object,
3888
+ required: true
3889
+ },
3890
+ title: {
3891
+ type: String,
3892
+ default: "\u7528\u6237\u7BA1\u7406"
3893
+ },
3894
+ pageSize: {
3895
+ type: String,
3896
+ default: "20"
3897
+ }
3898
+ },
3899
+ setup(props, { slots }) {
3900
+ const records = (0, import_vue6.ref)([]);
3901
+ const loading = (0, import_vue6.ref)(false);
3902
+ const error = (0, import_vue6.ref)("");
3903
+ const keyword = (0, import_vue6.ref)("");
3904
+ const keywordInput = (0, import_vue6.ref)("");
3905
+ const enabledFilter = (0, import_vue6.ref)("all");
3906
+ const pageSize = (0, import_vue6.ref)(props.pageSize);
3907
+ const pageToken = (0, import_vue6.ref)("");
3908
+ const hasPreviousPage = (0, import_vue6.ref)(false);
3909
+ const hasNextPage = (0, import_vue6.ref)(false);
3910
+ const dialogOpen = (0, import_vue6.ref)(false);
3911
+ const editing = (0, import_vue6.ref)(null);
3912
+ const form = (0, import_vue6.reactive)(emptyForm4());
3913
+ const formError = (0, import_vue6.ref)("");
3914
+ const saving = (0, import_vue6.ref)(false);
3915
+ const deletingRow = (0, import_vue6.ref)(null);
3916
+ const deleting = (0, import_vue6.ref)(false);
3917
+ const groups = (0, import_vue6.ref)([]);
3918
+ const roles = (0, import_vue6.ref)([]);
3919
+ const optionsLoading = (0, import_vue6.ref)(false);
3920
+ function enabledParam() {
3921
+ if (enabledFilter.value === "all") return void 0;
3922
+ return enabledFilter.value === "true";
3923
+ }
3924
+ async function loadList(direction = "current", token = pageToken.value) {
3925
+ loading.value = true;
3926
+ error.value = "";
3927
+ try {
3928
+ const result = await props.api.list({
3929
+ keyword: keyword.value,
3930
+ enabled: enabledParam(),
3931
+ pagination: {
3932
+ pageToken: token,
3933
+ pageSize: pageSize.value,
3934
+ pageDirection: direction
3935
+ }
3936
+ });
3937
+ records.value = result.records;
3938
+ pageToken.value = result.pageToken;
3939
+ hasPreviousPage.value = result.hasPreviousPage;
3940
+ hasNextPage.value = result.hasNextPage;
3941
+ } catch (err) {
3942
+ error.value = err instanceof Error ? err.message : "\u52A0\u8F7D\u5931\u8D25";
3943
+ } finally {
3944
+ loading.value = false;
3945
+ }
3946
+ }
3947
+ async function loadOptions() {
3948
+ optionsLoading.value = true;
3949
+ try {
3950
+ const [groupList, roleList] = await Promise.all([
3951
+ props.api.listGroups(),
3952
+ props.api.listRoleOptions()
3953
+ ]);
3954
+ groups.value = groupList;
3955
+ roles.value = roleList;
3956
+ } catch (err) {
3957
+ formError.value = err instanceof Error ? err.message : "\u52A0\u8F7D\u90E8\u95E8/\u89D2\u8272\u5931\u8D25";
3958
+ } finally {
3959
+ optionsLoading.value = false;
3960
+ }
3961
+ }
3962
+ function handleSearch() {
3963
+ pageToken.value = "";
3964
+ keyword.value = keywordInput.value.trim();
3965
+ }
3966
+ function handleReset() {
3967
+ keywordInput.value = "";
3968
+ keyword.value = "";
3969
+ enabledFilter.value = "all";
3970
+ pageToken.value = "";
3971
+ }
3972
+ function openCreate() {
3973
+ editing.value = null;
3974
+ Object.assign(form, emptyForm4());
3975
+ formError.value = "";
3976
+ dialogOpen.value = true;
3977
+ void loadOptions();
3978
+ }
3979
+ function openEdit(row) {
3980
+ editing.value = row;
3981
+ Object.assign(form, {
3982
+ username: row.username,
3983
+ name: row.name,
3984
+ password: "",
3985
+ groupIds: [...row.groupIds],
3986
+ roleIds: [...row.roleIds],
3987
+ enabled: row.enabled
3988
+ });
3989
+ formError.value = "";
3990
+ dialogOpen.value = true;
3991
+ void loadOptions();
3992
+ }
3993
+ function closeDialog() {
3994
+ if (!saving.value) dialogOpen.value = false;
3995
+ }
3996
+ function toggleId(field, id) {
3997
+ const exists = form[field].includes(id);
3998
+ form[field] = exists ? form[field].filter((x) => x !== id) : [...form[field], id];
3999
+ }
4000
+ async function handleSubmit(event) {
4001
+ event.preventDefault();
4002
+ const usernameError = validateUsername(form.username);
4003
+ if (usernameError) {
4004
+ formError.value = usernameError;
4005
+ return;
4006
+ }
4007
+ if (!form.name.trim()) {
4008
+ formError.value = "\u8BF7\u586B\u5199\u7528\u6237\u540D";
4009
+ return;
4010
+ }
4011
+ if (!editing.value && !form.password.trim()) {
4012
+ formError.value = "\u8BF7\u586B\u5199\u521D\u59CB\u5BC6\u7801";
4013
+ return;
4014
+ }
4015
+ saving.value = true;
4016
+ formError.value = "";
4017
+ error.value = "";
4018
+ try {
4019
+ if (editing.value) {
4020
+ await props.api.update(editing.value.userId, { ...form });
4021
+ } else {
4022
+ await props.api.create({ ...form });
4023
+ }
4024
+ dialogOpen.value = false;
4025
+ await loadList("current", "");
4026
+ } catch (err) {
4027
+ formError.value = err instanceof Error ? err.message : "\u4FDD\u5B58\u5931\u8D25";
4028
+ } finally {
4029
+ saving.value = false;
4030
+ }
4031
+ }
4032
+ function askDelete(row) {
4033
+ deletingRow.value = row;
4034
+ }
4035
+ function closeDeleteDialog() {
4036
+ if (!deleting.value) deletingRow.value = null;
4037
+ }
4038
+ async function confirmDelete() {
4039
+ if (!deletingRow.value) return;
4040
+ deleting.value = true;
4041
+ error.value = "";
4042
+ try {
4043
+ await props.api.remove(deletingRow.value.userId);
4044
+ deletingRow.value = null;
4045
+ await loadList("current", "");
4046
+ } catch (err) {
4047
+ error.value = err instanceof Error ? err.message : "\u5220\u9664\u5931\u8D25";
4048
+ } finally {
4049
+ deleting.value = false;
4050
+ }
4051
+ }
4052
+ function groupLabel(row) {
4053
+ if (row.groupNames?.length) return row.groupNames.join("\u3001");
4054
+ if (!row.groupIds.length) return "\u2014";
4055
+ const map = new Map(groups.value.map((g) => [g.groupId, g.name]));
4056
+ return row.groupIds.map((id) => map.get(id) || id).join("\u3001");
4057
+ }
4058
+ function roleLabel(row) {
4059
+ if (row.roleNames?.length) return row.roleNames.join("\u3001");
4060
+ if (!row.roleIds.length) return "\u2014";
4061
+ const map = new Map(roles.value.map((r) => [r.roleId, r.name]));
4062
+ return row.roleIds.map((id) => map.get(id) || id).join("\u3001");
4063
+ }
4064
+ (0, import_vue6.onMounted)(() => {
4065
+ void loadList("current", "");
4066
+ void (async () => {
4067
+ try {
4068
+ const [groupList, roleList] = await Promise.all([
4069
+ props.api.listGroups(),
4070
+ props.api.listRoleOptions()
4071
+ ]);
4072
+ groups.value = groupList;
4073
+ roles.value = roleList;
4074
+ } catch {
4075
+ }
4076
+ })();
4077
+ });
4078
+ (0, import_vue6.watch)(
4079
+ () => [
4080
+ props.api,
4081
+ pageSize.value,
4082
+ keyword.value,
4083
+ enabledFilter.value
4084
+ ],
4085
+ () => {
4086
+ pageToken.value = "";
4087
+ void loadList("current", "");
4088
+ }
4089
+ );
4090
+ return () => (0, import_vue6.h)("div", { style: s4.root }, [
4091
+ (0, import_vue6.h)("div", { style: s4.toolbar }, [
4092
+ (0, import_vue6.h)("h2", { style: s4.title }, props.title),
4093
+ (0, import_vue6.h)("div", { style: s4.toolbarRight }, [
4094
+ slots.toolbarExtra?.(),
4095
+ (0, import_vue6.h)(
4096
+ "button",
4097
+ { type: "button", style: s4.primaryBtn, onClick: openCreate },
4098
+ "\u65B0\u589E\u7528\u6237"
4099
+ )
4100
+ ])
4101
+ ]),
4102
+ (0, import_vue6.h)("div", { style: s4.searchBar }, [
4103
+ (0, import_vue6.h)("input", {
4104
+ style: { ...s4.input, maxWidth: "240px" },
4105
+ value: keywordInput.value,
4106
+ placeholder: "\u641C\u7D22\u8D26\u53F7 / \u7528\u6237\u540D",
4107
+ onInput: (e) => {
4108
+ keywordInput.value = e.target.value;
4109
+ },
4110
+ onKeydown: (e) => {
4111
+ if (e.key === "Enter") handleSearch();
4112
+ }
4113
+ }),
4114
+ (0, import_vue6.h)(
4115
+ "select",
4116
+ {
4117
+ style: s4.select,
4118
+ value: enabledFilter.value,
4119
+ onChange: (e) => {
4120
+ pageToken.value = "";
4121
+ enabledFilter.value = e.target.value;
4122
+ }
4123
+ },
4124
+ [
4125
+ (0, import_vue6.h)("option", { value: "all" }, "\u5168\u90E8\u72B6\u6001"),
4126
+ (0, import_vue6.h)("option", { value: "true" }, "\u5DF2\u542F\u7528"),
4127
+ (0, import_vue6.h)("option", { value: "false" }, "\u5DF2\u7981\u7528")
4128
+ ]
4129
+ ),
4130
+ (0, import_vue6.h)(
4131
+ "button",
4132
+ { type: "button", style: s4.secondaryBtn, onClick: handleSearch },
4133
+ "\u67E5\u8BE2"
4134
+ ),
4135
+ (0, import_vue6.h)(
4136
+ "button",
4137
+ { type: "button", style: s4.secondaryBtn, onClick: handleReset },
4138
+ "\u91CD\u7F6E"
4139
+ )
4140
+ ]),
4141
+ error.value ? (0, import_vue6.h)("div", { style: s4.error }, error.value) : null,
4142
+ (0, import_vue6.h)("div", { style: s4.tableWrap }, [
4143
+ (0, import_vue6.h)("table", { style: s4.table }, [
4144
+ (0, import_vue6.h)("thead", [
4145
+ (0, import_vue6.h)("tr", [
4146
+ (0, import_vue6.h)("th", { style: s4.th }, "\u8D26\u53F7"),
4147
+ (0, import_vue6.h)("th", { style: s4.th }, "\u7528\u6237\u540D"),
4148
+ (0, import_vue6.h)("th", { style: s4.th }, "\u5F52\u5C5E\u90E8\u95E8"),
4149
+ (0, import_vue6.h)("th", { style: s4.th }, "\u7528\u6237\u89D2\u8272"),
4150
+ (0, import_vue6.h)("th", { style: { ...s4.th, width: "90px" } }, "\u72B6\u6001"),
4151
+ (0, import_vue6.h)("th", { style: { ...s4.th, width: "140px" } }, "\u64CD\u4F5C")
4152
+ ])
4153
+ ]),
4154
+ (0, import_vue6.h)(
4155
+ "tbody",
4156
+ loading.value ? [
4157
+ (0, import_vue6.h)("tr", [
4158
+ (0, import_vue6.h)("td", { colspan: 6, style: s4.empty }, "\u52A0\u8F7D\u4E2D\u2026")
4159
+ ])
4160
+ ] : records.value.length === 0 ? [
4161
+ (0, import_vue6.h)("tr", [
4162
+ (0, import_vue6.h)("td", { colspan: 6, style: s4.empty }, "\u6682\u65E0\u6570\u636E")
4163
+ ])
4164
+ ] : records.value.map(
4165
+ (row) => (0, import_vue6.h)("tr", { key: row.userId }, [
4166
+ (0, import_vue6.h)("td", { style: s4.td }, row.username),
4167
+ (0, import_vue6.h)("td", { style: s4.td }, row.name),
4168
+ (0, import_vue6.h)("td", { style: s4.td }, groupLabel(row)),
4169
+ (0, import_vue6.h)("td", { style: s4.td }, roleLabel(row)),
4170
+ (0, import_vue6.h)("td", { style: s4.td }, [
4171
+ (0, import_vue6.h)(
4172
+ "span",
4173
+ {
4174
+ style: {
4175
+ ...s4.badge,
4176
+ ...row.enabled ? s4.badgeOn : s4.badgeOff
4177
+ }
4178
+ },
4179
+ row.enabled ? "\u542F\u7528" : "\u7981\u7528"
4180
+ )
4181
+ ]),
4182
+ (0, import_vue6.h)("td", { style: s4.td }, [
4183
+ (0, import_vue6.h)(
4184
+ "button",
4185
+ {
4186
+ type: "button",
4187
+ style: s4.linkBtn,
4188
+ onClick: () => openEdit(row)
4189
+ },
4190
+ "\u7F16\u8F91"
4191
+ ),
4192
+ (0, import_vue6.h)(
4193
+ "button",
4194
+ {
4195
+ type: "button",
4196
+ style: { ...s4.linkBtn, color: "#d92d20" },
4197
+ onClick: () => askDelete(row)
4198
+ },
4199
+ "\u5220\u9664"
4200
+ )
4201
+ ])
4202
+ ])
4203
+ )
4204
+ )
4205
+ ])
4206
+ ]),
4207
+ (0, import_vue6.h)("div", { style: s4.pagination }, [
4208
+ (0, import_vue6.h)("label", { style: s4.pageSize }, [
4209
+ "\u6BCF\u9875",
4210
+ (0, import_vue6.h)(
4211
+ "select",
4212
+ {
4213
+ style: s4.select,
4214
+ value: pageSize.value,
4215
+ onChange: (e) => {
4216
+ pageSize.value = e.target.value;
4217
+ }
4218
+ },
4219
+ PAGE_SIZE_OPTIONS4.map(
4220
+ (size) => (0, import_vue6.h)("option", { key: size, value: size }, size)
4221
+ )
4222
+ )
4223
+ ]),
4224
+ (0, import_vue6.h)("div", { style: s4.pageBtns }, [
4225
+ (0, import_vue6.h)(
4226
+ "button",
4227
+ {
4228
+ type: "button",
4229
+ style: s4.secondaryBtn,
4230
+ disabled: !hasPreviousPage.value || loading.value,
4231
+ onClick: () => void loadList("previous")
4232
+ },
4233
+ "\u4E0A\u4E00\u9875"
4234
+ ),
4235
+ (0, import_vue6.h)(
4236
+ "button",
4237
+ {
4238
+ type: "button",
4239
+ style: s4.secondaryBtn,
4240
+ disabled: !hasNextPage.value || loading.value,
4241
+ onClick: () => void loadList("next")
4242
+ },
4243
+ "\u4E0B\u4E00\u9875"
4244
+ )
4245
+ ])
4246
+ ]),
4247
+ dialogOpen.value ? (0, import_vue6.h)("div", { style: s4.mask, onClick: closeDialog }, [
4248
+ (0, import_vue6.h)(
4249
+ "div",
4250
+ {
4251
+ style: { ...s4.dialog, maxWidth: "560px" },
4252
+ role: "dialog",
4253
+ "aria-modal": "true",
4254
+ onClick: (e) => e.stopPropagation()
4255
+ },
4256
+ [
4257
+ (0, import_vue6.h)("div", { style: s4.dialogHeader }, [
4258
+ (0, import_vue6.h)(
4259
+ "h3",
4260
+ { style: s4.dialogTitle },
4261
+ editing.value ? "\u7F16\u8F91\u7528\u6237" : "\u65B0\u589E\u7528\u6237"
4262
+ ),
4263
+ (0, import_vue6.h)(
4264
+ "button",
4265
+ {
4266
+ type: "button",
4267
+ style: s4.iconBtn,
4268
+ "aria-label": "\u5173\u95ED",
4269
+ onClick: closeDialog
4270
+ },
4271
+ "\xD7"
4272
+ )
4273
+ ]),
4274
+ (0, import_vue6.h)(
4275
+ "form",
4276
+ {
4277
+ style: s4.form,
4278
+ onSubmit: (e) => void handleSubmit(e)
4279
+ },
4280
+ [
4281
+ formError.value ? (0, import_vue6.h)("div", { style: s4.error }, formError.value) : null,
4282
+ (0, import_vue6.h)("label", { style: s4.field }, [
4283
+ (0, import_vue6.h)("span", { style: s4.label }, "\u8D26\u53F7"),
4284
+ (0, import_vue6.h)("input", {
4285
+ style: s4.input,
4286
+ value: form.username,
4287
+ placeholder: "\u81F3\u5C116\u4F4D\uFF0C\u9700\u542B\u5B57\u6BCD\u548C\u6570\u5B57",
4288
+ required: true,
4289
+ onInput: (e) => {
4290
+ form.username = e.target.value;
4291
+ }
4292
+ })
4293
+ ]),
4294
+ (0, import_vue6.h)("label", { style: s4.field }, [
4295
+ (0, import_vue6.h)("span", { style: s4.label }, "\u7528\u6237\u540D"),
4296
+ (0, import_vue6.h)("input", {
4297
+ style: s4.input,
4298
+ value: form.name,
4299
+ placeholder: "\u8BF7\u8F93\u5165\u7528\u6237\u540D",
4300
+ required: true,
4301
+ onInput: (e) => {
4302
+ form.name = e.target.value;
4303
+ }
4304
+ })
4305
+ ]),
4306
+ (0, import_vue6.h)("label", { style: s4.field }, [
4307
+ (0, import_vue6.h)(
4308
+ "span",
4309
+ { style: s4.label },
4310
+ editing.value ? "\u5BC6\u7801\uFF08\u7559\u7A7A\u5219\u4E0D\u4FEE\u6539\uFF09" : "\u521D\u59CB\u5BC6\u7801"
4311
+ ),
4312
+ (0, import_vue6.h)("input", {
4313
+ style: s4.input,
4314
+ type: "password",
4315
+ value: form.password,
4316
+ placeholder: editing.value ? "\u7559\u7A7A\u8868\u793A\u4E0D\u4FEE\u6539\u5BC6\u7801" : "\u8BF7\u8F93\u5165\u521D\u59CB\u5BC6\u7801",
4317
+ required: !editing.value,
4318
+ autocomplete: "new-password",
4319
+ onInput: (e) => {
4320
+ form.password = e.target.value;
4321
+ }
4322
+ })
4323
+ ]),
4324
+ (0, import_vue6.h)("fieldset", { style: s4.fieldset }, [
4325
+ (0, import_vue6.h)("legend", { style: s4.label }, "\u5F52\u5C5E\u90E8\u95E8"),
4326
+ (0, import_vue6.h)("div", { style: s4.multiSelect }, [
4327
+ optionsLoading.value ? (0, import_vue6.h)("div", { style: s4.hint }, "\u52A0\u8F7D\u4E2D\u2026") : groups.value.length === 0 ? (0, import_vue6.h)("div", { style: s4.hint }, "\u6682\u65E0\u90E8\u95E8\u6570\u636E") : groups.value.map(
4328
+ (g) => (0, import_vue6.h)(
4329
+ "label",
4330
+ {
4331
+ key: g.groupId,
4332
+ style: s4.checkItem
4333
+ },
4334
+ [
4335
+ (0, import_vue6.h)("input", {
4336
+ type: "checkbox",
4337
+ style: s4.control,
4338
+ checked: form.groupIds.includes(
4339
+ g.groupId
4340
+ ),
4341
+ onChange: () => toggleId("groupIds", g.groupId)
4342
+ }),
4343
+ (0, import_vue6.h)("span", g.name || g.groupId)
4344
+ ]
4345
+ )
4346
+ )
4347
+ ])
4348
+ ]),
4349
+ (0, import_vue6.h)("fieldset", { style: s4.fieldset }, [
4350
+ (0, import_vue6.h)("legend", { style: s4.label }, "\u7528\u6237\u89D2\u8272"),
4351
+ (0, import_vue6.h)("div", { style: s4.multiSelect }, [
4352
+ optionsLoading.value ? (0, import_vue6.h)("div", { style: s4.hint }, "\u52A0\u8F7D\u4E2D\u2026") : roles.value.length === 0 ? (0, import_vue6.h)("div", { style: s4.hint }, "\u6682\u65E0\u89D2\u8272\u6570\u636E") : roles.value.map(
4353
+ (r) => (0, import_vue6.h)(
4354
+ "label",
4355
+ {
4356
+ key: r.roleId,
4357
+ style: s4.checkItem
4358
+ },
4359
+ [
4360
+ (0, import_vue6.h)("input", {
4361
+ type: "checkbox",
4362
+ style: s4.control,
4363
+ checked: form.roleIds.includes(
4364
+ r.roleId
4365
+ ),
4366
+ onChange: () => toggleId("roleIds", r.roleId)
4367
+ }),
4368
+ (0, import_vue6.h)("span", r.name || r.roleId)
4369
+ ]
4370
+ )
4371
+ )
4372
+ ])
4373
+ ]),
4374
+ (0, import_vue6.h)("div", { style: s4.switchRow }, [
4375
+ (0, import_vue6.h)("span", { style: s4.label }, "\u662F\u5426\u542F\u7528"),
4376
+ (0, import_vue6.h)(
4377
+ "button",
4378
+ {
4379
+ type: "button",
4380
+ role: "switch",
4381
+ "aria-checked": form.enabled,
4382
+ style: {
4383
+ ...s4.switchTrack,
4384
+ ...form.enabled ? s4.switchTrackOn : {}
4385
+ },
4386
+ onClick: () => {
4387
+ form.enabled = !form.enabled;
4388
+ }
4389
+ },
4390
+ [
4391
+ (0, import_vue6.h)("span", {
4392
+ style: {
4393
+ ...s4.switchThumb,
4394
+ ...form.enabled ? s4.switchThumbOn : {}
4395
+ }
4396
+ })
4397
+ ]
4398
+ )
4399
+ ]),
4400
+ (0, import_vue6.h)("div", { style: s4.dialogFooter }, [
4401
+ (0, import_vue6.h)(
4402
+ "button",
4403
+ {
4404
+ type: "button",
4405
+ style: s4.secondaryBtn,
4406
+ onClick: closeDialog
4407
+ },
4408
+ "\u53D6\u6D88"
4409
+ ),
4410
+ (0, import_vue6.h)(
4411
+ "button",
4412
+ {
4413
+ type: "submit",
4414
+ style: s4.primaryBtn,
4415
+ disabled: saving.value
4416
+ },
4417
+ saving.value ? "\u4FDD\u5B58\u4E2D\u2026" : "\u4FDD\u5B58"
4418
+ )
4419
+ ])
4420
+ ]
4421
+ )
4422
+ ]
4423
+ )
4424
+ ]) : null,
4425
+ deletingRow.value ? (0, import_vue6.h)("div", { style: s4.mask, onClick: closeDeleteDialog }, [
4426
+ (0, import_vue6.h)(
4427
+ "div",
4428
+ {
4429
+ style: { ...s4.dialog, maxWidth: "420px" },
4430
+ role: "dialog",
4431
+ "aria-modal": "true",
4432
+ onClick: (e) => e.stopPropagation()
4433
+ },
4434
+ [
4435
+ (0, import_vue6.h)("div", { style: s4.dialogHeader }, [
4436
+ (0, import_vue6.h)("h3", { style: s4.dialogTitle }, "\u786E\u8BA4\u5220\u9664"),
4437
+ (0, import_vue6.h)(
4438
+ "button",
4439
+ {
4440
+ type: "button",
4441
+ style: s4.iconBtn,
4442
+ "aria-label": "\u5173\u95ED",
4443
+ onClick: closeDeleteDialog
4444
+ },
4445
+ "\xD7"
4446
+ )
4447
+ ]),
4448
+ (0, import_vue6.h)("div", { style: s4.confirmBody }, [
4449
+ (0, import_vue6.h)("p", { style: s4.confirmText }, [
4450
+ "\u786E\u8BA4\u5220\u9664\u7528\u6237\u300C",
4451
+ (0, import_vue6.h)("strong", deletingRow.value.name),
4452
+ "\u300D\uFF08",
4453
+ deletingRow.value.username,
4454
+ "\uFF09\u5417\uFF1F\u5220\u9664\u540E\u4E0D\u53EF\u6062\u590D\u3002"
4455
+ ]),
4456
+ (0, import_vue6.h)("div", { style: s4.dialogFooter }, [
4457
+ (0, import_vue6.h)(
4458
+ "button",
4459
+ {
4460
+ type: "button",
4461
+ style: s4.secondaryBtn,
4462
+ disabled: deleting.value,
4463
+ onClick: closeDeleteDialog
4464
+ },
4465
+ "\u53D6\u6D88"
4466
+ ),
4467
+ (0, import_vue6.h)(
4468
+ "button",
4469
+ {
4470
+ type: "button",
4471
+ style: s4.dangerBtn,
4472
+ disabled: deleting.value,
4473
+ onClick: () => void confirmDelete()
4474
+ },
4475
+ deleting.value ? "\u5220\u9664\u4E2D\u2026" : "\u786E\u8BA4\u5220\u9664"
4476
+ )
4477
+ ])
4478
+ ])
4479
+ ]
4480
+ )
4481
+ ]) : null
4482
+ ]);
4483
+ }
4484
+ });
4485
+
4486
+ // src/vue/SystemAdmin.ts
4487
+ var import_vue7 = require("vue");
4488
+
4489
+ // src/admin/menu.ts
4490
+ var SYSTEM_ADMIN_MENU = {
4491
+ key: "system",
4492
+ label: "\u7CFB\u7EDF\u7BA1\u7406",
4493
+ children: [
4494
+ { key: "menu", label: "\u83DC\u5355\u7BA1\u7406" },
4495
+ { key: "resource", label: "\u6743\u9650\u70B9\u7BA1\u7406" },
4496
+ { key: "role", label: "\u89D2\u8272\u7BA1\u7406" },
4497
+ { key: "user", label: "\u7528\u6237\u7BA1\u7406" }
4498
+ ]
4499
+ };
4500
+ var SYSTEM_ADMIN_DEFAULT_KEY = "menu";
4501
+
4502
+ // src/vue/SystemAdmin.ts
4503
+ var s5 = {
4504
+ root: {
4505
+ display: "flex",
4506
+ minHeight: "560px",
4507
+ border: "1px solid #eaecf0",
4508
+ borderRadius: "12px",
4509
+ overflow: "hidden",
4510
+ background: "#fff",
4511
+ fontFamily: '"PingFang SC", "Microsoft YaHei", -apple-system, BlinkMacSystemFont, sans-serif',
4512
+ color: "#101828"
4513
+ },
4514
+ sidebar: {
4515
+ width: "200px",
4516
+ flexShrink: "0",
4517
+ borderRight: "1px solid #eaecf0",
4518
+ background: "#f9fafb",
4519
+ padding: "16px 12px"
4520
+ },
4521
+ sidebarTitle: {
4522
+ fontSize: "14px",
4523
+ fontWeight: "600",
4524
+ color: "#344054",
4525
+ padding: "4px 10px 12px"
4526
+ },
4527
+ nav: {
4528
+ display: "flex",
4529
+ flexDirection: "column",
4530
+ gap: "4px"
4531
+ },
4532
+ navItem: {
4533
+ border: "none",
4534
+ background: "transparent",
4535
+ textAlign: "left",
4536
+ padding: "10px 12px",
4537
+ borderRadius: "8px",
4538
+ fontSize: "14px",
4539
+ color: "#475467",
4540
+ cursor: "pointer"
4541
+ },
4542
+ navItemActive: {
4543
+ background: "#e6f7f9",
4544
+ color: "#049BAD",
4545
+ fontWeight: "600"
4546
+ },
4547
+ content: {
4548
+ flex: "1",
4549
+ minWidth: "0",
4550
+ display: "flex",
4551
+ flexDirection: "column",
4552
+ background: "#fff"
4553
+ },
4554
+ contentHeader: {
4555
+ display: "flex",
4556
+ alignItems: "center",
4557
+ justifyContent: "space-between",
4558
+ gap: "12px",
4559
+ padding: "12px 16px",
4560
+ borderBottom: "1px solid #f2f4f7"
4561
+ },
4562
+ breadcrumb: {
4563
+ display: "flex",
4564
+ alignItems: "center",
4565
+ gap: "8px",
4566
+ fontSize: "13px"
4567
+ },
4568
+ breadcrumbParent: { color: "#98a2b3" },
4569
+ breadcrumbSep: { color: "#d0d5dd" },
4570
+ breadcrumbCurrent: { color: "#344054", fontWeight: "600" },
4571
+ panel: {
4572
+ flex: "1",
4573
+ minHeight: "0",
4574
+ overflow: "auto"
4575
+ }
4576
+ };
4577
+ var SystemAdmin = (0, import_vue7.defineComponent)({
4578
+ name: "SystemAdmin",
3476
4579
  props: {
3477
4580
  menuApi: {
3478
4581
  type: Object,
@@ -3486,6 +4589,10 @@ var SystemAdmin = (0, import_vue6.defineComponent)({
3486
4589
  type: Object,
3487
4590
  required: true
3488
4591
  },
4592
+ userApi: {
4593
+ type: Object,
4594
+ required: true
4595
+ },
3489
4596
  defaultActiveKey: {
3490
4597
  type: String,
3491
4598
  default: SYSTEM_ADMIN_DEFAULT_KEY
@@ -3504,17 +4611,17 @@ var SystemAdmin = (0, import_vue6.defineComponent)({
3504
4611
  activeKeyChange: (_key) => true
3505
4612
  },
3506
4613
  setup(props, { emit, slots }) {
3507
- const innerKey = (0, import_vue6.ref)(props.defaultActiveKey);
3508
- (0, import_vue6.watch)(
4614
+ const innerKey = (0, import_vue7.ref)(props.defaultActiveKey);
4615
+ (0, import_vue7.watch)(
3509
4616
  () => props.defaultActiveKey,
3510
4617
  (value) => {
3511
4618
  if (props.activeKey === void 0) innerKey.value = value;
3512
4619
  }
3513
4620
  );
3514
- const activeKey = (0, import_vue6.computed)(
4621
+ const activeKey = (0, import_vue7.computed)(
3515
4622
  () => props.activeKey ?? innerKey.value
3516
4623
  );
3517
- const activeLabel = (0, import_vue6.computed)(
4624
+ const activeLabel = (0, import_vue7.computed)(
3518
4625
  () => SYSTEM_ADMIN_MENU.children.find((item) => item.key === activeKey.value)?.label ?? ""
3519
4626
  );
3520
4627
  function setActiveKey(key) {
@@ -3522,22 +4629,22 @@ var SystemAdmin = (0, import_vue6.defineComponent)({
3522
4629
  emit("update:activeKey", key);
3523
4630
  emit("activeKeyChange", key);
3524
4631
  }
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)(
4632
+ return () => (0, import_vue7.h)("div", { style: s5.root }, [
4633
+ (0, import_vue7.h)("aside", { style: s5.sidebar }, [
4634
+ (0, import_vue7.h)("div", { style: s5.sidebarTitle }, props.title),
4635
+ (0, import_vue7.h)(
3529
4636
  "nav",
3530
- { style: s4.nav },
4637
+ { style: s5.nav },
3531
4638
  SYSTEM_ADMIN_MENU.children.map((item) => {
3532
4639
  const active = item.key === activeKey.value;
3533
- return (0, import_vue6.h)(
4640
+ return (0, import_vue7.h)(
3534
4641
  "button",
3535
4642
  {
3536
4643
  key: item.key,
3537
4644
  type: "button",
3538
4645
  style: {
3539
- ...s4.navItem,
3540
- ...active ? s4.navItemActive : {}
4646
+ ...s5.navItem,
4647
+ ...active ? s5.navItemActive : {}
3541
4648
  },
3542
4649
  onClick: () => setActiveKey(item.key)
3543
4650
  },
@@ -3546,20 +4653,20 @@ var SystemAdmin = (0, import_vue6.defineComponent)({
3546
4653
  })
3547
4654
  )
3548
4655
  ]),
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)
4656
+ (0, import_vue7.h)("main", { style: s5.content }, [
4657
+ (0, import_vue7.h)("div", { style: s5.contentHeader }, [
4658
+ (0, import_vue7.h)("div", { style: s5.breadcrumb }, [
4659
+ (0, import_vue7.h)("span", { style: s5.breadcrumbParent }, props.title),
4660
+ (0, import_vue7.h)("span", { style: s5.breadcrumbSep }, "/"),
4661
+ (0, import_vue7.h)("span", { style: s5.breadcrumbCurrent }, activeLabel.value)
3555
4662
  ]),
3556
4663
  slots.toolbarExtra?.()
3557
4664
  ]),
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, {
4665
+ (0, import_vue7.h)("div", { style: s5.panel }, [
4666
+ activeKey.value === "menu" ? (0, import_vue7.h)(MenuManager, { api: props.menuApi, title: "\u83DC\u5355\u7BA1\u7406" }) : activeKey.value === "resource" ? (0, import_vue7.h)(ResourceManager, {
3560
4667
  api: props.resourceApi,
3561
4668
  title: "\u6743\u9650\u70B9\u7BA1\u7406"
3562
- }) : (0, import_vue6.h)(RoleManager, { api: props.roleApi, title: "\u89D2\u8272\u7BA1\u7406" })
4669
+ }) : activeKey.value === "role" ? (0, import_vue7.h)(RoleManager, { api: props.roleApi, title: "\u89D2\u8272\u7BA1\u7406" }) : (0, import_vue7.h)(UserManager, { api: props.userApi, title: "\u7528\u6237\u7BA1\u7406" })
3563
4670
  ])
3564
4671
  ])
3565
4672
  ]);
@@ -3592,36 +4699,49 @@ var SystemAdmin = (0, import_vue6.defineComponent)({
3592
4699
  SYSTEM_ADMIN_DEFAULT_KEY,
3593
4700
  SYSTEM_ADMIN_MENU,
3594
4701
  SystemAdmin,
4702
+ UserManager,
3595
4703
  appendQueryParam,
3596
4704
  buildCreateBody,
3597
4705
  buildCreateMenuBody,
3598
4706
  buildCreateRoleBody,
4707
+ buildCreateUserBody,
4708
+ buildPermissionTreeIndex,
3599
4709
  buildSavePermissionsBody,
3600
4710
  buildUpdateBody,
3601
4711
  buildUpdateMenuBody,
3602
4712
  buildUpdateRoleBody,
4713
+ buildUpdateUserBody,
3603
4714
  collectTreeResourceIds,
4715
+ countCheckedDescendants,
3604
4716
  createAuthorizationResourceApi,
3605
4717
  createDefaultResourceRequest,
3606
4718
  createMenuResourceApi,
3607
4719
  createPermissionPlugin,
3608
4720
  createPermissionStore,
3609
4721
  createSystemRoleApi,
4722
+ createSystemUserApi,
3610
4723
  createVPermission,
3611
4724
  extractPagination,
3612
4725
  extractRecords,
3613
4726
  getAppClientId,
3614
4727
  getDeviceWorkerId,
4728
+ hasCheckedDescendant,
3615
4729
  isMenuLeaf,
4730
+ isPermissionNodeIndeterminate,
3616
4731
  mapAuthorizationResource,
3617
4732
  mapMenuResource,
3618
4733
  mapPermissionTreeNode,
3619
4734
  mapRolePermissions,
4735
+ mapSystemGroupOption,
3620
4736
  mapSystemRole,
4737
+ mapSystemRoleOption,
4738
+ mapSystemUser,
3621
4739
  resolveMenuDepth,
3622
4740
  snowyflake,
4741
+ togglePermissionCheck,
3623
4742
  useHasPermission,
3624
4743
  useHasRole,
3625
- usePermission
4744
+ usePermission,
4745
+ validateUsername
3626
4746
  });
3627
4747
  //# sourceMappingURL=index.cjs.map