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.
@@ -46,35 +46,48 @@ __export(react_exports, {
46
46
  SYSTEM_ADMIN_DEFAULT_KEY: () => SYSTEM_ADMIN_DEFAULT_KEY,
47
47
  SYSTEM_ADMIN_MENU: () => SYSTEM_ADMIN_MENU,
48
48
  SystemAdmin: () => SystemAdmin,
49
+ UserManager: () => UserManager,
49
50
  appendQueryParam: () => appendQueryParam,
50
51
  buildCreateBody: () => buildCreateBody,
51
52
  buildCreateMenuBody: () => buildCreateMenuBody,
52
53
  buildCreateRoleBody: () => buildCreateRoleBody,
54
+ buildCreateUserBody: () => buildCreateUserBody,
55
+ buildPermissionTreeIndex: () => buildPermissionTreeIndex,
53
56
  buildSavePermissionsBody: () => buildSavePermissionsBody,
54
57
  buildUpdateBody: () => buildUpdateBody,
55
58
  buildUpdateMenuBody: () => buildUpdateMenuBody,
56
59
  buildUpdateRoleBody: () => buildUpdateRoleBody,
60
+ buildUpdateUserBody: () => buildUpdateUserBody,
57
61
  collectTreeResourceIds: () => collectTreeResourceIds,
62
+ countCheckedDescendants: () => countCheckedDescendants,
58
63
  createAuthorizationResourceApi: () => createAuthorizationResourceApi,
59
64
  createDefaultResourceRequest: () => createDefaultResourceRequest,
60
65
  createMenuResourceApi: () => createMenuResourceApi,
61
66
  createPermissionStore: () => createPermissionStore,
62
67
  createSystemRoleApi: () => createSystemRoleApi,
68
+ createSystemUserApi: () => createSystemUserApi,
63
69
  extractPagination: () => extractPagination,
64
70
  extractRecords: () => extractRecords,
65
71
  getAppClientId: () => getAppClientId,
66
72
  getDeviceWorkerId: () => getDeviceWorkerId,
73
+ hasCheckedDescendant: () => hasCheckedDescendant,
67
74
  isMenuLeaf: () => isMenuLeaf,
75
+ isPermissionNodeIndeterminate: () => isPermissionNodeIndeterminate,
68
76
  mapAuthorizationResource: () => mapAuthorizationResource,
69
77
  mapMenuResource: () => mapMenuResource,
70
78
  mapPermissionTreeNode: () => mapPermissionTreeNode,
71
79
  mapRolePermissions: () => mapRolePermissions,
80
+ mapSystemGroupOption: () => mapSystemGroupOption,
72
81
  mapSystemRole: () => mapSystemRole,
82
+ mapSystemRoleOption: () => mapSystemRoleOption,
83
+ mapSystemUser: () => mapSystemUser,
73
84
  resolveMenuDepth: () => resolveMenuDepth,
74
85
  snowyflake: () => snowyflake,
86
+ togglePermissionCheck: () => togglePermissionCheck,
75
87
  useHasPermission: () => useHasPermission,
76
88
  useHasRole: () => useHasRole,
77
- usePermission: () => usePermission
89
+ usePermission: () => usePermission,
90
+ validateUsername: () => validateUsername
78
91
  });
79
92
  module.exports = __toCommonJS(react_exports);
80
93
 
