com-angel-authorization 1.0.5 → 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.
@@ -21,6 +21,14 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var vue_exports = {};
22
22
  __export(vue_exports, {
23
23
  Can: () => Can,
24
+ MENU_LIST_TYPE_PARAM: () => MENU_LIST_TYPE_PARAM,
25
+ MENU_TYPE_BUTTON: () => MENU_TYPE_BUTTON,
26
+ MENU_TYPE_LABEL: () => MENU_TYPE_LABEL,
27
+ MENU_TYPE_MENU: () => MENU_TYPE_MENU,
28
+ MENU_TYPE_OPTIONS: () => MENU_TYPE_OPTIONS,
29
+ MENU_TYPE_PAGE: () => MENU_TYPE_PAGE,
30
+ MENU_VISIBILITY_OPTIONS: () => MENU_VISIBILITY_OPTIONS,
31
+ MenuManager: () => MenuManager,
24
32
  PERMISSION_STORE_KEY: () => PERMISSION_STORE_KEY,
25
33
  PermissionStore: () => PermissionStore,
26
34
  RESOURCE_PRIVATE_OPTIONS: () => RESOURCE_PRIVATE_OPTIONS,
@@ -28,12 +36,16 @@ __export(vue_exports, {
28
36
  RESOURCE_STATUS_ENABLED: () => RESOURCE_STATUS_ENABLED,
29
37
  RESOURCE_STATUS_OPTIONS: () => RESOURCE_STATUS_OPTIONS,
30
38
  RESOURCE_TYPE_API: () => RESOURCE_TYPE_API,
39
+ ROOT_PARENT_ID: () => ROOT_PARENT_ID,
31
40
  ResourceManager: () => ResourceManager,
32
41
  appendQueryParam: () => appendQueryParam,
33
42
  buildCreateBody: () => buildCreateBody,
43
+ buildCreateMenuBody: () => buildCreateMenuBody,
34
44
  buildUpdateBody: () => buildUpdateBody,
45
+ buildUpdateMenuBody: () => buildUpdateMenuBody,
35
46
  createAuthorizationResourceApi: () => createAuthorizationResourceApi,
36
47
  createDefaultResourceRequest: () => createDefaultResourceRequest,
48
+ createMenuResourceApi: () => createMenuResourceApi,
37
49
  createPermissionPlugin: () => createPermissionPlugin,
38
50
  createPermissionStore: () => createPermissionStore,
39
51
  createVPermission: () => createVPermission,
@@ -42,6 +54,7 @@ __export(vue_exports, {
42
54
  getAppClientId: () => getAppClientId,
43
55
  getDeviceWorkerId: () => getDeviceWorkerId,
44
56
  mapAuthorizationResource: () => mapAuthorizationResource,
57
+ mapMenuResource: () => mapMenuResource,
45
58
  snowyflake: () => snowyflake,
46
59
  useHasPermission: () => useHasPermission,
47
60
  useHasRole: () => useHasRole,
@@ -349,16 +362,35 @@ var import_vue3 = require("vue");
349
362
 
350
363
  // src/resources/types.ts
351
364
  var RESOURCE_TYPE_API = "api";
365
+ var MENU_TYPE_PAGE = "page";
366
+ var MENU_TYPE_MENU = "menu";
367
+ var MENU_TYPE_BUTTON = "button";
368
+ var MENU_LIST_TYPE_PARAM = "page,menu,button";
369
+ var ROOT_PARENT_ID = "0";
352
370
  var RESOURCE_STATUS_ENABLED = 1;
353
371
  var RESOURCE_STATUS_DISABLED = 0;
354
372
  var RESOURCE_STATUS_OPTIONS = [
355
373
  { label: "\u542F\u7528", value: RESOURCE_STATUS_ENABLED },
356
374
  { label: "\u7981\u7528", value: RESOURCE_STATUS_DISABLED }
357
375
  ];
376
+ var MENU_VISIBILITY_OPTIONS = [
377
+ { label: "\u663E\u793A", value: RESOURCE_STATUS_ENABLED },
378
+ { label: "\u9690\u85CF", value: RESOURCE_STATUS_DISABLED }
379
+ ];
358
380
  var RESOURCE_PRIVATE_OPTIONS = [
359
381
  { label: "\u662F", value: true },
360
382
  { label: "\u5426", value: false }
361
383
  ];
384
+ var MENU_TYPE_OPTIONS = [
385
+ { label: "\u76EE\u5F55", value: MENU_TYPE_PAGE },
386
+ { label: "\u83DC\u5355", value: MENU_TYPE_MENU },
387
+ { label: "\u6309\u94AE", value: MENU_TYPE_BUTTON }
388
+ ];
389
+ var MENU_TYPE_LABEL = {
390
+ page: "\u76EE\u5F55",
391
+ menu: "\u83DC\u5355",
392
+ button: "\u6309\u94AE"
393
+ };
362
394
 
363
395
  // src/utils/snowflake.ts
364
396
  var DEVICE_WORKER_ID_KEY = "hgams_device_worker_id";
@@ -503,6 +535,29 @@ function toBoolean(value) {
503
535
  }
504
536
  return false;
505
537
  }
538
+ function toStringArray(value) {
539
+ if (Array.isArray(value)) {
540
+ return value.map((item) => {
541
+ if (item && typeof item === "object") {
542
+ const row = item;
543
+ const id = row.resourceId ?? row.resource_id ?? row.id;
544
+ return id === void 0 || id === null ? "" : String(id);
545
+ }
546
+ return String(item ?? "");
547
+ }).filter(Boolean);
548
+ }
549
+ if (typeof value === "string" && value.trim()) {
550
+ return value.split(",").map((s3) => s3.trim()).filter(Boolean);
551
+ }
552
+ return [];
553
+ }
554
+ function toMenuType(value) {
555
+ const v = String(value ?? "").toLowerCase();
556
+ if (v === MENU_TYPE_PAGE || v === MENU_TYPE_MENU || v === MENU_TYPE_BUTTON) {
557
+ return v;
558
+ }
559
+ return MENU_TYPE_MENU;
560
+ }
506
561
  function mapAuthorizationResource(item) {
507
562
  if (!item || typeof item !== "object") return null;
508
563
  const row = item;
@@ -518,9 +573,31 @@ function mapAuthorizationResource(item) {
518
573
  description: String(row.description ?? row.desc ?? "")
519
574
  };
520
575
  }
521
- function buildListUrl(params) {
576
+ function mapMenuResource(item) {
577
+ if (!item || typeof item !== "object") return null;
578
+ const row = item;
579
+ const resourceId = row.resourceId ?? row.resource_id ?? row.id;
580
+ if (resourceId === void 0 || resourceId === null || resourceId === "") return null;
581
+ const permissionPointIds = toStringArray(
582
+ row.permissionPointIds ?? row.permission_point_ids ?? row.permissionPoints ?? row.permissions
583
+ );
584
+ const permissionNamesRaw = row.permissionPointNames ?? row.permission_point_names ?? row.permissionNames;
585
+ const permissionPointNames = Array.isArray(permissionNamesRaw) ? permissionNamesRaw.map((n) => String(n ?? "")).filter(Boolean) : void 0;
586
+ const parentId = row.parentId ?? row.parent_id ?? ROOT_PARENT_ID;
587
+ return {
588
+ resourceId: String(resourceId),
589
+ parentId: parentId === void 0 || parentId === null ? ROOT_PARENT_ID : String(parentId),
590
+ type: toMenuType(row.type),
591
+ name: String(row.name ?? ""),
592
+ identification: String(row.identification ?? row.identity ?? row.path ?? ""),
593
+ permissionPointIds,
594
+ permissionPointNames,
595
+ status: toResourceStatus(row.status)
596
+ };
597
+ }
598
+ function buildListUrl(type, params) {
522
599
  const parts = [];
523
- appendQueryParam(parts, "type", RESOURCE_TYPE_API);
600
+ appendQueryParam(parts, "type", type);
524
601
  appendQueryParam(parts, "page-token", params?.pagination?.pageToken ?? "");
525
602
  appendQueryParam(parts, "page-size", params?.pagination?.pageSize ?? "20");
526
603
  appendQueryParam(parts, "page-direction", params?.pagination?.pageDirection ?? "current");
@@ -547,12 +624,33 @@ function buildUpdateBody(values) {
547
624
  description: values.description.trim()
548
625
  };
549
626
  }
627
+ function buildCreateMenuBody(values, resourceId = getAppClientId()) {
628
+ return {
629
+ resourceId,
630
+ parentId: values.parentId || ROOT_PARENT_ID,
631
+ type: values.type,
632
+ name: values.name.trim(),
633
+ identification: values.identification.trim(),
634
+ permissionPointIds: [...values.permissionPointIds],
635
+ status: values.status
636
+ };
637
+ }
638
+ function buildUpdateMenuBody(values) {
639
+ return {
640
+ parentId: values.parentId || ROOT_PARENT_ID,
641
+ type: values.type,
642
+ name: values.name.trim(),
643
+ identification: values.identification.trim(),
644
+ permissionPointIds: [...values.permissionPointIds],
645
+ status: values.status
646
+ };
647
+ }
550
648
  function createAuthorizationResourceApi(request) {
551
649
  return {
552
650
  async list(params, signal) {
553
651
  const json = await request({
554
652
  method: "GET",
555
- url: buildListUrl(params),
653
+ url: buildListUrl(RESOURCE_TYPE_API, params),
556
654
  signal
557
655
  });
558
656
  const records = extractRecords(json).map(mapAuthorizationResource).filter((item) => item !== null);
@@ -587,6 +685,50 @@ function createAuthorizationResourceApi(request) {
587
685
  }
588
686
  };
589
687
  }
688
+ function createMenuResourceApi(request) {
689
+ const permissionApi = createAuthorizationResourceApi(request);
690
+ return {
691
+ async list(params, signal) {
692
+ const json = await request({
693
+ method: "GET",
694
+ url: buildListUrl(MENU_LIST_TYPE_PARAM, params),
695
+ signal
696
+ });
697
+ const records = extractRecords(json).map(mapMenuResource).filter((item) => item !== null);
698
+ const pagination = extractPagination(json);
699
+ return {
700
+ records,
701
+ ...pagination
702
+ };
703
+ },
704
+ listPermissionPoints(params, signal) {
705
+ return permissionApi.list(params, signal);
706
+ },
707
+ async create(values, signal) {
708
+ return request({
709
+ method: "POST",
710
+ url: "/authorization-resources",
711
+ body: buildCreateMenuBody(values),
712
+ signal
713
+ });
714
+ },
715
+ async update(resourceId, values, signal) {
716
+ return request({
717
+ method: "PATCH",
718
+ url: `/authorization-resources/${encodeURIComponent(resourceId)}`,
719
+ body: buildUpdateMenuBody(values),
720
+ signal
721
+ });
722
+ },
723
+ async remove(resourceId, signal) {
724
+ return request({
725
+ method: "DELETE",
726
+ url: `/authorization-resources/${encodeURIComponent(resourceId)}`,
727
+ signal
728
+ });
729
+ }
730
+ };
731
+ }
590
732
  function createDefaultResourceRequest(options = {}) {
591
733
  const baseUrl = (options.baseUrl ?? "").replace(/\/+$/, "");
592
734
  const credentials = options.credentials ?? "include";
@@ -1287,9 +1429,806 @@ var ResourceManager = (0, import_vue3.defineComponent)({
1287
1429
  ]);
1288
1430
  }
1289
1431
  });
1432
+
1433
+ // src/vue/MenuManager.ts
1434
+ var import_vue4 = require("vue");
1435
+ var PAGE_SIZE_OPTIONS2 = ["10", "20", "50", "100"];
1436
+ function emptyForm2() {
1437
+ return {
1438
+ parentId: ROOT_PARENT_ID,
1439
+ type: MENU_TYPE_MENU,
1440
+ name: "",
1441
+ identification: "",
1442
+ permissionPointIds: [],
1443
+ status: RESOURCE_STATUS_ENABLED
1444
+ };
1445
+ }
1446
+ var s2 = {
1447
+ root: {
1448
+ display: "flex",
1449
+ flexDirection: "column",
1450
+ gap: "16px",
1451
+ padding: "16px",
1452
+ color: "#101828",
1453
+ fontFamily: '"PingFang SC", "Microsoft YaHei", -apple-system, BlinkMacSystemFont, sans-serif'
1454
+ },
1455
+ toolbar: {
1456
+ display: "flex",
1457
+ alignItems: "center",
1458
+ justifyContent: "space-between",
1459
+ gap: "12px"
1460
+ },
1461
+ title: { margin: "0", fontSize: "18px", fontWeight: "600" },
1462
+ toolbarRight: { display: "flex", alignItems: "center", gap: "8px" },
1463
+ error: {
1464
+ padding: "10px 12px",
1465
+ borderRadius: "8px",
1466
+ background: "#fef3f2",
1467
+ color: "#b42318",
1468
+ fontSize: "13px"
1469
+ },
1470
+ tableWrap: {
1471
+ overflow: "auto",
1472
+ border: "1px solid #eaecf0",
1473
+ borderRadius: "10px",
1474
+ background: "#fff"
1475
+ },
1476
+ table: { width: "100%", borderCollapse: "collapse", minWidth: "820px" },
1477
+ th: {
1478
+ textAlign: "left",
1479
+ padding: "12px 14px",
1480
+ fontSize: "13px",
1481
+ fontWeight: "600",
1482
+ color: "#475467",
1483
+ background: "#f9fafb",
1484
+ borderBottom: "1px solid #eaecf0"
1485
+ },
1486
+ td: {
1487
+ padding: "12px 14px",
1488
+ fontSize: "14px",
1489
+ borderBottom: "1px solid #f2f4f7",
1490
+ verticalAlign: "middle"
1491
+ },
1492
+ empty: {
1493
+ padding: "28px",
1494
+ textAlign: "center",
1495
+ color: "#98a2b3",
1496
+ fontSize: "14px"
1497
+ },
1498
+ code: {
1499
+ fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
1500
+ fontSize: "13px",
1501
+ background: "#f2f4f7",
1502
+ padding: "2px 6px",
1503
+ borderRadius: "4px"
1504
+ },
1505
+ badge: {
1506
+ display: "inline-block",
1507
+ padding: "2px 8px",
1508
+ borderRadius: "999px",
1509
+ fontSize: "12px",
1510
+ fontWeight: "500"
1511
+ },
1512
+ linkBtn: {
1513
+ border: "none",
1514
+ background: "transparent",
1515
+ color: "#049BAD",
1516
+ cursor: "pointer",
1517
+ padding: "0 8px 0 0",
1518
+ fontSize: "13px"
1519
+ },
1520
+ pagination: {
1521
+ display: "flex",
1522
+ alignItems: "center",
1523
+ justifyContent: "space-between",
1524
+ gap: "12px"
1525
+ },
1526
+ pageSize: {
1527
+ display: "flex",
1528
+ alignItems: "center",
1529
+ gap: "8px",
1530
+ fontSize: "13px",
1531
+ color: "#475467"
1532
+ },
1533
+ pageBtns: { display: "flex", gap: "8px" },
1534
+ primaryBtn: {
1535
+ border: "none",
1536
+ background: "#049BAD",
1537
+ color: "#fff",
1538
+ borderRadius: "8px",
1539
+ padding: "8px 14px",
1540
+ cursor: "pointer",
1541
+ fontSize: "14px"
1542
+ },
1543
+ secondaryBtn: {
1544
+ border: "1px solid #d0d5dd",
1545
+ background: "#fff",
1546
+ color: "#344054",
1547
+ borderRadius: "8px",
1548
+ padding: "8px 14px",
1549
+ cursor: "pointer",
1550
+ fontSize: "14px"
1551
+ },
1552
+ dangerBtn: {
1553
+ border: "none",
1554
+ background: "#d92d20",
1555
+ color: "#fff",
1556
+ borderRadius: "8px",
1557
+ padding: "8px 14px",
1558
+ cursor: "pointer",
1559
+ fontSize: "14px"
1560
+ },
1561
+ select: {
1562
+ border: "1px solid #d0d5dd",
1563
+ borderRadius: "6px",
1564
+ padding: "4px 8px",
1565
+ fontSize: "13px",
1566
+ backgroundColor: "#ffffff",
1567
+ color: "#101828"
1568
+ },
1569
+ mask: {
1570
+ position: "fixed",
1571
+ inset: "0",
1572
+ background: "rgba(16, 24, 40, 0.45)",
1573
+ display: "flex",
1574
+ alignItems: "center",
1575
+ justifyContent: "center",
1576
+ zIndex: "1000",
1577
+ padding: "16px"
1578
+ },
1579
+ dialog: {
1580
+ width: "100%",
1581
+ maxWidth: "480px",
1582
+ background: "#fff",
1583
+ borderRadius: "12px",
1584
+ boxShadow: "0 20px 40px rgba(16,24,40,0.18)",
1585
+ maxHeight: "90vh",
1586
+ overflow: "auto"
1587
+ },
1588
+ dialogHeader: {
1589
+ display: "flex",
1590
+ alignItems: "center",
1591
+ justifyContent: "space-between",
1592
+ padding: "14px 16px",
1593
+ borderBottom: "1px solid #eaecf0",
1594
+ position: "sticky",
1595
+ top: "0",
1596
+ background: "#fff",
1597
+ zIndex: "1"
1598
+ },
1599
+ dialogTitle: { margin: "0", fontSize: "16px", fontWeight: "600" },
1600
+ iconBtn: {
1601
+ border: "none",
1602
+ background: "transparent",
1603
+ fontSize: "22px",
1604
+ lineHeight: "1",
1605
+ cursor: "pointer",
1606
+ color: "#667085"
1607
+ },
1608
+ form: { display: "flex", flexDirection: "column", gap: "12px", padding: "16px" },
1609
+ confirmBody: {
1610
+ display: "flex",
1611
+ flexDirection: "column",
1612
+ gap: "16px",
1613
+ padding: "16px"
1614
+ },
1615
+ confirmText: {
1616
+ margin: "0",
1617
+ fontSize: "14px",
1618
+ color: "#344054",
1619
+ lineHeight: "1.6"
1620
+ },
1621
+ field: { display: "flex", flexDirection: "column", gap: "6px" },
1622
+ fieldset: {
1623
+ margin: "0",
1624
+ padding: "0",
1625
+ border: "none",
1626
+ display: "flex",
1627
+ flexDirection: "column",
1628
+ gap: "8px"
1629
+ },
1630
+ label: { fontSize: "13px", color: "#344054", fontWeight: "500" },
1631
+ input: {
1632
+ border: "1px solid #d0d5dd",
1633
+ borderRadius: "8px",
1634
+ padding: "8px 10px",
1635
+ fontSize: "14px",
1636
+ outline: "none",
1637
+ backgroundColor: "#ffffff",
1638
+ color: "#101828",
1639
+ boxSizing: "border-box",
1640
+ width: "100%"
1641
+ },
1642
+ radioGroup: { display: "flex", flexWrap: "wrap", gap: "16px" },
1643
+ radioItem: {
1644
+ display: "flex",
1645
+ alignItems: "center",
1646
+ gap: "6px",
1647
+ fontSize: "14px",
1648
+ color: "#344054",
1649
+ cursor: "pointer"
1650
+ },
1651
+ multiSelect: {
1652
+ maxHeight: "160px",
1653
+ overflow: "auto",
1654
+ border: "1px solid #eaecf0",
1655
+ borderRadius: "8px",
1656
+ padding: "8px",
1657
+ background: "#f9fafb"
1658
+ },
1659
+ checkItem: {
1660
+ display: "flex",
1661
+ alignItems: "center",
1662
+ gap: "8px",
1663
+ padding: "6px 4px",
1664
+ fontSize: "13px",
1665
+ color: "#344054",
1666
+ cursor: "pointer"
1667
+ },
1668
+ hint: { fontSize: "13px", color: "#98a2b3", padding: "8px" },
1669
+ dialogFooter: {
1670
+ display: "flex",
1671
+ justifyContent: "flex-end",
1672
+ gap: "8px",
1673
+ paddingTop: "4px"
1674
+ }
1675
+ };
1676
+ var MenuManager = (0, import_vue4.defineComponent)({
1677
+ name: "MenuManager",
1678
+ props: {
1679
+ api: {
1680
+ type: Object,
1681
+ required: true
1682
+ },
1683
+ title: {
1684
+ type: String,
1685
+ default: "\u83DC\u5355\u7BA1\u7406"
1686
+ },
1687
+ pageSize: {
1688
+ type: String,
1689
+ default: "20"
1690
+ }
1691
+ },
1692
+ setup(props, { slots }) {
1693
+ const records = (0, import_vue4.ref)([]);
1694
+ const permissionPoints = (0, import_vue4.ref)([]);
1695
+ const loading = (0, import_vue4.ref)(false);
1696
+ const error = (0, import_vue4.ref)("");
1697
+ const pageSize = (0, import_vue4.ref)(props.pageSize);
1698
+ const pageToken = (0, import_vue4.ref)("");
1699
+ const hasPreviousPage = (0, import_vue4.ref)(false);
1700
+ const hasNextPage = (0, import_vue4.ref)(false);
1701
+ const dialogOpen = (0, import_vue4.ref)(false);
1702
+ const editing = (0, import_vue4.ref)(null);
1703
+ const form = (0, import_vue4.reactive)(emptyForm2());
1704
+ const saving = (0, import_vue4.ref)(false);
1705
+ const deletingRow = (0, import_vue4.ref)(null);
1706
+ const deleting = (0, import_vue4.ref)(false);
1707
+ const permissionNameMap = (0, import_vue4.computed)(() => {
1708
+ const map = /* @__PURE__ */ new Map();
1709
+ permissionPoints.value.forEach(
1710
+ (p) => map.set(p.resourceId, p.name || p.identification)
1711
+ );
1712
+ return map;
1713
+ });
1714
+ const parentOptions = (0, import_vue4.computed)(
1715
+ () => records.value.filter((row) => !editing.value || row.resourceId !== editing.value.resourceId).map((row) => ({
1716
+ value: row.resourceId,
1717
+ label: `${row.name}\uFF08${MENU_TYPE_LABEL[row.type]}\uFF09`
1718
+ }))
1719
+ );
1720
+ async function loadList(direction = "current", token = pageToken.value) {
1721
+ loading.value = true;
1722
+ error.value = "";
1723
+ try {
1724
+ const result = await props.api.list({
1725
+ pagination: {
1726
+ pageToken: token,
1727
+ pageSize: pageSize.value,
1728
+ pageDirection: direction
1729
+ }
1730
+ });
1731
+ records.value = result.records;
1732
+ pageToken.value = result.pageToken;
1733
+ hasPreviousPage.value = result.hasPreviousPage;
1734
+ hasNextPage.value = result.hasNextPage;
1735
+ } catch (err) {
1736
+ error.value = err instanceof Error ? err.message : "\u52A0\u8F7D\u5931\u8D25";
1737
+ } finally {
1738
+ loading.value = false;
1739
+ }
1740
+ }
1741
+ async function loadPermissionPoints() {
1742
+ try {
1743
+ const result = await props.api.listPermissionPoints({
1744
+ pagination: { pageSize: "200", pageDirection: "current" }
1745
+ });
1746
+ permissionPoints.value = result.records;
1747
+ } catch {
1748
+ }
1749
+ }
1750
+ function openCreate() {
1751
+ editing.value = null;
1752
+ Object.assign(form, emptyForm2());
1753
+ dialogOpen.value = true;
1754
+ void loadPermissionPoints();
1755
+ }
1756
+ function openEdit(row) {
1757
+ editing.value = row;
1758
+ Object.assign(form, {
1759
+ parentId: row.parentId || ROOT_PARENT_ID,
1760
+ type: row.type,
1761
+ name: row.name,
1762
+ identification: row.identification,
1763
+ permissionPointIds: [...row.permissionPointIds],
1764
+ status: row.status
1765
+ });
1766
+ dialogOpen.value = true;
1767
+ void loadPermissionPoints();
1768
+ }
1769
+ function closeDialog() {
1770
+ if (!saving.value) dialogOpen.value = false;
1771
+ }
1772
+ async function handleSubmit(event) {
1773
+ event.preventDefault();
1774
+ if (!form.name.trim()) {
1775
+ error.value = "\u8BF7\u586B\u5199\u83DC\u5355\u540D\u79F0";
1776
+ return;
1777
+ }
1778
+ saving.value = true;
1779
+ error.value = "";
1780
+ try {
1781
+ if (editing.value) {
1782
+ await props.api.update(editing.value.resourceId, { ...form });
1783
+ } else {
1784
+ await props.api.create({ ...form });
1785
+ }
1786
+ dialogOpen.value = false;
1787
+ await loadList("current", "");
1788
+ } catch (err) {
1789
+ error.value = err instanceof Error ? err.message : "\u4FDD\u5B58\u5931\u8D25";
1790
+ } finally {
1791
+ saving.value = false;
1792
+ }
1793
+ }
1794
+ function askDelete(row) {
1795
+ deletingRow.value = row;
1796
+ }
1797
+ function closeDeleteDialog() {
1798
+ if (!deleting.value) deletingRow.value = null;
1799
+ }
1800
+ async function confirmDelete() {
1801
+ if (!deletingRow.value) return;
1802
+ deleting.value = true;
1803
+ error.value = "";
1804
+ try {
1805
+ await props.api.remove(deletingRow.value.resourceId);
1806
+ deletingRow.value = null;
1807
+ await loadList("current", "");
1808
+ } catch (err) {
1809
+ error.value = err instanceof Error ? err.message : "\u5220\u9664\u5931\u8D25";
1810
+ } finally {
1811
+ deleting.value = false;
1812
+ }
1813
+ }
1814
+ function togglePermission(id) {
1815
+ const exists = form.permissionPointIds.includes(id);
1816
+ form.permissionPointIds = exists ? form.permissionPointIds.filter((x) => x !== id) : [...form.permissionPointIds, id];
1817
+ }
1818
+ function renderPermissionLabels(row) {
1819
+ if (row.permissionPointNames?.length) {
1820
+ return row.permissionPointNames.join("\u3001");
1821
+ }
1822
+ if (!row.permissionPointIds.length) return "\u2014";
1823
+ return row.permissionPointIds.map((id) => permissionNameMap.value.get(id) ?? id).join("\u3001");
1824
+ }
1825
+ (0, import_vue4.onMounted)(() => {
1826
+ void loadList("current", "");
1827
+ void loadPermissionPoints();
1828
+ });
1829
+ (0, import_vue4.watch)(
1830
+ () => [props.api, pageSize.value],
1831
+ () => {
1832
+ pageToken.value = "";
1833
+ void loadList("current", "");
1834
+ }
1835
+ );
1836
+ return () => (0, import_vue4.h)("div", { style: s2.root }, [
1837
+ (0, import_vue4.h)("div", { style: s2.toolbar }, [
1838
+ (0, import_vue4.h)("h2", { style: s2.title }, props.title),
1839
+ (0, import_vue4.h)("div", { style: s2.toolbarRight }, [
1840
+ slots.toolbarExtra?.(),
1841
+ (0, import_vue4.h)(
1842
+ "button",
1843
+ { type: "button", style: s2.primaryBtn, onClick: openCreate },
1844
+ "\u65B0\u589E"
1845
+ )
1846
+ ])
1847
+ ]),
1848
+ error.value ? (0, import_vue4.h)("div", { style: s2.error }, error.value) : null,
1849
+ (0, import_vue4.h)("div", { style: s2.tableWrap }, [
1850
+ (0, import_vue4.h)("table", { style: s2.table }, [
1851
+ (0, import_vue4.h)("thead", [
1852
+ (0, import_vue4.h)("tr", [
1853
+ (0, import_vue4.h)("th", { style: s2.th }, "\u83DC\u5355\u540D\u79F0"),
1854
+ (0, import_vue4.h)("th", { style: s2.th }, "\u8BF7\u6C42\u5730\u5740"),
1855
+ (0, import_vue4.h)("th", { style: { ...s2.th, width: "90px" } }, "\u7C7B\u578B"),
1856
+ (0, import_vue4.h)("th", { style: { ...s2.th, width: "80px" } }, "\u53EF\u89C1"),
1857
+ (0, import_vue4.h)("th", { style: s2.th }, "\u6743\u9650\u6807\u8BC6"),
1858
+ (0, import_vue4.h)("th", { style: { ...s2.th, width: "140px" } }, "\u64CD\u4F5C")
1859
+ ])
1860
+ ]),
1861
+ (0, import_vue4.h)(
1862
+ "tbody",
1863
+ loading.value ? [
1864
+ (0, import_vue4.h)("tr", [
1865
+ (0, import_vue4.h)("td", { colspan: 6, style: s2.empty }, "\u52A0\u8F7D\u4E2D\u2026")
1866
+ ])
1867
+ ] : records.value.length === 0 ? [
1868
+ (0, import_vue4.h)("tr", [
1869
+ (0, import_vue4.h)("td", { colspan: 6, style: s2.empty }, "\u6682\u65E0\u6570\u636E")
1870
+ ])
1871
+ ] : records.value.map(
1872
+ (row) => (0, import_vue4.h)("tr", { key: row.resourceId }, [
1873
+ (0, import_vue4.h)("td", { style: s2.td }, row.name),
1874
+ (0, import_vue4.h)("td", { style: s2.td }, [
1875
+ (0, import_vue4.h)(
1876
+ "code",
1877
+ { style: s2.code },
1878
+ row.identification || "\u2014"
1879
+ )
1880
+ ]),
1881
+ (0, import_vue4.h)("td", { style: s2.td }, MENU_TYPE_LABEL[row.type]),
1882
+ (0, import_vue4.h)("td", { style: s2.td }, [
1883
+ (0, import_vue4.h)(
1884
+ "span",
1885
+ {
1886
+ style: {
1887
+ ...s2.badge,
1888
+ background: row.status === RESOURCE_STATUS_ENABLED ? "#e8f7ef" : "#f4f4f5",
1889
+ color: row.status === RESOURCE_STATUS_ENABLED ? "#067647" : "#667085"
1890
+ }
1891
+ },
1892
+ row.status === RESOURCE_STATUS_ENABLED ? "\u663E\u793A" : "\u9690\u85CF"
1893
+ )
1894
+ ]),
1895
+ (0, import_vue4.h)("td", { style: s2.td }, renderPermissionLabels(row)),
1896
+ (0, import_vue4.h)("td", { style: s2.td }, [
1897
+ (0, import_vue4.h)(
1898
+ "button",
1899
+ {
1900
+ type: "button",
1901
+ style: s2.linkBtn,
1902
+ onClick: () => openEdit(row)
1903
+ },
1904
+ "\u7F16\u8F91"
1905
+ ),
1906
+ (0, import_vue4.h)(
1907
+ "button",
1908
+ {
1909
+ type: "button",
1910
+ style: { ...s2.linkBtn, color: "#d92d20" },
1911
+ onClick: () => askDelete(row)
1912
+ },
1913
+ "\u5220\u9664"
1914
+ )
1915
+ ])
1916
+ ])
1917
+ )
1918
+ )
1919
+ ])
1920
+ ]),
1921
+ (0, import_vue4.h)("div", { style: s2.pagination }, [
1922
+ (0, import_vue4.h)("label", { style: s2.pageSize }, [
1923
+ "\u6BCF\u9875",
1924
+ (0, import_vue4.h)(
1925
+ "select",
1926
+ {
1927
+ style: s2.select,
1928
+ value: pageSize.value,
1929
+ onChange: (e) => {
1930
+ pageSize.value = e.target.value;
1931
+ }
1932
+ },
1933
+ PAGE_SIZE_OPTIONS2.map(
1934
+ (size) => (0, import_vue4.h)("option", { key: size, value: size }, size)
1935
+ )
1936
+ )
1937
+ ]),
1938
+ (0, import_vue4.h)("div", { style: s2.pageBtns }, [
1939
+ (0, import_vue4.h)(
1940
+ "button",
1941
+ {
1942
+ type: "button",
1943
+ style: s2.secondaryBtn,
1944
+ disabled: !hasPreviousPage.value || loading.value,
1945
+ onClick: () => void loadList("previous")
1946
+ },
1947
+ "\u4E0A\u4E00\u9875"
1948
+ ),
1949
+ (0, import_vue4.h)(
1950
+ "button",
1951
+ {
1952
+ type: "button",
1953
+ style: s2.secondaryBtn,
1954
+ disabled: !hasNextPage.value || loading.value,
1955
+ onClick: () => void loadList("next")
1956
+ },
1957
+ "\u4E0B\u4E00\u9875"
1958
+ )
1959
+ ])
1960
+ ]),
1961
+ dialogOpen.value ? (0, import_vue4.h)(
1962
+ "div",
1963
+ { style: s2.mask, onClick: closeDialog },
1964
+ [
1965
+ (0, import_vue4.h)(
1966
+ "div",
1967
+ {
1968
+ style: { ...s2.dialog, maxWidth: "520px" },
1969
+ role: "dialog",
1970
+ "aria-modal": "true",
1971
+ onClick: (e) => e.stopPropagation()
1972
+ },
1973
+ [
1974
+ (0, import_vue4.h)("div", { style: s2.dialogHeader }, [
1975
+ (0, import_vue4.h)(
1976
+ "h3",
1977
+ { style: s2.dialogTitle },
1978
+ editing.value ? "\u7F16\u8F91\u83DC\u5355" : "\u65B0\u589E\u83DC\u5355"
1979
+ ),
1980
+ (0, import_vue4.h)(
1981
+ "button",
1982
+ {
1983
+ type: "button",
1984
+ style: s2.iconBtn,
1985
+ "aria-label": "\u5173\u95ED",
1986
+ onClick: closeDialog
1987
+ },
1988
+ "\xD7"
1989
+ )
1990
+ ]),
1991
+ (0, import_vue4.h)(
1992
+ "form",
1993
+ {
1994
+ style: s2.form,
1995
+ onSubmit: (e) => void handleSubmit(e)
1996
+ },
1997
+ [
1998
+ (0, import_vue4.h)("label", { style: s2.field }, [
1999
+ (0, import_vue4.h)("span", { style: s2.label }, "\u4E0A\u7EA7\u83DC\u5355"),
2000
+ (0, import_vue4.h)(
2001
+ "select",
2002
+ {
2003
+ style: s2.input,
2004
+ value: form.parentId,
2005
+ onChange: (e) => {
2006
+ form.parentId = e.target.value;
2007
+ }
2008
+ },
2009
+ [
2010
+ (0, import_vue4.h)("option", { value: ROOT_PARENT_ID }, "\u6839\u76EE\u5F55"),
2011
+ ...parentOptions.value.map(
2012
+ (opt) => (0, import_vue4.h)(
2013
+ "option",
2014
+ { key: opt.value, value: opt.value },
2015
+ opt.label
2016
+ )
2017
+ )
2018
+ ]
2019
+ )
2020
+ ]),
2021
+ (0, import_vue4.h)("fieldset", { style: s2.fieldset }, [
2022
+ (0, import_vue4.h)("legend", { style: s2.label }, "\u83DC\u5355\u7C7B\u578B"),
2023
+ (0, import_vue4.h)(
2024
+ "div",
2025
+ { style: s2.radioGroup },
2026
+ MENU_TYPE_OPTIONS.map(
2027
+ (opt) => (0, import_vue4.h)("label", { key: opt.value, style: s2.radioItem }, [
2028
+ (0, import_vue4.h)("input", {
2029
+ type: "radio",
2030
+ name: "menu-type",
2031
+ checked: form.type === opt.value,
2032
+ onChange: () => {
2033
+ form.type = opt.value;
2034
+ }
2035
+ }),
2036
+ opt.label
2037
+ ])
2038
+ )
2039
+ )
2040
+ ]),
2041
+ (0, import_vue4.h)("label", { style: s2.field }, [
2042
+ (0, import_vue4.h)("span", { style: s2.label }, "\u83DC\u5355\u540D\u79F0"),
2043
+ (0, import_vue4.h)("input", {
2044
+ style: s2.input,
2045
+ value: form.name,
2046
+ placeholder: "\u8BF7\u8F93\u5165\u83DC\u5355\u540D\u79F0",
2047
+ required: true,
2048
+ onInput: (e) => {
2049
+ form.name = e.target.value;
2050
+ }
2051
+ })
2052
+ ]),
2053
+ (0, import_vue4.h)("label", { style: s2.field }, [
2054
+ (0, import_vue4.h)("span", { style: s2.label }, "\u8BF7\u6C42\u5730\u5740"),
2055
+ (0, import_vue4.h)("input", {
2056
+ style: s2.input,
2057
+ value: form.identification,
2058
+ placeholder: "\u5982 /system/user",
2059
+ onInput: (e) => {
2060
+ form.identification = e.target.value;
2061
+ }
2062
+ })
2063
+ ]),
2064
+ (0, import_vue4.h)("fieldset", { style: s2.fieldset }, [
2065
+ (0, import_vue4.h)("legend", { style: s2.label }, "\u6743\u9650\u6807\u8BC6"),
2066
+ (0, import_vue4.h)(
2067
+ "div",
2068
+ { style: s2.multiSelect },
2069
+ permissionPoints.value.length === 0 ? [
2070
+ (0, import_vue4.h)(
2071
+ "div",
2072
+ { style: s2.hint },
2073
+ "\u6682\u65E0\u6743\u9650\u70B9\uFF0C\u8BF7\u5148\u5728\u6743\u9650\u70B9\u7BA1\u7406\u4E2D\u65B0\u589E"
2074
+ )
2075
+ ] : permissionPoints.value.map(
2076
+ (p) => (0, import_vue4.h)(
2077
+ "label",
2078
+ { key: p.resourceId, style: s2.checkItem },
2079
+ [
2080
+ (0, import_vue4.h)("input", {
2081
+ type: "checkbox",
2082
+ checked: form.permissionPointIds.includes(
2083
+ p.resourceId
2084
+ ),
2085
+ onChange: () => togglePermission(p.resourceId)
2086
+ }),
2087
+ (0, import_vue4.h)("span", [
2088
+ p.name,
2089
+ (0, import_vue4.h)(
2090
+ "code",
2091
+ {
2092
+ style: {
2093
+ ...s2.code,
2094
+ marginLeft: "6px"
2095
+ }
2096
+ },
2097
+ p.identification
2098
+ )
2099
+ ])
2100
+ ]
2101
+ )
2102
+ )
2103
+ )
2104
+ ]),
2105
+ (0, import_vue4.h)("fieldset", { style: s2.fieldset }, [
2106
+ (0, import_vue4.h)("legend", { style: s2.label }, "\u72B6\u6001"),
2107
+ (0, import_vue4.h)(
2108
+ "div",
2109
+ { style: s2.radioGroup },
2110
+ MENU_VISIBILITY_OPTIONS.map(
2111
+ (opt) => (0, import_vue4.h)("label", { key: opt.value, style: s2.radioItem }, [
2112
+ (0, import_vue4.h)("input", {
2113
+ type: "radio",
2114
+ name: "menu-status",
2115
+ checked: form.status === opt.value,
2116
+ onChange: () => {
2117
+ form.status = opt.value;
2118
+ }
2119
+ }),
2120
+ opt.label
2121
+ ])
2122
+ )
2123
+ )
2124
+ ]),
2125
+ (0, import_vue4.h)("div", { style: s2.dialogFooter }, [
2126
+ (0, import_vue4.h)(
2127
+ "button",
2128
+ {
2129
+ type: "button",
2130
+ style: s2.secondaryBtn,
2131
+ onClick: closeDialog
2132
+ },
2133
+ "\u53D6\u6D88"
2134
+ ),
2135
+ (0, import_vue4.h)(
2136
+ "button",
2137
+ {
2138
+ type: "submit",
2139
+ style: s2.primaryBtn,
2140
+ disabled: saving.value
2141
+ },
2142
+ saving.value ? "\u4FDD\u5B58\u4E2D\u2026" : "\u4FDD\u5B58"
2143
+ )
2144
+ ])
2145
+ ]
2146
+ )
2147
+ ]
2148
+ )
2149
+ ]
2150
+ ) : null,
2151
+ deletingRow.value ? (0, import_vue4.h)(
2152
+ "div",
2153
+ { style: s2.mask, onClick: closeDeleteDialog },
2154
+ [
2155
+ (0, import_vue4.h)(
2156
+ "div",
2157
+ {
2158
+ style: { ...s2.dialog, maxWidth: "420px" },
2159
+ role: "dialog",
2160
+ "aria-modal": "true",
2161
+ "aria-labelledby": "angel-auth-menu-delete-title",
2162
+ onClick: (e) => e.stopPropagation()
2163
+ },
2164
+ [
2165
+ (0, import_vue4.h)("div", { style: s2.dialogHeader }, [
2166
+ (0, import_vue4.h)(
2167
+ "h3",
2168
+ {
2169
+ id: "angel-auth-menu-delete-title",
2170
+ style: s2.dialogTitle
2171
+ },
2172
+ "\u786E\u8BA4\u5220\u9664"
2173
+ ),
2174
+ (0, import_vue4.h)(
2175
+ "button",
2176
+ {
2177
+ type: "button",
2178
+ style: s2.iconBtn,
2179
+ "aria-label": "\u5173\u95ED",
2180
+ onClick: closeDeleteDialog
2181
+ },
2182
+ "\xD7"
2183
+ )
2184
+ ]),
2185
+ (0, import_vue4.h)("div", { style: s2.confirmBody }, [
2186
+ (0, import_vue4.h)("p", { style: s2.confirmText }, [
2187
+ "\u786E\u8BA4\u5220\u9664\u83DC\u5355\u300C",
2188
+ (0, import_vue4.h)("strong", deletingRow.value.name),
2189
+ "\u300D\u5417\uFF1F\u5220\u9664\u540E\u4E0D\u53EF\u6062\u590D\u3002"
2190
+ ]),
2191
+ (0, import_vue4.h)("div", { style: s2.dialogFooter }, [
2192
+ (0, import_vue4.h)(
2193
+ "button",
2194
+ {
2195
+ type: "button",
2196
+ style: s2.secondaryBtn,
2197
+ disabled: deleting.value,
2198
+ onClick: closeDeleteDialog
2199
+ },
2200
+ "\u53D6\u6D88"
2201
+ ),
2202
+ (0, import_vue4.h)(
2203
+ "button",
2204
+ {
2205
+ type: "button",
2206
+ style: s2.dangerBtn,
2207
+ disabled: deleting.value,
2208
+ onClick: () => void confirmDelete()
2209
+ },
2210
+ deleting.value ? "\u5220\u9664\u4E2D\u2026" : "\u786E\u8BA4\u5220\u9664"
2211
+ )
2212
+ ])
2213
+ ])
2214
+ ]
2215
+ )
2216
+ ]
2217
+ ) : null
2218
+ ]);
2219
+ }
2220
+ });
1290
2221
  // Annotate the CommonJS export names for ESM import in node:
1291
2222
  0 && (module.exports = {
1292
2223
  Can,
2224
+ MENU_LIST_TYPE_PARAM,
2225
+ MENU_TYPE_BUTTON,
2226
+ MENU_TYPE_LABEL,
2227
+ MENU_TYPE_MENU,
2228
+ MENU_TYPE_OPTIONS,
2229
+ MENU_TYPE_PAGE,
2230
+ MENU_VISIBILITY_OPTIONS,
2231
+ MenuManager,
1293
2232
  PERMISSION_STORE_KEY,
1294
2233
  PermissionStore,
1295
2234
  RESOURCE_PRIVATE_OPTIONS,
@@ -1297,12 +2236,16 @@ var ResourceManager = (0, import_vue3.defineComponent)({
1297
2236
  RESOURCE_STATUS_ENABLED,
1298
2237
  RESOURCE_STATUS_OPTIONS,
1299
2238
  RESOURCE_TYPE_API,
2239
+ ROOT_PARENT_ID,
1300
2240
  ResourceManager,
1301
2241
  appendQueryParam,
1302
2242
  buildCreateBody,
2243
+ buildCreateMenuBody,
1303
2244
  buildUpdateBody,
2245
+ buildUpdateMenuBody,
1304
2246
  createAuthorizationResourceApi,
1305
2247
  createDefaultResourceRequest,
2248
+ createMenuResourceApi,
1306
2249
  createPermissionPlugin,
1307
2250
  createPermissionStore,
1308
2251
  createVPermission,
@@ -1311,6 +2254,7 @@ var ResourceManager = (0, import_vue3.defineComponent)({
1311
2254
  getAppClientId,
1312
2255
  getDeviceWorkerId,
1313
2256
  mapAuthorizationResource,
2257
+ mapMenuResource,
1314
2258
  snowyflake,
1315
2259
  useHasPermission,
1316
2260
  useHasRole,