com-angel-authorization 1.0.4 → 1.0.6

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.
@@ -233,16 +233,35 @@ import {
233
233
 
234
234
  // src/resources/types.ts
235
235
  var RESOURCE_TYPE_API = "api";
236
+ var MENU_TYPE_PAGE = "page";
237
+ var MENU_TYPE_MENU = "menu";
238
+ var MENU_TYPE_BUTTON = "button";
239
+ var MENU_LIST_TYPE_PARAM = "page,menu,button";
240
+ var ROOT_PARENT_ID = "0";
236
241
  var RESOURCE_STATUS_ENABLED = 1;
237
242
  var RESOURCE_STATUS_DISABLED = 0;
238
243
  var RESOURCE_STATUS_OPTIONS = [
239
244
  { label: "\u542F\u7528", value: RESOURCE_STATUS_ENABLED },
240
245
  { label: "\u7981\u7528", value: RESOURCE_STATUS_DISABLED }
241
246
  ];
247
+ var MENU_VISIBILITY_OPTIONS = [
248
+ { label: "\u663E\u793A", value: RESOURCE_STATUS_ENABLED },
249
+ { label: "\u9690\u85CF", value: RESOURCE_STATUS_DISABLED }
250
+ ];
242
251
  var RESOURCE_PRIVATE_OPTIONS = [
243
252
  { label: "\u662F", value: true },
244
253
  { label: "\u5426", value: false }
245
254
  ];
255
+ var MENU_TYPE_OPTIONS = [
256
+ { label: "\u76EE\u5F55", value: MENU_TYPE_PAGE },
257
+ { label: "\u83DC\u5355", value: MENU_TYPE_MENU },
258
+ { label: "\u6309\u94AE", value: MENU_TYPE_BUTTON }
259
+ ];
260
+ var MENU_TYPE_LABEL = {
261
+ page: "\u76EE\u5F55",
262
+ menu: "\u83DC\u5355",
263
+ button: "\u6309\u94AE"
264
+ };
246
265
 
247
266
  // src/utils/snowflake.ts
248
267
  var DEVICE_WORKER_ID_KEY = "hgams_device_worker_id";
@@ -387,6 +406,29 @@ function toBoolean(value) {
387
406
  }
388
407
  return false;
389
408
  }
409
+ function toStringArray(value) {
410
+ if (Array.isArray(value)) {
411
+ return value.map((item) => {
412
+ if (item && typeof item === "object") {
413
+ const row = item;
414
+ const id = row.resourceId ?? row.resource_id ?? row.id;
415
+ return id === void 0 || id === null ? "" : String(id);
416
+ }
417
+ return String(item ?? "");
418
+ }).filter(Boolean);
419
+ }
420
+ if (typeof value === "string" && value.trim()) {
421
+ return value.split(",").map((s) => s.trim()).filter(Boolean);
422
+ }
423
+ return [];
424
+ }
425
+ function toMenuType(value) {
426
+ const v = String(value ?? "").toLowerCase();
427
+ if (v === MENU_TYPE_PAGE || v === MENU_TYPE_MENU || v === MENU_TYPE_BUTTON) {
428
+ return v;
429
+ }
430
+ return MENU_TYPE_MENU;
431
+ }
390
432
  function mapAuthorizationResource(item) {
391
433
  if (!item || typeof item !== "object") return null;
392
434
  const row = item;
@@ -402,9 +444,31 @@ function mapAuthorizationResource(item) {
402
444
  description: String(row.description ?? row.desc ?? "")
403
445
  };
404
446
  }