@@ -2060,6 +2073,72 @@ function mapRolePermissions(payload) {
2060
2073
  function collectTreeResourceIds(node) {
2061
2074
  return [node.resourceId, ...node.children.flatMap(collectTreeResourceIds)];
2062
2075
  }
2076
+ function buildPermissionTreeIndex(tree) {
2077
+ const parentMap = /* @__PURE__ */ new Map();
2078
+ const nodeMap = /* @__PURE__ */ new Map();
2079
+ const walk = (nodes, parentId) => {
2080
+ for (const node of nodes) {
2081
+ parentMap.set(node.resourceId, parentId);
2082
+ nodeMap.set(node.resourceId, node);
2083
+ if (node.children.length > 0) {
2084
+ walk(node.children, node.resourceId);
2085
+ }
2086
+ }
2087
+ };
2088
+ walk(tree, null);
2089
+ return { parentMap, nodeMap };
2090
+ }
2091
+ function togglePermissionCheck(tree, checked, node) {
2092
+ const next = new Set(checked);
2093
+ const ids = collectTreeResourceIds(node);
2094
+ const shouldCheck = !checked.has(node.resourceId);
2095
+ if (shouldCheck) {
2096
+ ids.forEach((id) => next.add(id));
2097
+ } else {
2098
+ ids.forEach((id) => next.delete(id));
2099
+ }
2100
+ const { parentMap, nodeMap } = buildPermissionTreeIndex(tree);
2101
+ let parentId = parentMap.get(node.resourceId) ?? null;
2102
+ while (parentId) {
2103
+ const parent = nodeMap.get(parentId);
2104
+ if (!parent) break;
2105
+ const allChildrenChecked = parent.children.every(
2106
+ (child) => next.has(child.resourceId)
2107
+ );
2108
+ if (allChildrenChecked && parent.children.length > 0) {
2109
+ next.add(parentId);
2110
+ } else {
2111
+ next.delete(parentId);
2112
+ }
2113
+ parentId = parentMap.get(parentId) ?? null;
2114
+ }
2115
+ return next;
2116
+ }
2117
+ function countCheckedDescendants(node, checked) {
2118
+ let total = 0;
2119
+ let checkedCount = 0;
2120
+ const walk = (n) => {
2121
+ for (const child of n.children) {
2122
+ total += 1;
2123
+ if (checked.has(child.resourceId)) checkedCount += 1;
2124
+ walk(child);
2125
+ }
2126
+ };
2127
+ walk(node);
2128
+ return { total, checkedCount };
2129
+ }
2130
+ function hasCheckedDescendant(node, checked) {
2131
+ for (const child of node.children) {
2132
+ if (checked.has(child.resourceId) || hasCheckedDescendant(child, checked)) {
2133
+ return true;
2134
+ }
2135
+ }
2136
+ return false;
2137
+ }
2138
+ function isPermissionNodeIndeterminate(node, checked) {
2139
+ if (checked.has(node.resourceId) || node.children.length === 0) return false;
2140
+ return hasCheckedDescendant(node, checked);
2141
+ }
2063
2142
  function buildListUrl2(params) {
2064
2143
  const parts = [];
2065
2144
  appendQueryParam(parts, "keyword", params?.keyword ?? "");
@@ -2148,19 +2227,6 @@ var emptyForm3 = () => ({
2148
2227
  name: "",
2149
2228
  description: ""
2150
2229
  });
2151
- function countCheckedDescendants(node, checked) {
2152
- let total = 0;
2153
- let checkedCount = 0;
2154
- const walk = (n) => {
2155
- for (const child of n.children) {
2156
- total += 1;
2157
- if (checked.has(child.resourceId)) checkedCount += 1;
2158
- walk(child);
2159
- }
2160
- };
2161
- walk(node);
2162
- return { total, checkedCount };
2163
- }
2164
2230
  function RoleManager({
2165
2231
  api,
2166
2232
  title = "\u89D2\u8272\u7BA1\u7406",
@@ -2315,17 +2381,7 @@ function RoleManager({
2315
2381
  setAuthExpanded((prev) => ({ ...prev, [resourceId]: !prev[resourceId] }));
2316
2382
  };
2317
2383
  const toggleCheck = (node) => {
2318
- setAuthChecked((prev) => {
2319
- const next = new Set(prev);
2320
- const ids = collectTreeResourceIds(node);
2321
- const shouldCheck = !prev.has(node.resourceId);
2322
- if (shouldCheck) {
2323
- ids.forEach((id) => next.add(id));
2324
- } else {
2325
- ids.forEach((id) => next.delete(id));
2326
- }
2327
- return next;
2328
- });
2384
+ setAuthChecked((prev) => togglePermissionCheck(authTree, prev, node));
2329
2385
  };
2330
2386
  const saveAuthorize = async () => {
2331
2387
  if (!authRole) return;
@@ -2344,8 +2400,7 @@ function RoleManager({
2344
2400
  const hasChildren = node.children.length > 0;
2345
2401
  const expanded = Boolean(authExpanded[node.resourceId]);
2346
2402
  const checked = authChecked.has(node.resourceId);
2347
- const { total, checkedCount } = countCheckedDescendants(node, authChecked);
2348
- const indeterminate = hasChildren && checkedCount > 0 && checkedCount < total && !checked;
2403
+ const indeterminate = isPermissionNodeIndeterminate(node, authChecked);
2349
2404
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
2350
2405
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { ...styles3.treeRow, paddingLeft: 12 + depth * 20 }, children: [
2351
2406
  hasChildren ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
@@ -2856,55 +2911,953 @@ var styles3 = {
2856
2911
  }
2857
2912
  };
2858
2913
 
2859
- // src/react/SystemAdmin.tsx
2914
+ // src/react/UserManager.tsx
2860
2915
  var import_react5 = require("react");
2861
2916
 
2862
- // src/admin/menu.ts
2863
- var SYSTEM_ADMIN_MENU = {
2864
- key: "system",
2865
- label: "\u7CFB\u7EDF\u7BA1\u7406",
2866
- children: [
2867
- { key: "menu", label: "\u83DC\u5355\u7BA1\u7406" },
2868
- { key: "resource", label: "\u6743\u9650\u70B9\u7BA1\u7406" },
2869
- { key: "role", label: "\u89D2\u8272\u7BA1\u7406" }
2870
- ]
2871
- };
2872
- var SYSTEM_ADMIN_DEFAULT_KEY = "menu";
2917
+ // src/users/index.ts
2918
+ function asIdList(value) {
2919
+ if (!Array.isArray(value)) return [];
2920
+ return value.map((item) => {
2921
+ if (item === void 0 || item === null || item === "") return "";
2922
+ if (typeof item === "object") {
2923
+ const row = item;
2924
+ const id = row.groupId ?? row.roleId ?? row.id;
2925
+ return id === void 0 || id === null ? "" : String(id);
2926
+ }
2927
+ return String(item);
2928
+ }).filter(Boolean);
2929
+ }
2930
+ function asNameList(value) {
2931
+ if (!Array.isArray(value)) return void 0;
2932
+ const names = value.map((item) => {
2933
+ if (item === void 0 || item === null) return "";
2934
+ if (typeof item === "object") {
2935
+ return String(item.name ?? "");
2936
+ }
2937
+ return String(item);
2938
+ }).filter(Boolean);
2939
+ return names.length ? names : void 0;
2940
+ }
2941
+ function mapSystemUser(item) {
2942
+ if (!item || typeof item !== "object") return null;
2943
+ const row = item;
2944
+ const userId = row.userId ?? row.user_id ?? row.id;
2945
+ if (userId === void 0 || userId === null || userId === "") return null;
2946
+ return {
2947
+ userId: String(userId),
2948
+ username: String(row.username ?? row.account ?? ""),
2949
+ name: String(row.name ?? ""),
2950
+ groupIds: asIdList(row.groupIds ?? row.group_ids ?? row.groups),
2951
+ roleIds: asIdList(row.roleIds ?? row.role_ids ?? row.roles),
2952
+ groupNames: asNameList(row.groupNames ?? row.group_names ?? row.groups),
2953
+ roleNames: asNameList(row.roleNames ?? row.role_names ?? row.roles),
2954
+ enabled: Boolean(row.enabled ?? row.enable ?? true)
2955
+ };
2956
+ }
2957
+ function mapSystemGroupOption(item) {
2958
+ if (!item || typeof item !== "object") return null;
2959
+ const row = item;
2960
+ const groupId = row.groupId ?? row.group_id ?? row.id;
2961
+ if (groupId === void 0 || groupId === null || groupId === "") return null;
2962
+ return {
2963
+ groupId: String(groupId),
2964
+ name: String(row.name ?? "")
2965
+ };
2966
+ }
2967
+ function mapSystemRoleOption(item) {
2968
+ if (!item || typeof item !== "object") return null;
2969
+ const row = item;
2970
+ const roleId = row.roleId ?? row.role_id ?? row.id;
2971
+ if (roleId === void 0 || roleId === null || roleId === "") return null;
2972
+ return {
2973
+ roleId: String(roleId),
2974
+ name: String(row.name ?? "")
2975
+ };
2976
+ }
2977
+ function validateUsername(username) {
2978
+ const value = username.trim();
2979
+ if (value.length < 6) return "\u8D26\u53F7\u957F\u5EA6\u4E0D\u5C11\u4E8E 6 \u4E2A\u5B57\u7B26";
2980
+ if (!/[A-Za-z]/.test(value) || !/[0-9]/.test(value)) {
2981
+ return "\u8D26\u53F7\u9700\u540C\u65F6\u5305\u542B\u5B57\u6BCD\u548C\u6570\u5B57";
2982
+ }
2983
+ return null;
2984
+ }
2985
+ function buildListUrl3(params) {
2986
+ const parts = [];
2987
+ appendQueryParam(parts, "keyword", params?.keyword ?? "");
2988
+ if (params?.enabled !== void 0) {
2989
+ appendQueryParam(parts, "enabled", String(params.enabled));
2990
+ }
2991
+ appendQueryParam(parts, "page-token", params?.pagination?.pageToken ?? "");
2992
+ appendQueryParam(parts, "page-size", params?.pagination?.pageSize ?? "20");
2993
+ appendQueryParam(parts, "page-direction", params?.pagination?.pageDirection ?? "current");
2994
+ return parts.length ? `/system/users?${parts.join("&")}` : "/system/users";
2995
+ }
2996
+ function buildKeywordUrl(base, keyword) {
2997
+ const parts = [];
2998
+ appendQueryParam(parts, "keyword", keyword ?? "");
2999
+ return parts.length ? `${base}?${parts.join("&")}` : base;
3000
+ }
3001
+ function buildCreateUserBody(values) {
3002
+ return {
3003
+ username: values.username.trim(),
3004
+ name: values.name.trim(),
3005
+ password: values.password,
3006
+ groupIds: [...new Set(values.groupIds.map(String))],
3007
+ roleIds: [...new Set(values.roleIds.map(String))],
3008
+ enabled: Boolean(values.enabled)
3009
+ };
3010
+ }
3011
+ function buildUpdateUserBody(values) {
3012
+ const body = {
3013
+ username: values.username.trim(),
3014
+ name: values.name.trim(),
3015
+ groupIds: [...new Set(values.groupIds.map(String))],
3016
+ roleIds: [...new Set(values.roleIds.map(String))],
3017
+ enabled: Boolean(values.enabled)
3018
+ };
3019
+ if (values.password.trim()) {
3020
+ body.password = values.password;
3021
+ }
3022
+ return body;
3023
+ }
3024
+ function createSystemUserApi(request) {
3025
+ return {
3026
+ async list(params, signal) {
3027
+ const json = await request({
3028
+ method: "GET",
3029
+ url: buildListUrl3(params),
3030
+ signal
3031
+ });
3032
+ const records = extractRecords(json).map(mapSystemUser).filter((item) => item !== null);
3033
+ return {
3034
+ records,
3035
+ ...extractPagination(json)
3036
+ };
3037
+ },
3038
+ async create(values, signal) {
3039
+ return request({
3040
+ method: "POST",
3041
+ url: "/system/users",
3042
+ body: buildCreateUserBody(values),
3043
+ signal
3044
+ });
3045
+ },
3046
+ async update(userId, values, signal) {
3047
+ return request({
3048
+ method: "PATCH",
3049
+ url: `/system/users/${encodeURIComponent(userId)}`,
3050
+ body: buildUpdateUserBody(values),
3051
+ signal
3052
+ });
3053
+ },
3054
+ async remove(userId, signal) {
3055
+ return request({
3056
+ method: "DELETE",
3057
+ url: `/system/users/${encodeURIComponent(userId)}`,
3058
+ signal
3059
+ });
3060
+ },
3061
+ async listGroups(params, signal) {
3062
+ const json = await request({
3063
+ method: "GET",
3064
+ url: buildKeywordUrl("/system/groups", params?.keyword),
3065
+ signal
3066
+ });
3067
+ return extractRecords(json).map(mapSystemGroupOption).filter((item) => item !== null);
3068
+ },
3069
+ async listRoleOptions(params, signal) {
3070
+ const json = await request({
3071
+ method: "GET",
3072
+ url: buildKeywordUrl("/system/roles", params?.keyword),
3073
+ signal
3074
+ });
3075
+ return extractRecords(json).map(mapSystemRoleOption).filter((item) => item !== null);
3076
+ }
3077
+ };
3078
+ }
2873
3079
 
2874
- // src/react/SystemAdmin.tsx
3080
+ // src/react/UserManager.tsx
2875
3081
  var import_jsx_runtime5 = require("react/jsx-runtime");
2876
- function SystemAdmin({
2877
- menuApi,
2878
- resourceApi,
2879
- roleApi,
2880
- defaultActiveKey = SYSTEM_ADMIN_DEFAULT_KEY,
2881
- activeKey: controlledKey,
2882
- onActiveKeyChange,
2883
- title = SYSTEM_ADMIN_MENU.label,
3082
+ var PAGE_SIZE_OPTIONS4 = ["10", "20", "50", "100"];
3083
+ var emptyForm4 = () => ({
3084
+ username: "",
3085
+ name: "",
3086
+ password: "",
3087
+ groupIds: [],
3088
+ roleIds: [],
3089
+ enabled: true
3090
+ });
3091
+ function UserManager({
3092
+ api,
3093
+ title = "\u7528\u6237\u7BA1\u7406",
3094
+ pageSize: initialPageSize = "20",
2884
3095
  toolbarExtra
2885
3096
  }) {
2886
- const [innerKey, setInnerKey] = (0, import_react5.useState)(defaultActiveKey);
2887
- const activeKey = controlledKey ?? innerKey;
2888
- const setActiveKey = (key) => {
2889
- if (controlledKey === void 0) setInnerKey(key);
2890
- onActiveKeyChange?.(key);
2891
- };
2892
- const activeLabel = (0, import_react5.useMemo)(
2893
- () => SYSTEM_ADMIN_MENU.children.find((item) => item.key === activeKey)?.label ?? "",
2894
- [activeKey]
3097
+ const [records, setRecords] = (0, import_react5.useState)([]);
3098
+ const [loading, setLoading] = (0, import_react5.useState)(false);
3099
+ const [error, setError] = (0, import_react5.useState)("");
3100
+ const [keyword, setKeyword] = (0, import_react5.useState)("");
3101
+ const [keywordInput, setKeywordInput] = (0, import_react5.useState)("");
3102
+ const [enabledFilter, setEnabledFilter] = (0, import_react5.useState)("all");
3103
+ const [pageSize, setPageSize] = (0, import_react5.useState)(initialPageSize);
3104
+ const [pageToken, setPageToken] = (0, import_react5.useState)("");
3105
+ const [hasPreviousPage, setHasPreviousPage] = (0, import_react5.useState)(false);
3106
+ const [hasNextPage, setHasNextPage] = (0, import_react5.useState)(false);
3107
+ const [dialogOpen, setDialogOpen] = (0, import_react5.useState)(false);
3108
+ const [editing, setEditing] = (0, import_react5.useState)(null);
3109
+ const [form, setForm] = (0, import_react5.useState)(emptyForm4);
3110
+ const [formError, setFormError] = (0, import_react5.useState)("");
3111
+ const [saving, setSaving] = (0, import_react5.useState)(false);
3112
+ const [deletingRow, setDeletingRow] = (0, import_react5.useState)(null);
3113
+ const [deleting, setDeleting] = (0, import_react5.useState)(false);
3114
+ const [groups, setGroups] = (0, import_react5.useState)([]);
3115
+ const [roles, setRoles] = (0, import_react5.useState)([]);
3116
+ const [optionsLoading, setOptionsLoading] = (0, import_react5.useState)(false);
3117
+ const enabledParam = enabledFilter === "all" ? void 0 : enabledFilter === "true";
3118
+ const loadList = (0, import_react5.useCallback)(
3119
+ async (direction = "current", token = pageToken) => {
3120
+ setLoading(true);
3121
+ setError("");
3122
+ try {
3123
+ const result = await api.list({
3124
+ keyword,
3125
+ enabled: enabledParam,
3126
+ pagination: {
3127
+ pageToken: token,
3128
+ pageSize,
3129
+ pageDirection: direction
3130
+ }
3131
+ });
3132
+ setRecords(result.records);
3133
+ setPageToken(result.pageToken);
3134
+ setHasPreviousPage(result.hasPreviousPage);
3135
+ setHasNextPage(result.hasNextPage);
3136
+ } catch (err) {
3137
+ setError(err instanceof Error ? err.message : "\u52A0\u8F7D\u5931\u8D25");
3138
+ } finally {
3139
+ setLoading(false);
3140
+ }
3141
+ },
3142
+ [api, keyword, enabledParam, pageSize, pageToken]
2895
3143
  );
3144
+ (0, import_react5.useEffect)(() => {
3145
+ void loadList("current", "");
3146
+ }, [api, pageSize, keyword, enabledFilter]);
3147
+ const loadOptions = (0, import_react5.useCallback)(async () => {
3148
+ setOptionsLoading(true);
3149
+ try {
3150
+ const [groupList, roleList] = await Promise.all([
3151
+ api.listGroups(),
3152
+ api.listRoleOptions()
3153
+ ]);
3154
+ setGroups(groupList);
3155
+ setRoles(roleList);
3156
+ } catch (err) {
3157
+ setFormError(err instanceof Error ? err.message : "\u52A0\u8F7D\u90E8\u95E8/\u89D2\u8272\u5931\u8D25");
3158
+ } finally {
3159
+ setOptionsLoading(false);
3160
+ }
3161
+ }, [api]);
3162
+ const handleSearch = () => {
3163
+ setPageToken("");
3164
+ setKeyword(keywordInput.trim());
3165
+ };
3166
+ const openCreate = () => {
3167
+ setEditing(null);
3168
+ setForm(emptyForm4());
3169
+ setFormError("");
3170
+ setDialogOpen(true);
3171
+ void loadOptions();
3172
+ };
3173
+ const openEdit = (row) => {
3174
+ setEditing(row);
3175
+ setForm({
3176
+ username: row.username,
3177
+ name: row.name,
3178
+ password: "",
3179
+ groupIds: [...row.groupIds],
3180
+ roleIds: [...row.roleIds],
3181
+ enabled: row.enabled
3182
+ });
3183
+ setFormError("");
3184
+ setDialogOpen(true);
3185
+ void loadOptions();
3186
+ };
3187
+ const closeDialog = () => {
3188
+ if (!saving) setDialogOpen(false);
3189
+ };
3190
+ const toggleId = (field, id) => {
3191
+ setForm((prev) => {
3192
+ const exists = prev[field].includes(id);
3193
+ return {
3194
+ ...prev,
3195
+ [field]: exists ? prev[field].filter((x) => x !== id) : [...prev[field], id]
3196
+ };
3197
+ });
3198
+ };
3199
+ const handleSubmit = async (event) => {
3200
+ event.preventDefault();
3201
+ const usernameError = validateUsername(form.username);
3202
+ if (usernameError) {
3203
+ setFormError(usernameError);
3204
+ return;
3205
+ }
3206
+ if (!form.name.trim()) {
3207
+ setFormError("\u8BF7\u586B\u5199\u7528\u6237\u540D");
3208
+ return;
3209
+ }
3210
+ if (!editing && !form.password.trim()) {
3211
+ setFormError("\u8BF7\u586B\u5199\u521D\u59CB\u5BC6\u7801");
3212
+ return;
3213
+ }
3214
+ setSaving(true);
3215
+ setFormError("");
3216
+ setError("");
3217
+ try {
3218
+ if (editing) {
3219
+ await api.update(editing.userId, form);
3220
+ } else {
3221
+ await api.create(form);
3222
+ }
3223
+ setDialogOpen(false);
3224
+ await loadList("current", "");
3225
+ } catch (err) {
3226
+ setFormError(err instanceof Error ? err.message : "\u4FDD\u5B58\u5931\u8D25");
3227
+ } finally {
3228
+ setSaving(false);
3229
+ }
3230
+ };
3231
+ const askDelete = (row) => setDeletingRow(row);
3232
+ const closeDeleteDialog = () => {
3233
+ if (!deleting) setDeletingRow(null);
3234
+ };
3235
+ const confirmDelete = async () => {
3236
+ if (!deletingRow) return;
3237
+ setDeleting(true);
3238
+ setError("");
3239
+ try {
3240
+ await api.remove(deletingRow.userId);
3241
+ setDeletingRow(null);
3242
+ await loadList("current", "");
3243
+ } catch (err) {
3244
+ setError(err instanceof Error ? err.message : "\u5220\u9664\u5931\u8D25");
3245
+ } finally {
3246
+ setDeleting(false);
3247
+ }
3248
+ };
3249
+ const groupLabel = (row) => {
3250
+ if (row.groupNames?.length) return row.groupNames.join("\u3001");
3251
+ if (!row.groupIds.length) return "\u2014";
3252
+ const map = new Map(groups.map((g) => [g.groupId, g.name]));
3253
+ return row.groupIds.map((id) => map.get(id) || id).join("\u3001");
3254
+ };
3255
+ const roleLabel = (row) => {
3256
+ if (row.roleNames?.length) return row.roleNames.join("\u3001");
3257
+ if (!row.roleIds.length) return "\u2014";
3258
+ const map = new Map(roles.map((r) => [r.roleId, r.name]));
3259
+ return row.roleIds.map((id) => map.get(id) || id).join("\u3001");
3260
+ };
3261
+ (0, import_react5.useEffect)(() => {
3262
+ void (async () => {
3263
+ try {
3264
+ const [groupList, roleList] = await Promise.all([
3265
+ api.listGroups(),
3266
+ api.listRoleOptions()
3267
+ ]);
3268
+ setGroups(groupList);
3269
+ setRoles(roleList);
3270
+ } catch {
3271
+ }
3272
+ })();
3273
+ }, [api]);
2896
3274
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: styles4.root, children: [
2897
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("aside", { style: styles4.sidebar, children: [
2898
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: styles4.sidebarTitle, children: title }),
2899
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("nav", { style: styles4.nav, children: SYSTEM_ADMIN_MENU.children.map((item) => {
2900
- const active = item.key === activeKey;
2901
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2902
- "button",
2903
- {
3275
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: styles4.toolbar, children: [
3276
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h2", { style: styles4.title, children: title }),
3277
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: styles4.toolbarRight, children: [
3278
+ toolbarExtra,
3279
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", style: styles4.primaryBtn, onClick: openCreate, children: "\u65B0\u589E\u7528\u6237" })
3280
+ ] })
3281
+ ] }),
3282
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: styles4.searchBar, children: [
3283
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3284
+ "input",
3285
+ {
3286
+ style: { ...styles4.input, maxWidth: 240 },
3287
+ value: keywordInput,
3288
+ onChange: (e) => setKeywordInput(e.target.value),
3289
+ placeholder: "\u641C\u7D22\u8D26\u53F7 / \u7528\u6237\u540D",
3290
+ onKeyDown: (e) => {
3291
+ if (e.key === "Enter") handleSearch();
3292
+ }
3293
+ }
3294
+ ),
3295
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
3296
+ "select",
3297
+ {
3298
+ style: styles4.select,
3299
+ value: enabledFilter,
3300
+ onChange: (e) => {
3301
+ setPageToken("");
3302
+ setEnabledFilter(e.target.value);
3303
+ },
3304
+ children: [
3305
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "all", children: "\u5168\u90E8\u72B6\u6001" }),
3306
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "true", children: "\u5DF2\u542F\u7528" }),
3307
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "false", children: "\u5DF2\u7981\u7528" })
3308
+ ]
3309
+ }
3310
+ ),
3311
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", style: styles4.secondaryBtn, onClick: handleSearch, children: "\u67E5\u8BE2" }),
3312
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3313
+ "button",
3314
+ {
3315
+ type: "button",
3316
+ style: styles4.secondaryBtn,
3317
+ onClick: () => {
3318
+ setKeywordInput("");
3319
+ setKeyword("");
3320
+ setEnabledFilter("all");
3321
+ setPageToken("");
3322
+ },
3323
+ children: "\u91CD\u7F6E"
3324
+ }
3325
+ )
3326
+ ] }),
3327
+ error ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: styles4.error, children: error }) : null,
3328
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: styles4.tableWrap, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("table", { style: styles4.table, children: [
3329
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("tr", { children: [
3330
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("th", { style: styles4.th, children: "\u8D26\u53F7" }),
3331
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("th", { style: styles4.th, children: "\u7528\u6237\u540D" }),
3332
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("th", { style: styles4.th, children: "\u5F52\u5C5E\u90E8\u95E8" }),
3333
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("th", { style: styles4.th, children: "\u7528\u6237\u89D2\u8272" }),
3334
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("th", { style: { ...styles4.th, width: 90 }, children: "\u72B6\u6001" }),
3335
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("th", { style: { ...styles4.th, width: 140 }, children: "\u64CD\u4F5C" })
3336
+ ] }) }),
3337
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("tbody", { children: loading ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { colSpan: 6, style: styles4.empty, children: "\u52A0\u8F7D\u4E2D\u2026" }) }) : records.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { colSpan: 6, style: styles4.empty, children: "\u6682\u65E0\u6570\u636E" }) }) : records.map((row) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("tr", { children: [
3338
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { style: styles4.td, children: row.username }),
3339
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { style: styles4.td, children: row.name }),
3340
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { style: styles4.td, children: groupLabel(row) }),
3341
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { style: styles4.td, children: roleLabel(row) }),
3342
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { style: styles4.td, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3343
+ "span",
3344
+ {
3345
+ style: {
3346
+ ...styles4.badge,
3347
+ ...row.enabled ? styles4.badgeOn : styles4.badgeOff
3348
+ },
3349
+ children: row.enabled ? "\u542F\u7528" : "\u7981\u7528"
3350
+ }
3351
+ ) }),
3352
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("td", { style: styles4.td, children: [
3353
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", style: styles4.linkBtn, onClick: () => openEdit(row), children: "\u7F16\u8F91" }),
3354
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3355
+ "button",
3356
+ {
3357
+ type: "button",
3358
+ style: { ...styles4.linkBtn, color: "#d92d20" },
3359
+ onClick: () => askDelete(row),
3360
+ children: "\u5220\u9664"
3361
+ }
3362
+ )
3363
+ ] })
3364
+ ] }, row.userId)) })
3365
+ ] }) }),
3366
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: styles4.pagination, children: [
3367
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { style: styles4.pageSize, children: [
3368
+ "\u6BCF\u9875",
3369
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3370
+ "select",
3371
+ {
3372
+ value: pageSize,
3373
+ onChange: (e) => {
3374
+ setPageToken("");
3375
+ setPageSize(e.target.value);
3376
+ },
3377
+ style: styles4.select,
3378
+ children: PAGE_SIZE_OPTIONS4.map((size) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: size, children: size }, size))
3379
+ }
3380
+ )
3381
+ ] }),
3382
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: styles4.pageBtns, children: [
3383
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3384
+ "button",
3385
+ {
3386
+ type: "button",
3387
+ style: styles4.secondaryBtn,
3388
+ disabled: !hasPreviousPage || loading,
3389
+ onClick: () => void loadList("previous"),
3390
+ children: "\u4E0A\u4E00\u9875"
3391
+ }
3392
+ ),
3393
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3394
+ "button",
3395
+ {
3396
+ type: "button",
3397
+ style: styles4.secondaryBtn,
3398
+ disabled: !hasNextPage || loading,
3399
+ onClick: () => void loadList("next"),
3400
+ children: "\u4E0B\u4E00\u9875"
3401
+ }
3402
+ )
3403
+ ] })
3404
+ ] }),
3405
+ dialogOpen ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: styles4.mask, onClick: closeDialog, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
3406
+ "div",
3407
+ {
3408
+ style: { ...styles4.dialog, maxWidth: 560 },
3409
+ onClick: (e) => e.stopPropagation(),
3410
+ role: "dialog",
3411
+ "aria-modal": "true",
3412
+ children: [
3413
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: styles4.dialogHeader, children: [
3414
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h3", { style: styles4.dialogTitle, children: editing ? "\u7F16\u8F91\u7528\u6237" : "\u65B0\u589E\u7528\u6237" }),
3415
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", style: styles4.iconBtn, onClick: closeDialog, "aria-label": "\u5173\u95ED", children: "\xD7" })
3416
+ ] }),
3417
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("form", { style: styles4.form, onSubmit: (e) => void handleSubmit(e), children: [
3418
+ formError ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: styles4.error, children: formError }) : null,
3419
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { style: styles4.field, children: [
3420
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: styles4.label, children: "\u8D26\u53F7" }),
3421
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3422
+ "input",
3423
+ {
3424
+ style: styles4.input,
3425
+ value: form.username,
3426
+ onChange: (e) => setForm((prev) => ({ ...prev, username: e.target.value })),
3427
+ placeholder: "\u81F3\u5C116\u4F4D\uFF0C\u9700\u542B\u5B57\u6BCD\u548C\u6570\u5B57",
3428
+ required: true
3429
+ }
3430
+ )
3431
+ ] }),
3432
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { style: styles4.field, children: [
3433
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: styles4.label, children: "\u7528\u6237\u540D" }),
3434
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3435
+ "input",
3436
+ {
3437
+ style: styles4.input,
3438
+ value: form.name,
3439
+ onChange: (e) => setForm((prev) => ({ ...prev, name: e.target.value })),
3440
+ placeholder: "\u8BF7\u8F93\u5165\u7528\u6237\u540D",
3441
+ required: true
3442
+ }
3443
+ )
3444
+ ] }),
3445
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { style: styles4.field, children: [
3446
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: styles4.label, children: editing ? "\u5BC6\u7801\uFF08\u7559\u7A7A\u5219\u4E0D\u4FEE\u6539\uFF09" : "\u521D\u59CB\u5BC6\u7801" }),
3447
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3448
+ "input",
3449
+ {
3450
+ style: styles4.input,
3451
+ type: "password",
3452
+ value: form.password,
3453
+ onChange: (e) => setForm((prev) => ({ ...prev, password: e.target.value })),
3454
+ placeholder: editing ? "\u7559\u7A7A\u8868\u793A\u4E0D\u4FEE\u6539\u5BC6\u7801" : "\u8BF7\u8F93\u5165\u521D\u59CB\u5BC6\u7801",
3455
+ required: !editing,
3456
+ autoComplete: "new-password"
3457
+ }
3458
+ )
3459
+ ] }),
3460
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("fieldset", { style: styles4.fieldset, children: [
3461
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("legend", { style: styles4.label, children: "\u5F52\u5C5E\u90E8\u95E8" }),
3462
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: styles4.multiSelect, children: optionsLoading ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: styles4.hint, children: "\u52A0\u8F7D\u4E2D\u2026" }) : groups.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: styles4.hint, children: "\u6682\u65E0\u90E8\u95E8\u6570\u636E" }) : groups.map((g) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { style: styles4.checkItem, children: [
3463
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3464
+ "input",
3465
+ {
3466
+ type: "checkbox",
3467
+ style: styles4.control,
3468
+ checked: form.groupIds.includes(g.groupId),
3469
+ onChange: () => toggleId("groupIds", g.groupId)
3470
+ }
3471
+ ),
3472
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: g.name || g.groupId })
3473
+ ] }, g.groupId)) })
3474
+ ] }),
3475
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("fieldset", { style: styles4.fieldset, children: [
3476
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("legend", { style: styles4.label, children: "\u7528\u6237\u89D2\u8272" }),
3477
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: styles4.multiSelect, children: optionsLoading ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: styles4.hint, children: "\u52A0\u8F7D\u4E2D\u2026" }) : roles.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: styles4.hint, children: "\u6682\u65E0\u89D2\u8272\u6570\u636E" }) : roles.map((r) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { style: styles4.checkItem, children: [
3478
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3479
+ "input",
3480
+ {
3481
+ type: "checkbox",
3482
+ style: styles4.control,
3483
+ checked: form.roleIds.includes(r.roleId),
3484
+ onChange: () => toggleId("roleIds", r.roleId)
3485
+ }
3486
+ ),
3487
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: r.name || r.roleId })
3488
+ ] }, r.roleId)) })
3489
+ ] }),
3490
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: styles4.switchRow, children: [
3491
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: styles4.label, children: "\u662F\u5426\u542F\u7528" }),
3492
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3493
+ "button",
3494
+ {
3495
+ type: "button",
3496
+ role: "switch",
3497
+ "aria-checked": form.enabled,
3498
+ style: {
3499
+ ...styles4.switchTrack,
3500
+ ...form.enabled ? styles4.switchTrackOn : null
3501
+ },
3502
+ onClick: () => setForm((prev) => ({ ...prev, enabled: !prev.enabled })),
3503
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3504
+ "span",
3505
+ {
3506
+ style: {
3507
+ ...styles4.switchThumb,
3508
+ ...form.enabled ? styles4.switchThumbOn : null
3509
+ }
3510
+ }
3511
+ )
3512
+ }
3513
+ )
3514
+ ] }),
3515
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: styles4.dialogFooter, children: [
3516
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", style: styles4.secondaryBtn, onClick: closeDialog, children: "\u53D6\u6D88" }),
3517
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "submit", style: styles4.primaryBtn, disabled: saving, children: saving ? "\u4FDD\u5B58\u4E2D\u2026" : "\u4FDD\u5B58" })
3518
+ ] })
3519
+ ] })
3520
+ ]
3521
+ }
3522
+ ) }) : null,
3523
+ deletingRow ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: styles4.mask, onClick: closeDeleteDialog, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
3524
+ "div",
3525
+ {
3526
+ style: { ...styles4.dialog, maxWidth: 420 },
3527
+ onClick: (e) => e.stopPropagation(),
3528
+ role: "dialog",
3529
+ "aria-modal": "true",
3530
+ children: [
3531
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: styles4.dialogHeader, children: [
3532
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h3", { style: styles4.dialogTitle, children: "\u786E\u8BA4\u5220\u9664" }),
3533
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3534
+ "button",
3535
+ {
3536
+ type: "button",
3537
+ style: styles4.iconBtn,
3538
+ onClick: closeDeleteDialog,
3539
+ "aria-label": "\u5173\u95ED",
3540
+ children: "\xD7"
3541
+ }
3542
+ )
3543
+ ] }),
3544
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: styles4.confirmBody, children: [
3545
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("p", { style: styles4.confirmText, children: [
3546
+ "\u786E\u8BA4\u5220\u9664\u7528\u6237\u300C",
3547
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { children: deletingRow.name }),
3548
+ "\u300D\uFF08",
3549
+ deletingRow.username,
3550
+ "\uFF09\u5417\uFF1F\u5220\u9664\u540E\u4E0D\u53EF\u6062\u590D\u3002"
3551
+ ] }),
3552
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: styles4.dialogFooter, children: [
3553
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3554
+ "button",
3555
+ {
3556
+ type: "button",
3557
+ style: styles4.secondaryBtn,
3558
+ onClick: closeDeleteDialog,
3559
+ disabled: deleting,
3560
+ children: "\u53D6\u6D88"
3561
+ }
3562
+ ),
3563
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3564
+ "button",
3565
+ {
3566
+ type: "button",
3567
+ style: styles4.dangerBtn,
3568
+ onClick: () => void confirmDelete(),
3569
+ disabled: deleting,
3570
+ children: deleting ? "\u5220\u9664\u4E2D\u2026" : "\u786E\u8BA4\u5220\u9664"
3571
+ }
3572
+ )
3573
+ ] })
3574
+ ] })
3575
+ ]
3576
+ }
3577
+ ) }) : null
3578
+ ] });
3579
+ }
3580
+ var styles4 = {
3581
+ root: {
3582
+ display: "flex",
3583
+ flexDirection: "column",
3584
+ gap: 16,
3585
+ padding: 16,
3586
+ color: "#101828",
3587
+ fontFamily: '"PingFang SC", "Microsoft YaHei", -apple-system, BlinkMacSystemFont, sans-serif'
3588
+ },
3589
+ toolbar: {
3590
+ display: "flex",
3591
+ alignItems: "center",
3592
+ justifyContent: "space-between",
3593
+ gap: 12
3594
+ },
3595
+ title: { margin: 0, fontSize: 18, fontWeight: 600 },
3596
+ toolbarRight: { display: "flex", alignItems: "center", gap: 8 },
3597
+ searchBar: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" },
3598
+ error: {
3599
+ padding: "10px 12px",
3600
+ borderRadius: 8,
3601
+ background: "#fef3f2",
3602
+ color: "#b42318",
3603
+ fontSize: 13
3604
+ },
3605
+ tableWrap: {
3606
+ overflow: "auto",
3607
+ border: "1px solid #eaecf0",
3608
+ borderRadius: 10,
3609
+ background: "#fff"
3610
+ },
3611
+ table: { width: "100%", borderCollapse: "collapse", minWidth: 720 },
3612
+ th: {
3613
+ textAlign: "left",
3614
+ padding: "12px 14px",
3615
+ fontSize: 13,
3616
+ fontWeight: 600,
3617
+ color: "#475467",
3618
+ background: "#f9fafb",
3619
+ borderBottom: "1px solid #eaecf0"
3620
+ },
3621
+ td: {
3622
+ padding: "12px 14px",
3623
+ fontSize: 14,
3624
+ borderBottom: "1px solid #f2f4f7",
3625
+ verticalAlign: "middle"
3626
+ },
3627
+ empty: { padding: 28, textAlign: "center", color: "#98a2b3", fontSize: 14 },
3628
+ linkBtn: {
3629
+ border: "none",
3630
+ background: "transparent",
3631
+ color: "#049BAD",
3632
+ cursor: "pointer",
3633
+ padding: "0 8px 0 0",
3634
+ fontSize: 13
3635
+ },
3636
+ badge: {
3637
+ display: "inline-block",
3638
+ padding: "2px 8px",
3639
+ borderRadius: 999,
3640
+ fontSize: 12,
3641
+ fontWeight: 500
3642
+ },
3643
+ badgeOn: { background: "#ecfdf3", color: "#027a48" },
3644
+ badgeOff: { background: "#f2f4f7", color: "#667085" },
3645
+ pagination: {
3646
+ display: "flex",
3647
+ alignItems: "center",
3648
+ justifyContent: "space-between",
3649
+ gap: 12
3650
+ },
3651
+ pageSize: { display: "flex", alignItems: "center", gap: 8, fontSize: 13, color: "#475467" },
3652
+ pageBtns: { display: "flex", gap: 8 },
3653
+ primaryBtn: {
3654
+ border: "none",
3655
+ background: "#049BAD",
3656
+ color: "#fff",
3657
+ borderRadius: 8,
3658
+ padding: "8px 14px",
3659
+ cursor: "pointer",
3660
+ fontSize: 14
3661
+ },
3662
+ secondaryBtn: {
3663
+ border: "1px solid #d0d5dd",
3664
+ background: "#fff",
3665
+ color: "#344054",
3666
+ borderRadius: 8,
3667
+ padding: "8px 14px",
3668
+ cursor: "pointer",
3669
+ fontSize: 14
3670
+ },
3671
+ dangerBtn: {
3672
+ border: "none",
3673
+ background: "#d92d20",
3674
+ color: "#fff",
3675
+ borderRadius: 8,
3676
+ padding: "8px 14px",
3677
+ cursor: "pointer",
3678
+ fontSize: 14
3679
+ },
3680
+ select: {
3681
+ border: "1px solid #d0d5dd",
3682
+ borderRadius: 6,
3683
+ padding: "4px 8px",
3684
+ fontSize: 13,
3685
+ backgroundColor: "#ffffff",
3686
+ color: "#101828"
3687
+ },
3688
+ mask: {
3689
+ position: "fixed",
3690
+ inset: 0,
3691
+ background: "rgba(16, 24, 40, 0.45)",
3692
+ display: "flex",
3693
+ alignItems: "center",
3694
+ justifyContent: "center",
3695
+ zIndex: 1e3,
3696
+ padding: 16
3697
+ },
3698
+ dialog: {
3699
+ width: "100%",
3700
+ maxWidth: 480,
3701
+ background: "#fff",
3702
+ borderRadius: 12,
3703
+ boxShadow: "0 20px 40px rgba(16,24,40,0.18)",
3704
+ maxHeight: "90vh",
3705
+ overflow: "auto"
3706
+ },
3707
+ dialogHeader: {
3708
+ display: "flex",
3709
+ alignItems: "center",
3710
+ justifyContent: "space-between",
3711
+ padding: "14px 16px",
3712
+ borderBottom: "1px solid #eaecf0",
3713
+ position: "sticky",
3714
+ top: 0,
3715
+ background: "#fff",
3716
+ zIndex: 1
3717
+ },
3718
+ dialogTitle: { margin: 0, fontSize: 16, fontWeight: 600 },
3719
+ iconBtn: {
3720
+ border: "none",
3721
+ background: "transparent",
3722
+ fontSize: 22,
3723
+ lineHeight: 1,
3724
+ cursor: "pointer",
3725
+ color: "#667085"
3726
+ },
3727
+ form: { display: "flex", flexDirection: "column", gap: 12, padding: 16 },
3728
+ confirmBody: { display: "flex", flexDirection: "column", gap: 16, padding: 16 },
3729
+ confirmText: { margin: 0, fontSize: 14, color: "#344054", lineHeight: 1.6 },
3730
+ field: { display: "flex", flexDirection: "column", gap: 6 },
3731
+ fieldset: {
3732
+ border: "1px solid #eaecf0",
3733
+ borderRadius: 8,
3734
+ margin: 0,
3735
+ padding: "10px 12px 12px"
3736
+ },
3737
+ label: { fontSize: 13, color: "#344054", fontWeight: 500 },
3738
+ input: {
3739
+ border: "1px solid #d0d5dd",
3740
+ borderRadius: 8,
3741
+ padding: "8px 10px",
3742
+ fontSize: 14,
3743
+ outline: "none",
3744
+ backgroundColor: "#ffffff",
3745
+ color: "#101828",
3746
+ boxSizing: "border-box",
3747
+ width: "100%"
3748
+ },
3749
+ multiSelect: {
3750
+ display: "flex",
3751
+ flexDirection: "column",
3752
+ gap: 6,
3753
+ maxHeight: 160,
3754
+ overflow: "auto"
3755
+ },
3756
+ checkItem: {
3757
+ display: "flex",
3758
+ alignItems: "center",
3759
+ gap: 8,
3760
+ fontSize: 14,
3761
+ color: "#101828",
3762
+ cursor: "pointer"
3763
+ },
3764
+ control: {
3765
+ width: 16,
3766
+ height: 16,
3767
+ accentColor: "#049BAD",
3768
+ cursor: "pointer",
3769
+ colorScheme: "light",
3770
+ backgroundColor: "#ffffff"
3771
+ },
3772
+ hint: { fontSize: 13, color: "#98a2b3", padding: "4px 0" },
3773
+ switchRow: {
3774
+ display: "flex",
3775
+ alignItems: "center",
3776
+ justifyContent: "space-between",
3777
+ gap: 12
3778
+ },
3779
+ switchTrack: {
3780
+ width: 44,
3781
+ height: 24,
3782
+ borderRadius: 999,
3783
+ border: "none",
3784
+ padding: 2,
3785
+ background: "#d0d5dd",
3786
+ cursor: "pointer",
3787
+ position: "relative",
3788
+ transition: "background 0.15s ease"
3789
+ },
3790
+ switchTrackOn: { background: "#049BAD" },
3791
+ switchThumb: {
3792
+ display: "block",
3793
+ width: 20,
3794
+ height: 20,
3795
+ borderRadius: "50%",
3796
+ background: "#fff",
3797
+ boxShadow: "0 1px 2px rgba(16,24,40,0.2)",
3798
+ transform: "translateX(0)",
3799
+ transition: "transform 0.15s ease"
3800
+ },
3801
+ switchThumbOn: { transform: "translateX(20px)" },
3802
+ dialogFooter: {
3803
+ display: "flex",
3804
+ justifyContent: "flex-end",
3805
+ gap: 8,
3806
+ paddingTop: 4
3807
+ }
3808
+ };
3809
+
3810
+ // src/react/SystemAdmin.tsx
3811
+ var import_react6 = require("react");
3812
+
3813
+ // src/admin/menu.ts
3814
+ var SYSTEM_ADMIN_MENU = {
3815
+ key: "system",
3816
+ label: "\u7CFB\u7EDF\u7BA1\u7406",
3817
+ children: [
3818
+ { key: "menu", label: "\u83DC\u5355\u7BA1\u7406" },
3819
+ { key: "resource", label: "\u6743\u9650\u70B9\u7BA1\u7406" },
3820
+ { key: "role", label: "\u89D2\u8272\u7BA1\u7406" },
3821
+ { key: "user", label: "\u7528\u6237\u7BA1\u7406" }
3822
+ ]
3823
+ };
3824
+ var SYSTEM_ADMIN_DEFAULT_KEY = "menu";
3825
+
3826
+ // src/react/SystemAdmin.tsx
3827
+ var import_jsx_runtime6 = require("react/jsx-runtime");
3828
+ function SystemAdmin({
3829
+ menuApi,
3830
+ resourceApi,
3831
+ roleApi,
3832
+ userApi,
3833
+ defaultActiveKey = SYSTEM_ADMIN_DEFAULT_KEY,
3834
+ activeKey: controlledKey,
3835
+ onActiveKeyChange,
3836
+ title = SYSTEM_ADMIN_MENU.label,
3837
+ toolbarExtra
3838
+ }) {
3839
+ const [innerKey, setInnerKey] = (0, import_react6.useState)(defaultActiveKey);
3840
+ const activeKey = controlledKey ?? innerKey;
3841
+ const setActiveKey = (key) => {
3842
+ if (controlledKey === void 0) setInnerKey(key);
3843
+ onActiveKeyChange?.(key);
3844
+ };
3845
+ const activeLabel = (0, import_react6.useMemo)(
3846
+ () => SYSTEM_ADMIN_MENU.children.find((item) => item.key === activeKey)?.label ?? "",
3847
+ [activeKey]
3848
+ );
3849
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: styles5.root, children: [
3850
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("aside", { style: styles5.sidebar, children: [
3851
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: styles5.sidebarTitle, children: title }),
3852
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("nav", { style: styles5.nav, children: SYSTEM_ADMIN_MENU.children.map((item) => {
3853
+ const active = item.key === activeKey;
3854
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3855
+ "button",
3856
+ {
2904
3857
  type: "button",
2905
3858
  style: {
2906
- ...styles4.navItem,
2907
- ...active ? styles4.navItemActive : null
3859
+ ...styles5.navItem,
3860
+ ...active ? styles5.navItemActive : null
2908
3861
  },
2909
3862
  onClick: () => setActiveKey(item.key),
2910
3863
  children: item.label
@@ -2913,20 +3866,20 @@ function SystemAdmin({
2913
3866
  );
2914
3867
  }) })
2915
3868
  ] }),
2916
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("main", { style: styles4.content, children: [
2917
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: styles4.contentHeader, children: [
2918
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: styles4.breadcrumb, children: [
2919
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: styles4.breadcrumbParent, children: title }),
2920
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: styles4.breadcrumbSep, children: "/" }),
2921
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: styles4.breadcrumbCurrent, children: activeLabel })
3869
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("main", { style: styles5.content, children: [
3870
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: styles5.contentHeader, children: [
3871
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: styles5.breadcrumb, children: [
3872
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: styles5.breadcrumbParent, children: title }),
3873
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: styles5.breadcrumbSep, children: "/" }),
3874
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: styles5.breadcrumbCurrent, children: activeLabel })
2922
3875
  ] }),
2923
3876
  toolbarExtra
2924
3877
  ] }),
2925
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: styles4.panel, children: activeKey === "menu" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MenuManager, { api: menuApi, title: "\u83DC\u5355\u7BA1\u7406" }) : activeKey === "resource" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ResourceManager, { api: resourceApi, title: "\u6743\u9650\u70B9\u7BA1\u7406" }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(RoleManager, { api: roleApi, title: "\u89D2\u8272\u7BA1\u7406" }) })
3878
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: styles5.panel, children: activeKey === "menu" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MenuManager, { api: menuApi, title: "\u83DC\u5355\u7BA1\u7406" }) : activeKey === "resource" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ResourceManager, { api: resourceApi, title: "\u6743\u9650\u70B9\u7BA1\u7406" }) : activeKey === "role" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(RoleManager, { api: roleApi, title: "\u89D2\u8272\u7BA1\u7406" }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(UserManager, { api: userApi, title: "\u7528\u6237\u7BA1\u7406" }) })
2926
3879
  ] })
2927
3880
  ] });
2928
3881
  }
2929
- var styles4 = {
3882
+ var styles5 = {
2930
3883
  root: {
2931
3884
  display: "flex",
2932
3885
  minHeight: 560,
@@ -3027,34 +3980,47 @@ var styles4 = {
3027
3980
  SYSTEM_ADMIN_DEFAULT_KEY,
3028
3981
  SYSTEM_ADMIN_MENU,
3029
3982
  SystemAdmin,
3983
+ UserManager,
3030
3984
  appendQueryParam,
3031
3985
  buildCreateBody,
3032
3986
  buildCreateMenuBody,
3033
3987
  buildCreateRoleBody,
3988
+ buildCreateUserBody,
3989
+ buildPermissionTreeIndex,
3034
3990
  buildSavePermissionsBody,
3035
3991
  buildUpdateBody,
3036
3992
  buildUpdateMenuBody,
3037
3993
  buildUpdateRoleBody,
3994
+ buildUpdateUserBody,
3038
3995
  collectTreeResourceIds,
3996
+ countCheckedDescendants,
3039
3997
  createAuthorizationResourceApi,
3040
3998
  createDefaultResourceRequest,
3041
3999
  createMenuResourceApi,
3042
4000
  createPermissionStore,
3043
4001
  createSystemRoleApi,
4002
+ createSystemUserApi,
3044
4003
  extractPagination,
3045
4004
  extractRecords,
3046
4005
  getAppClientId,
3047
4006
  getDeviceWorkerId,
4007
+ hasCheckedDescendant,
3048
4008
  isMenuLeaf,
4009
+ isPermissionNodeIndeterminate,
3049
4010
  mapAuthorizationResource,
3050
4011
  mapMenuResource,
3051
4012
  mapPermissionTreeNode,
3052
4013
  mapRolePermissions,
4014
+ mapSystemGroupOption,
3053
4015
  mapSystemRole,
4016
+ mapSystemRoleOption,
4017
+ mapSystemUser,
3054
4018
  resolveMenuDepth,
3055
4019
  snowyflake,
4020
+ togglePermissionCheck,
3056
4021
  useHasPermission,
3057
4022
  useHasRole,
3058
- usePermission
4023
+ usePermission,
4024
+ validateUsername
3059
4025
  });
3060
4026
  //# sourceMappingURL=index.cjs.map