405
- function buildListUrl(params) {
447
+ function mapMenuResource(item) {
448
+ if (!item || typeof item !== "object") return null;
449
+ const row = item;
450
+ const resourceId = row.resourceId ?? row.resource_id ?? row.id;
451
+ if (resourceId === void 0 || resourceId === null || resourceId === "") return null;
452
+ const permissionPointIds = toStringArray(
453
+ row.permissionPointIds ?? row.permission_point_ids ?? row.permissionPoints ?? row.permissions
454
+ );
455
+ const permissionNamesRaw = row.permissionPointNames ?? row.permission_point_names ?? row.permissionNames;
456
+ const permissionPointNames = Array.isArray(permissionNamesRaw) ? permissionNamesRaw.map((n) => String(n ?? "")).filter(Boolean) : void 0;
457
+ const parentId = row.parentId ?? row.parent_id ?? ROOT_PARENT_ID;
458
+ return {
459
+ resourceId: String(resourceId),
460
+ parentId: parentId === void 0 || parentId === null ? ROOT_PARENT_ID : String(parentId),
461
+ type: toMenuType(row.type),
462
+ name: String(row.name ?? ""),
463
+ identification: String(row.identification ?? row.identity ?? row.path ?? ""),
464
+ permissionPointIds,
465
+ permissionPointNames,
466
+ status: toResourceStatus(row.status)
467
+ };
468
+ }
469
+ function buildListUrl(type, params) {
406
470
  const parts = [];
407
- appendQueryParam(parts, "type", RESOURCE_TYPE_API);
471
+ appendQueryParam(parts, "type", type);
408
472
  appendQueryParam(parts, "page-token", params?.pagination?.pageToken ?? "");
409
473
  appendQueryParam(parts, "page-size", params?.pagination?.pageSize ?? "20");
410
474
  appendQueryParam(parts, "page-direction", params?.pagination?.pageDirection ?? "current");
@@ -431,12 +495,33 @@ function buildUpdateBody(values) {
431
495
  description: values.description.trim()
432
496
  };
433
497
  }
498
+ function buildCreateMenuBody(values, resourceId = getAppClientId()) {
499
+ return {
500
+ resourceId,
501
+ parentId: values.parentId || ROOT_PARENT_ID,
502
+ type: values.type,
503
+ name: values.name.trim(),
504
+ identification: values.identification.trim(),
505
+ permissionPointIds: [...values.permissionPointIds],
506
+ status: values.status
507
+ };
508
+ }
509
+ function buildUpdateMenuBody(values) {
510
+ return {
511
+ parentId: values.parentId || ROOT_PARENT_ID,
512
+ type: values.type,
513
+ name: values.name.trim(),
514
+ identification: values.identification.trim(),
515
+ permissionPointIds: [...values.permissionPointIds],
516
+ status: values.status
517
+ };
518
+ }
434
519
  function createAuthorizationResourceApi(request) {
435
520
  return {
436
521
  async list(params, signal) {
437
522
  const json = await request({
438
523
  method: "GET",
439
- url: buildListUrl(params),
524
+ url: buildListUrl(RESOURCE_TYPE_API, params),
440
525
  signal
441
526
  });
442
527
  const records = extractRecords(json).map(mapAuthorizationResource).filter((item) => item !== null);
@@ -471,6 +556,50 @@ function createAuthorizationResourceApi(request) {
471
556
  }
472
557
  };
473
558
  }
559
+ function createMenuResourceApi(request) {
560
+ const permissionApi = createAuthorizationResourceApi(request);
561
+ return {
562
+ async list(params, signal) {
563
+ const json = await request({
564
+ method: "GET",
565
+ url: buildListUrl(MENU_LIST_TYPE_PARAM, params),
566
+ signal
567
+ });
568
+ const records = extractRecords(json).map(mapMenuResource).filter((item) => item !== null);
569
+ const pagination = extractPagination(json);
570
+ return {
571
+ records,
572
+ ...pagination
573
+ };
574
+ },
575
+ listPermissionPoints(params, signal) {
576
+ return permissionApi.list(params, signal);
577
+ },
578
+ async create(values, signal) {
579
+ return request({
580
+ method: "POST",
581
+ url: "/authorization-resources",
582
+ body: buildCreateMenuBody(values),
583
+ signal
584
+ });
585
+ },
586
+ async update(resourceId, values, signal) {
587
+ return request({
588
+ method: "PATCH",
589
+ url: `/authorization-resources/${encodeURIComponent(resourceId)}`,
590
+ body: buildUpdateMenuBody(values),
591
+ signal
592
+ });
593
+ },
594
+ async remove(resourceId, signal) {
595
+ return request({
596
+ method: "DELETE",
597
+ url: `/authorization-resources/${encodeURIComponent(resourceId)}`,
598
+ signal
599
+ });
600
+ }
601
+ };
602
+ }
474
603
  function createDefaultResourceRequest(options = {}) {
475
604
  const baseUrl = (options.baseUrl ?? "").replace(/\/+$/, "");
476
605
  const credentials = options.credentials ?? "include";
@@ -537,6 +666,8 @@ function ResourceManager({
537
666
  const [editing, setEditing] = useState2(null);
538
667
  const [form, setForm] = useState2(emptyForm);
539
668
  const [saving, setSaving] = useState2(false);
669
+ const [deletingRow, setDeletingRow] = useState2(null);
670
+ const [deleting, setDeleting] = useState2(false);
540
671
  const loadList = useCallback2(
541
672
  async (direction = "current", token = pageToken) => {
542
673
  setLoading(true);
@@ -610,14 +741,25 @@ function ResourceManager({
610
741
  setSaving(false);
611
742
  }
612
743
  };
613
- const handleDelete = async (row) => {
614
- if (!window.confirm(`\u786E\u8BA4\u5220\u9664\u6743\u9650\u70B9\u300C${row.name}\u300D\uFF1F`)) return;
744
+ const askDelete = (row) => {
745
+ setDeletingRow(row);
746
+ };
747
+ const closeDeleteDialog = () => {
748
+ if (deleting) return;
749
+ setDeletingRow(null);
750
+ };
751
+ const confirmDelete = async () => {
752
+ if (!deletingRow) return;
753
+ setDeleting(true);
615
754
  setError("");
616
755
  try {
617
- await api.remove(row.resourceId);
756
+ await api.remove(deletingRow.resourceId);
757
+ setDeletingRow(null);
618
758
  await loadList("current", "");
619
759
  } catch (err) {
620
760
  setError(err instanceof Error ? err.message : "\u5220\u9664\u5931\u8D25");
761
+ } finally {
762
+ setDeleting(false);
621
763
  }
622
764
  };
623
765
  const statusLabel = useMemo2(
@@ -663,7 +805,7 @@ function ResourceManager({
663
805
  {
664
806
  type: "button",
665
807
  style: { ...styles.linkBtn, color: "#d92d20" },
666
- onClick: () => void handleDelete(row),
808
+ onClick: () => askDelete(row),
667
809
  children: "\u5220\u9664"
668
810
  }
669
811
  )
@@ -794,6 +936,60 @@ function ResourceManager({
794
936
  ] })
795
937
  ]
796
938
  }
939
+ ) }) : null,
940
+ deletingRow ? /* @__PURE__ */ jsx2("div", { style: styles.mask, onClick: closeDeleteDialog, children: /* @__PURE__ */ jsxs(
941
+ "div",
942
+ {
943
+ style: { ...styles.dialog, maxWidth: 420 },
944
+ onClick: (e) => e.stopPropagation(),
945
+ role: "dialog",
946
+ "aria-modal": "true",
947
+ "aria-labelledby": "angel-auth-delete-title",
948
+ children: [
949
+ /* @__PURE__ */ jsxs("div", { style: styles.dialogHeader, children: [
950
+ /* @__PURE__ */ jsx2("h3", { id: "angel-auth-delete-title", style: styles.dialogTitle, children: "\u786E\u8BA4\u5220\u9664" }),
951
+ /* @__PURE__ */ jsx2(
952
+ "button",
953
+ {
954
+ type: "button",
955
+ style: styles.iconBtn,
956
+ onClick: closeDeleteDialog,
957
+ "aria-label": "\u5173\u95ED",
958
+ children: "\xD7"
959
+ }
960
+ )
961
+ ] }),
962
+ /* @__PURE__ */ jsxs("div", { style: styles.confirmBody, children: [
963
+ /* @__PURE__ */ jsxs("p", { style: styles.confirmText, children: [
964
+ "\u786E\u8BA4\u5220\u9664\u6743\u9650\u70B9\u300C",
965
+ /* @__PURE__ */ jsx2("strong", { children: deletingRow.name }),
966
+ "\u300D\u5417\uFF1F\u5220\u9664\u540E\u4E0D\u53EF\u6062\u590D\u3002"
967
+ ] }),
968
+ /* @__PURE__ */ jsxs("div", { style: styles.dialogFooter, children: [
969
+ /* @__PURE__ */ jsx2(
970
+ "button",
971
+ {
972
+ type: "button",
973
+ style: styles.secondaryBtn,
974
+ onClick: closeDeleteDialog,
975
+ disabled: deleting,
976
+ children: "\u53D6\u6D88"
977
+ }
978
+ ),
979
+ /* @__PURE__ */ jsx2(
980
+ "button",
981
+ {
982
+ type: "button",
983
+ style: styles.dangerBtn,
984
+ onClick: () => void confirmDelete(),
985
+ disabled: deleting,
986
+ children: deleting ? "\u5220\u9664\u4E2D\u2026" : "\u786E\u8BA4\u5220\u9664"
987
+ }
988
+ )
989
+ ] })
990
+ ] })
991
+ ]
992
+ }
797
993
  ) }) : null
798
994
  ] });
799
995
  }
@@ -897,11 +1093,22 @@ var styles = {
897
1093
  cursor: "pointer",
898
1094
  fontSize: 14
899
1095
  },
1096
+ dangerBtn: {
1097
+ border: "none",
1098
+ background: "#d92d20",
1099
+ color: "#fff",
1100
+ borderRadius: 8,
1101
+ padding: "8px 14px",
1102
+ cursor: "pointer",
1103
+ fontSize: 14
1104
+ },
900
1105
  select: {
901
1106
  border: "1px solid #d0d5dd",
902
1107
  borderRadius: 6,
903
1108
  padding: "4px 8px",
904
- fontSize: 13
1109
+ fontSize: 13,
1110
+ backgroundColor: "#ffffff",
1111
+ color: "#101828"
905
1112
  },
906
1113
  mask: {
907
1114
  position: "fixed",
@@ -937,15 +1144,648 @@ var styles = {
937
1144
  color: "#667085"
938
1145
  },
939
1146
  form: { display: "flex", flexDirection: "column", gap: 12, padding: 16 },
1147
+ confirmBody: { display: "flex", flexDirection: "column", gap: 16, padding: 16 },
1148
+ confirmText: { margin: 0, fontSize: 14, color: "#344054", lineHeight: 1.6 },
1149
+ field: { display: "flex", flexDirection: "column", gap: 6 },
1150
+ label: { fontSize: 13, color: "#344054", fontWeight: 500 },
1151
+ input: {
1152
+ border: "1px solid #d0d5dd",
1153
+ borderRadius: 8,
1154
+ padding: "8px 10px",
1155
+ fontSize: 14,
1156
+ outline: "none",
1157
+ backgroundColor: "#ffffff",
1158
+ color: "#101828",
1159
+ boxSizing: "border-box",
1160
+ width: "100%"
1161
+ },
1162
+ dialogFooter: {
1163
+ display: "flex",
1164
+ justifyContent: "flex-end",
1165
+ gap: 8,
1166
+ paddingTop: 4
1167
+ }
1168
+ };
1169
+
1170
+ // src/react/MenuManager.tsx
1171
+ import {
1172
+ useCallback as useCallback3,
1173
+ useEffect as useEffect3,
1174
+ useMemo as useMemo3,
1175
+ useState as useState3
1176
+ } from "react";
1177
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
1178
+ var PAGE_SIZE_OPTIONS2 = ["10", "20", "50", "100"];
1179
+ var emptyForm2 = () => ({
1180
+ parentId: ROOT_PARENT_ID,
1181
+ type: MENU_TYPE_MENU,
1182
+ name: "",
1183
+ identification: "",
1184
+ permissionPointIds: [],
1185
+ status: RESOURCE_STATUS_ENABLED
1186
+ });
1187
+ function MenuManager({
1188
+ api,
1189
+ title = "\u83DC\u5355\u7BA1\u7406",
1190
+ pageSize: initialPageSize = "20",
1191
+ toolbarExtra
1192
+ }) {
1193
+ const [records, setRecords] = useState3([]);
1194
+ const [permissionPoints, setPermissionPoints] = useState3([]);
1195
+ const [loading, setLoading] = useState3(false);
1196
+ const [error, setError] = useState3("");
1197
+ const [pageSize, setPageSize] = useState3(initialPageSize);
1198
+ const [pageToken, setPageToken] = useState3("");
1199
+ const [hasPreviousPage, setHasPreviousPage] = useState3(false);
1200
+ const [hasNextPage, setHasNextPage] = useState3(false);
1201
+ const [dialogOpen, setDialogOpen] = useState3(false);
1202
+ const [editing, setEditing] = useState3(null);
1203
+ const [form, setForm] = useState3(emptyForm2);
1204
+ const [saving, setSaving] = useState3(false);
1205
+ const [deletingRow, setDeletingRow] = useState3(null);
1206
+ const [deleting, setDeleting] = useState3(false);
1207
+ const permissionNameMap = useMemo3(() => {
1208
+ const map = /* @__PURE__ */ new Map();
1209
+ permissionPoints.forEach((p) => map.set(p.resourceId, p.name || p.identification));
1210
+ return map;
1211
+ }, [permissionPoints]);
1212
+ const parentOptions = useMemo3(() => {
1213
+ return records.filter((row) => !editing || row.resourceId !== editing.resourceId).map((row) => ({
1214
+ value: row.resourceId,
1215
+ label: `${row.name}\uFF08${MENU_TYPE_LABEL[row.type]}\uFF09`
1216
+ }));
1217
+ }, [records, editing]);
1218
+ const loadList = useCallback3(
1219
+ async (direction = "current", token = pageToken) => {
1220
+ setLoading(true);
1221
+ setError("");
1222
+ try {
1223
+ const result = await api.list({
1224
+ pagination: {
1225
+ pageToken: token,
1226
+ pageSize,
1227
+ pageDirection: direction
1228
+ }
1229
+ });
1230
+ setRecords(result.records);
1231
+ setPageToken(result.pageToken);
1232
+ setHasPreviousPage(result.hasPreviousPage);
1233
+ setHasNextPage(result.hasNextPage);
1234
+ } catch (err) {
1235
+ setError(err instanceof Error ? err.message : "\u52A0\u8F7D\u5931\u8D25");
1236
+ } finally {
1237
+ setLoading(false);
1238
+ }
1239
+ },
1240
+ [api, pageSize, pageToken]
1241
+ );
1242
+ const loadPermissionPoints = useCallback3(async () => {
1243
+ try {
1244
+ const result = await api.listPermissionPoints({
1245
+ pagination: { pageSize: "200", pageDirection: "current" }
1246
+ });
1247
+ setPermissionPoints(result.records);
1248
+ } catch {
1249
+ }
1250
+ }, [api]);
1251
+ useEffect3(() => {
1252
+ void loadList("current", "");
1253
+ void loadPermissionPoints();
1254
+ }, [api, pageSize]);
1255
+ const openCreate = () => {
1256
+ setEditing(null);
1257
+ setForm(emptyForm2());
1258
+ setDialogOpen(true);
1259
+ void loadPermissionPoints();
1260
+ };
1261
+ const openEdit = (row) => {
1262
+ setEditing(row);
1263
+ setForm({
1264
+ parentId: row.parentId || ROOT_PARENT_ID,
1265
+ type: row.type,
1266
+ name: row.name,
1267
+ identification: row.identification,
1268
+ permissionPointIds: [...row.permissionPointIds],
1269
+ status: row.status
1270
+ });
1271
+ setDialogOpen(true);
1272
+ void loadPermissionPoints();
1273
+ };
1274
+ const closeDialog = () => {
1275
+ if (saving) return;
1276
+ setDialogOpen(false);
1277
+ };
1278
+ const handleSubmit = async (event) => {
1279
+ event.preventDefault();
1280
+ if (!form.name.trim()) {
1281
+ setError("\u8BF7\u586B\u5199\u83DC\u5355\u540D\u79F0");
1282
+ return;
1283
+ }
1284
+ setSaving(true);
1285
+ setError("");
1286
+ try {
1287
+ if (editing) {
1288
+ await api.update(editing.resourceId, form);
1289
+ } else {
1290
+ await api.create(form);
1291
+ }
1292
+ setDialogOpen(false);
1293
+ await loadList("current", "");
1294
+ } catch (err) {
1295
+ setError(err instanceof Error ? err.message : "\u4FDD\u5B58\u5931\u8D25");
1296
+ } finally {
1297
+ setSaving(false);
1298
+ }
1299
+ };
1300
+ const askDelete = (row) => setDeletingRow(row);
1301
+ const closeDeleteDialog = () => {
1302
+ if (!deleting) setDeletingRow(null);
1303
+ };
1304
+ const confirmDelete = async () => {
1305
+ if (!deletingRow) return;
1306
+ setDeleting(true);
1307
+ setError("");
1308
+ try {
1309
+ await api.remove(deletingRow.resourceId);
1310
+ setDeletingRow(null);
1311
+ await loadList("current", "");
1312
+ } catch (err) {
1313
+ setError(err instanceof Error ? err.message : "\u5220\u9664\u5931\u8D25");
1314
+ } finally {
1315
+ setDeleting(false);
1316
+ }
1317
+ };
1318
+ const togglePermission = (id) => {
1319
+ setForm((prev) => {
1320
+ const exists = prev.permissionPointIds.includes(id);
1321
+ return {
1322
+ ...prev,
1323
+ permissionPointIds: exists ? prev.permissionPointIds.filter((x) => x !== id) : [...prev.permissionPointIds, id]
1324
+ };
1325
+ });
1326
+ };
1327
+ const renderPermissionLabels = (row) => {
1328
+ if (row.permissionPointNames?.length) {
1329
+ return row.permissionPointNames.join("\u3001");
1330
+ }
1331
+ if (!row.permissionPointIds.length) return "\u2014";
1332
+ return row.permissionPointIds.map((id) => permissionNameMap.get(id) ?? id).join("\u3001");
1333
+ };
1334
+ return /* @__PURE__ */ jsxs2("div", { style: styles2.root, children: [
1335
+ /* @__PURE__ */ jsxs2("div", { style: styles2.toolbar, children: [
1336
+ /* @__PURE__ */ jsx3("h2", { style: styles2.title, children: title }),
1337
+ /* @__PURE__ */ jsxs2("div", { style: styles2.toolbarRight, children: [
1338
+ toolbarExtra,
1339
+ /* @__PURE__ */ jsx3("button", { type: "button", style: styles2.primaryBtn, onClick: openCreate, children: "\u65B0\u589E" })
1340
+ ] })
1341
+ ] }),
1342
+ error ? /* @__PURE__ */ jsx3("div", { style: styles2.error, children: error }) : null,
1343
+ /* @__PURE__ */ jsx3("div", { style: styles2.tableWrap, children: /* @__PURE__ */ jsxs2("table", { style: styles2.table, children: [
1344
+ /* @__PURE__ */ jsx3("thead", { children: /* @__PURE__ */ jsxs2("tr", { children: [
1345
+ /* @__PURE__ */ jsx3("th", { style: styles2.th, children: "\u83DC\u5355\u540D\u79F0" }),
1346
+ /* @__PURE__ */ jsx3("th", { style: styles2.th, children: "\u8BF7\u6C42\u5730\u5740" }),
1347
+ /* @__PURE__ */ jsx3("th", { style: { ...styles2.th, width: 90 }, children: "\u7C7B\u578B" }),
1348
+ /* @__PURE__ */ jsx3("th", { style: { ...styles2.th, width: 80 }, children: "\u53EF\u89C1" }),
1349
+ /* @__PURE__ */ jsx3("th", { style: styles2.th, children: "\u6743\u9650\u6807\u8BC6" }),
1350
+ /* @__PURE__ */ jsx3("th", { style: { ...styles2.th, width: 140 }, children: "\u64CD\u4F5C" })
1351
+ ] }) }),
1352
+ /* @__PURE__ */ jsx3("tbody", { children: loading ? /* @__PURE__ */ jsx3("tr", { children: /* @__PURE__ */ jsx3("td", { colSpan: 6, style: styles2.empty, children: "\u52A0\u8F7D\u4E2D\u2026" }) }) : records.length === 0 ? /* @__PURE__ */ jsx3("tr", { children: /* @__PURE__ */ jsx3("td", { colSpan: 6, style: styles2.empty, children: "\u6682\u65E0\u6570\u636E" }) }) : records.map((row) => /* @__PURE__ */ jsxs2("tr", { children: [
1353
+ /* @__PURE__ */ jsx3("td", { style: styles2.td, children: row.name }),
1354
+ /* @__PURE__ */ jsx3("td", { style: styles2.td, children: /* @__PURE__ */ jsx3("code", { style: styles2.code, children: row.identification || "\u2014" }) }),
1355
+ /* @__PURE__ */ jsx3("td", { style: styles2.td, children: MENU_TYPE_LABEL[row.type] }),
1356
+ /* @__PURE__ */ jsx3("td", { style: styles2.td, children: /* @__PURE__ */ jsx3(
1357
+ "span",
1358
+ {
1359
+ style: {
1360
+ ...styles2.badge,
1361
+ background: row.status === RESOURCE_STATUS_ENABLED ? "#e8f7ef" : "#f4f4f5",
1362
+ color: row.status === RESOURCE_STATUS_ENABLED ? "#067647" : "#667085"
1363
+ },
1364
+ children: row.status === RESOURCE_STATUS_ENABLED ? "\u663E\u793A" : "\u9690\u85CF"
1365
+ }
1366
+ ) }),
1367
+ /* @__PURE__ */ jsx3("td", { style: styles2.td, children: renderPermissionLabels(row) }),
1368
+ /* @__PURE__ */ jsxs2("td", { style: styles2.td, children: [
1369
+ /* @__PURE__ */ jsx3("button", { type: "button", style: styles2.linkBtn, onClick: () => openEdit(row), children: "\u7F16\u8F91" }),
1370
+ /* @__PURE__ */ jsx3(
1371
+ "button",
1372
+ {
1373
+ type: "button",
1374
+ style: { ...styles2.linkBtn, color: "#d92d20" },
1375
+ onClick: () => askDelete(row),
1376
+ children: "\u5220\u9664"
1377
+ }
1378
+ )
1379
+ ] })
1380
+ ] }, row.resourceId)) })
1381
+ ] }) }),
1382
+ /* @__PURE__ */ jsxs2("div", { style: styles2.pagination, children: [
1383
+ /* @__PURE__ */ jsxs2("label", { style: styles2.pageSize, children: [
1384
+ "\u6BCF\u9875",
1385
+ /* @__PURE__ */ jsx3(
1386
+ "select",
1387
+ {
1388
+ value: pageSize,
1389
+ onChange: (e) => {
1390
+ setPageToken("");
1391
+ setPageSize(e.target.value);
1392
+ },
1393
+ style: styles2.select,
1394
+ children: PAGE_SIZE_OPTIONS2.map((size) => /* @__PURE__ */ jsx3("option", { value: size, children: size }, size))
1395
+ }
1396
+ )
1397
+ ] }),
1398
+ /* @__PURE__ */ jsxs2("div", { style: styles2.pageBtns, children: [
1399
+ /* @__PURE__ */ jsx3(
1400
+ "button",
1401
+ {
1402
+ type: "button",
1403
+ style: styles2.secondaryBtn,
1404
+ disabled: !hasPreviousPage || loading,
1405
+ onClick: () => void loadList("previous"),
1406
+ children: "\u4E0A\u4E00\u9875"
1407
+ }
1408
+ ),
1409
+ /* @__PURE__ */ jsx3(
1410
+ "button",
1411
+ {
1412
+ type: "button",
1413
+ style: styles2.secondaryBtn,
1414
+ disabled: !hasNextPage || loading,
1415
+ onClick: () => void loadList("next"),
1416
+ children: "\u4E0B\u4E00\u9875"
1417
+ }
1418
+ )
1419
+ ] })
1420
+ ] }),
1421
+ dialogOpen ? /* @__PURE__ */ jsx3("div", { style: styles2.mask, onClick: closeDialog, children: /* @__PURE__ */ jsxs2(
1422
+ "div",
1423
+ {
1424
+ style: { ...styles2.dialog, maxWidth: 520 },
1425
+ onClick: (e) => e.stopPropagation(),
1426
+ role: "dialog",
1427
+ "aria-modal": "true",
1428
+ children: [
1429
+ /* @__PURE__ */ jsxs2("div", { style: styles2.dialogHeader, children: [
1430
+ /* @__PURE__ */ jsx3("h3", { style: styles2.dialogTitle, children: editing ? "\u7F16\u8F91\u83DC\u5355" : "\u65B0\u589E\u83DC\u5355" }),
1431
+ /* @__PURE__ */ jsx3("button", { type: "button", style: styles2.iconBtn, onClick: closeDialog, "aria-label": "\u5173\u95ED", children: "\xD7" })
1432
+ ] }),
1433
+ /* @__PURE__ */ jsxs2("form", { style: styles2.form, onSubmit: (e) => void handleSubmit(e), children: [
1434
+ /* @__PURE__ */ jsxs2("label", { style: styles2.field, children: [
1435
+ /* @__PURE__ */ jsx3("span", { style: styles2.label, children: "\u4E0A\u7EA7\u83DC\u5355" }),
1436
+ /* @__PURE__ */ jsxs2(
1437
+ "select",
1438
+ {
1439
+ style: styles2.input,
1440
+ value: form.parentId,
1441
+ onChange: (e) => setForm((prev) => ({ ...prev, parentId: e.target.value })),
1442
+ children: [
1443
+ /* @__PURE__ */ jsx3("option", { value: ROOT_PARENT_ID, children: "\u6839\u76EE\u5F55" }),
1444
+ parentOptions.map((opt) => /* @__PURE__ */ jsx3("option", { value: opt.value, children: opt.label }, opt.value))
1445
+ ]
1446
+ }
1447
+ )
1448
+ ] }),
1449
+ /* @__PURE__ */ jsxs2("fieldset", { style: styles2.fieldset, children: [
1450
+ /* @__PURE__ */ jsx3("legend", { style: styles2.label, children: "\u83DC\u5355\u7C7B\u578B" }),
1451
+ /* @__PURE__ */ jsx3("div", { style: styles2.radioGroup, children: MENU_TYPE_OPTIONS.map((opt) => /* @__PURE__ */ jsxs2("label", { style: styles2.radioItem, children: [
1452
+ /* @__PURE__ */ jsx3(
1453
+ "input",
1454
+ {
1455
+ type: "radio",
1456
+ name: "menu-type",
1457
+ checked: form.type === opt.value,
1458
+ onChange: () => setForm((prev) => ({
1459
+ ...prev,
1460
+ type: opt.value
1461
+ }))
1462
+ }
1463
+ ),
1464
+ opt.label
1465
+ ] }, opt.value)) })
1466
+ ] }),
1467
+ /* @__PURE__ */ jsxs2("label", { style: styles2.field, children: [
1468
+ /* @__PURE__ */ jsx3("span", { style: styles2.label, children: "\u83DC\u5355\u540D\u79F0" }),
1469
+ /* @__PURE__ */ jsx3(
1470
+ "input",
1471
+ {
1472
+ style: styles2.input,
1473
+ value: form.name,
1474
+ onChange: (e) => setForm((prev) => ({ ...prev, name: e.target.value })),
1475
+ placeholder: "\u8BF7\u8F93\u5165\u83DC\u5355\u540D\u79F0",
1476
+ required: true
1477
+ }
1478
+ )
1479
+ ] }),
1480
+ /* @__PURE__ */ jsxs2("label", { style: styles2.field, children: [
1481
+ /* @__PURE__ */ jsx3("span", { style: styles2.label, children: "\u8BF7\u6C42\u5730\u5740" }),
1482
+ /* @__PURE__ */ jsx3(
1483
+ "input",
1484
+ {
1485
+ style: styles2.input,
1486
+ value: form.identification,
1487
+ onChange: (e) => setForm((prev) => ({ ...prev, identification: e.target.value })),
1488
+ placeholder: "\u5982 /system/user"
1489
+ }
1490
+ )
1491
+ ] }),
1492
+ /* @__PURE__ */ jsxs2("fieldset", { style: styles2.fieldset, children: [
1493
+ /* @__PURE__ */ jsx3("legend", { style: styles2.label, children: "\u6743\u9650\u6807\u8BC6" }),
1494
+ /* @__PURE__ */ jsx3("div", { style: styles2.multiSelect, children: permissionPoints.length === 0 ? /* @__PURE__ */ jsx3("div", { style: styles2.hint, children: "\u6682\u65E0\u6743\u9650\u70B9\uFF0C\u8BF7\u5148\u5728\u6743\u9650\u70B9\u7BA1\u7406\u4E2D\u65B0\u589E" }) : permissionPoints.map((p) => /* @__PURE__ */ jsxs2("label", { style: styles2.checkItem, children: [
1495
+ /* @__PURE__ */ jsx3(
1496
+ "input",
1497
+ {
1498
+ type: "checkbox",
1499
+ checked: form.permissionPointIds.includes(p.resourceId),
1500
+ onChange: () => togglePermission(p.resourceId)
1501
+ }
1502
+ ),
1503
+ /* @__PURE__ */ jsxs2("span", { children: [
1504
+ p.name,
1505
+ /* @__PURE__ */ jsx3("code", { style: { ...styles2.code, marginLeft: 6 }, children: p.identification })
1506
+ ] })
1507
+ ] }, p.resourceId)) })
1508
+ ] }),
1509
+ /* @__PURE__ */ jsxs2("fieldset", { style: styles2.fieldset, children: [
1510
+ /* @__PURE__ */ jsx3("legend", { style: styles2.label, children: "\u72B6\u6001" }),
1511
+ /* @__PURE__ */ jsx3("div", { style: styles2.radioGroup, children: MENU_VISIBILITY_OPTIONS.map((opt) => /* @__PURE__ */ jsxs2("label", { style: styles2.radioItem, children: [
1512
+ /* @__PURE__ */ jsx3(
1513
+ "input",
1514
+ {
1515
+ type: "radio",
1516
+ name: "menu-status",
1517
+ checked: form.status === opt.value,
1518
+ onChange: () => setForm((prev) => ({ ...prev, status: opt.value }))
1519
+ }
1520
+ ),
1521
+ opt.label
1522
+ ] }, opt.value)) })
1523
+ ] }),
1524
+ /* @__PURE__ */ jsxs2("div", { style: styles2.dialogFooter, children: [
1525
+ /* @__PURE__ */ jsx3("button", { type: "button", style: styles2.secondaryBtn, onClick: closeDialog, children: "\u53D6\u6D88" }),
1526
+ /* @__PURE__ */ jsx3("button", { type: "submit", style: styles2.primaryBtn, disabled: saving, children: saving ? "\u4FDD\u5B58\u4E2D\u2026" : "\u4FDD\u5B58" })
1527
+ ] })
1528
+ ] })
1529
+ ]
1530
+ }
1531
+ ) }) : null,
1532
+ deletingRow ? /* @__PURE__ */ jsx3("div", { style: styles2.mask, onClick: closeDeleteDialog, children: /* @__PURE__ */ jsxs2(
1533
+ "div",
1534
+ {
1535
+ style: { ...styles2.dialog, maxWidth: 420 },
1536
+ onClick: (e) => e.stopPropagation(),
1537
+ role: "dialog",
1538
+ "aria-modal": "true",
1539
+ children: [
1540
+ /* @__PURE__ */ jsxs2("div", { style: styles2.dialogHeader, children: [
1541
+ /* @__PURE__ */ jsx3("h3", { style: styles2.dialogTitle, children: "\u786E\u8BA4\u5220\u9664" }),
1542
+ /* @__PURE__ */ jsx3(
1543
+ "button",
1544
+ {
1545
+ type: "button",
1546
+ style: styles2.iconBtn,
1547
+ onClick: closeDeleteDialog,
1548
+ "aria-label": "\u5173\u95ED",
1549
+ children: "\xD7"
1550
+ }
1551
+ )
1552
+ ] }),
1553
+ /* @__PURE__ */ jsxs2("div", { style: styles2.confirmBody, children: [
1554
+ /* @__PURE__ */ jsxs2("p", { style: styles2.confirmText, children: [
1555
+ "\u786E\u8BA4\u5220\u9664\u83DC\u5355\u300C",
1556
+ /* @__PURE__ */ jsx3("strong", { children: deletingRow.name }),
1557
+ "\u300D\u5417\uFF1F\u5220\u9664\u540E\u4E0D\u53EF\u6062\u590D\u3002"
1558
+ ] }),
1559
+ /* @__PURE__ */ jsxs2("div", { style: styles2.dialogFooter, children: [
1560
+ /* @__PURE__ */ jsx3(
1561
+ "button",
1562
+ {
1563
+ type: "button",
1564
+ style: styles2.secondaryBtn,
1565
+ onClick: closeDeleteDialog,
1566
+ disabled: deleting,
1567
+ children: "\u53D6\u6D88"
1568
+ }
1569
+ ),
1570
+ /* @__PURE__ */ jsx3(
1571
+ "button",
1572
+ {
1573
+ type: "button",
1574
+ style: styles2.dangerBtn,
1575
+ onClick: () => void confirmDelete(),
1576
+ disabled: deleting,
1577
+ children: deleting ? "\u5220\u9664\u4E2D\u2026" : "\u786E\u8BA4\u5220\u9664"
1578
+ }
1579
+ )
1580
+ ] })
1581
+ ] })
1582
+ ]
1583
+ }
1584
+ ) }) : null
1585
+ ] });
1586
+ }
1587
+ var styles2 = {
1588
+ root: {
1589
+ display: "flex",
1590
+ flexDirection: "column",
1591
+ gap: 16,
1592
+ padding: 16,
1593
+ color: "#101828",
1594
+ fontFamily: '"PingFang SC", "Microsoft YaHei", -apple-system, BlinkMacSystemFont, sans-serif'
1595
+ },
1596
+ toolbar: {
1597
+ display: "flex",
1598
+ alignItems: "center",
1599
+ justifyContent: "space-between",
1600
+ gap: 12
1601
+ },
1602
+ title: { margin: 0, fontSize: 18, fontWeight: 600 },
1603
+ toolbarRight: { display: "flex", alignItems: "center", gap: 8 },
1604
+ error: {
1605
+ padding: "10px 12px",
1606
+ borderRadius: 8,
1607
+ background: "#fef3f2",
1608
+ color: "#b42318",
1609
+ fontSize: 13
1610
+ },
1611
+ tableWrap: {
1612
+ overflow: "auto",
1613
+ border: "1px solid #eaecf0",
1614
+ borderRadius: 10,
1615
+ background: "#fff"
1616
+ },
1617
+ table: { width: "100%", borderCollapse: "collapse", minWidth: 820 },
1618
+ th: {
1619
+ textAlign: "left",
1620
+ padding: "12px 14px",
1621
+ fontSize: 13,
1622
+ fontWeight: 600,
1623
+ color: "#475467",
1624
+ background: "#f9fafb",
1625
+ borderBottom: "1px solid #eaecf0"
1626
+ },
1627
+ td: {
1628
+ padding: "12px 14px",
1629
+ fontSize: 14,
1630
+ borderBottom: "1px solid #f2f4f7",
1631
+ verticalAlign: "middle"
1632
+ },
1633
+ empty: { padding: 28, textAlign: "center", color: "#98a2b3", fontSize: 14 },
1634
+ code: {
1635
+ fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
1636
+ fontSize: 13,
1637
+ background: "#f2f4f7",
1638
+ padding: "2px 6px",
1639
+ borderRadius: 4
1640
+ },
1641
+ badge: {
1642
+ display: "inline-block",
1643
+ padding: "2px 8px",
1644
+ borderRadius: 999,
1645
+ fontSize: 12,
1646
+ fontWeight: 500
1647
+ },
1648
+ linkBtn: {
1649
+ border: "none",
1650
+ background: "transparent",
1651
+ color: "#049BAD",
1652
+ cursor: "pointer",
1653
+ padding: "0 8px 0 0",
1654
+ fontSize: 13
1655
+ },
1656
+ pagination: {
1657
+ display: "flex",
1658
+ alignItems: "center",
1659
+ justifyContent: "space-between",
1660
+ gap: 12
1661
+ },
1662
+ pageSize: { display: "flex", alignItems: "center", gap: 8, fontSize: 13, color: "#475467" },
1663
+ pageBtns: { display: "flex", gap: 8 },
1664
+ primaryBtn: {
1665
+ border: "none",
1666
+ background: "#049BAD",
1667
+ color: "#fff",
1668
+ borderRadius: 8,
1669
+ padding: "8px 14px",
1670
+ cursor: "pointer",
1671
+ fontSize: 14
1672
+ },
1673
+ secondaryBtn: {
1674
+ border: "1px solid #d0d5dd",
1675
+ background: "#fff",
1676
+ color: "#344054",
1677
+ borderRadius: 8,
1678
+ padding: "8px 14px",
1679
+ cursor: "pointer",
1680
+ fontSize: 14
1681
+ },
1682
+ dangerBtn: {
1683
+ border: "none",
1684
+ background: "#d92d20",
1685
+ color: "#fff",
1686
+ borderRadius: 8,
1687
+ padding: "8px 14px",
1688
+ cursor: "pointer",
1689
+ fontSize: 14
1690
+ },
1691
+ select: {
1692
+ border: "1px solid #d0d5dd",
1693
+ borderRadius: 6,
1694
+ padding: "4px 8px",
1695
+ fontSize: 13,
1696
+ backgroundColor: "#ffffff",
1697
+ color: "#101828"
1698
+ },
1699
+ mask: {
1700
+ position: "fixed",
1701
+ inset: 0,
1702
+ background: "rgba(16, 24, 40, 0.45)",
1703
+ display: "flex",
1704
+ alignItems: "center",
1705
+ justifyContent: "center",
1706
+ zIndex: 1e3,
1707
+ padding: 16
1708
+ },
1709
+ dialog: {
1710
+ width: "100%",
1711
+ maxWidth: 480,
1712
+ background: "#fff",
1713
+ borderRadius: 12,
1714
+ boxShadow: "0 20px 40px rgba(16,24,40,0.18)",
1715
+ maxHeight: "90vh",
1716
+ overflow: "auto"
1717
+ },
1718
+ dialogHeader: {
1719
+ display: "flex",
1720
+ alignItems: "center",
1721
+ justifyContent: "space-between",
1722
+ padding: "14px 16px",
1723
+ borderBottom: "1px solid #eaecf0",
1724
+ position: "sticky",
1725
+ top: 0,
1726
+ background: "#fff",
1727
+ zIndex: 1
1728
+ },
1729
+ dialogTitle: { margin: 0, fontSize: 16, fontWeight: 600 },
1730
+ iconBtn: {
1731
+ border: "none",
1732
+ background: "transparent",
1733
+ fontSize: 22,
1734
+ lineHeight: 1,
1735
+ cursor: "pointer",
1736
+ color: "#667085"
1737
+ },
1738
+ form: { display: "flex", flexDirection: "column", gap: 12, padding: 16 },
1739
+ confirmBody: { display: "flex", flexDirection: "column", gap: 16, padding: 16 },
1740
+ confirmText: { margin: 0, fontSize: 14, color: "#344054", lineHeight: 1.6 },
940
1741
  field: { display: "flex", flexDirection: "column", gap: 6 },
1742
+ fieldset: {
1743
+ margin: 0,
1744
+ padding: 0,
1745
+ border: "none",
1746
+ display: "flex",
1747
+ flexDirection: "column",
1748
+ gap: 8
1749
+ },
941
1750
  label: { fontSize: 13, color: "#344054", fontWeight: 500 },
942
1751
  input: {
943
1752
  border: "1px solid #d0d5dd",
944
1753
  borderRadius: 8,
945
1754
  padding: "8px 10px",
946
1755
  fontSize: 14,
947
- outline: "none"
1756
+ outline: "none",
1757
+ backgroundColor: "#ffffff",
1758
+ color: "#101828",
1759
+ boxSizing: "border-box",
1760
+ width: "100%"
1761
+ },
1762
+ radioGroup: { display: "flex", flexWrap: "wrap", gap: 16 },
1763
+ radioItem: {
1764
+ display: "flex",
1765
+ alignItems: "center",
1766
+ gap: 6,
1767
+ fontSize: 14,
1768
+ color: "#344054",
1769
+ cursor: "pointer"
1770
+ },
1771
+ multiSelect: {
1772
+ maxHeight: 160,
1773
+ overflow: "auto",
1774
+ border: "1px solid #eaecf0",
1775
+ borderRadius: 8,
1776
+ padding: 8,
1777
+ background: "#f9fafb"
1778
+ },
1779
+ checkItem: {
1780
+ display: "flex",
1781
+ alignItems: "center",
1782
+ gap: 8,
1783
+ padding: "6px 4px",
1784
+ fontSize: 13,
1785
+ color: "#344054",
1786
+ cursor: "pointer"
948
1787
  },
1788
+ hint: { fontSize: 13, color: "#98a2b3", padding: 8 },
949
1789
  dialogFooter: {
950
1790
  display: "flex",
951
1791
  justifyContent: "flex-end",
@@ -955,6 +1795,14 @@ var styles = {
955
1795
  };
956
1796
  export {
957
1797
  Can,
1798
+ MENU_LIST_TYPE_PARAM,
1799
+ MENU_TYPE_BUTTON,
1800
+ MENU_TYPE_LABEL,
1801
+ MENU_TYPE_MENU,
1802
+ MENU_TYPE_OPTIONS,
1803
+ MENU_TYPE_PAGE,
1804
+ MENU_VISIBILITY_OPTIONS,
1805
+ MenuManager,
958
1806
  PermissionProvider,
959
1807
  PermissionStore,
960
1808
  RESOURCE_PRIVATE_OPTIONS,
@@ -962,18 +1810,23 @@ export {
962
1810
  RESOURCE_STATUS_ENABLED,
963
1811
  RESOURCE_STATUS_OPTIONS,
964
1812
  RESOURCE_TYPE_API,
1813
+ ROOT_PARENT_ID,
965
1814
  ResourceManager,
966
1815
  appendQueryParam,
967
1816
  buildCreateBody,
1817
+ buildCreateMenuBody,
968
1818
  buildUpdateBody,
1819
+ buildUpdateMenuBody,
969
1820
  createAuthorizationResourceApi,
970
1821
  createDefaultResourceRequest,
1822
+ createMenuResourceApi,
971
1823
  createPermissionStore,
972
1824
  extractPagination,
973
1825
  extractRecords,
974
1826
  getAppClientId,
975
1827
  getDeviceWorkerId,
976
1828
  mapAuthorizationResource,
1829
+ mapMenuResource,
977
1830
  snowyflake,
978
1831
  useHasPermission,
979
1832
  useHasRole,