openxiangda 1.0.9 → 1.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/cli.js CHANGED
@@ -743,8 +743,10 @@ async function menu(args) {
743
743
  fail('用法: openxiangda menu create <menuCode> --name <text>');
744
744
  }
745
745
  const target = getWorkspaceTarget(config, profileName, flags);
746
+ const pageCode = flags['page-code'];
747
+ const pageEntry = pageCode ? findPageEntry(target.bound, entry => entry.pageCode === pageCode || entry.routeKey === pageCode) : undefined;
746
748
  const formUuid = flags['form-uuid'] || resolveOptionalFormUuid(target.bound, flags['form-code']);
747
- const pageId = flags['page-id'] || resolveOptionalPageId(target.bound, flags['page-code']);
749
+ const pageId = flags['page-id'] || resolveOptionalPageId(target.bound, pageCode);
748
750
  const data = await requestWithAuth(
749
751
  config,
750
752
  target.profileName,
@@ -767,6 +769,9 @@ async function menu(args) {
767
769
  type: flags.type || 'nav',
768
770
  ...(formUuid ? { formUuid } : {}),
769
771
  ...(pageId ? { pageId } : {}),
772
+ ...(pageCode ? { pageCode } : {}),
773
+ ...(pageEntry?.routeKey ? { routeKey: pageEntry.routeKey } : pageCode ? { routeKey: pageCode } : {}),
774
+ ...(pageEntry?.legacyFormUuid ? { legacyFormUuid: pageEntry.legacyFormUuid } : {}),
770
775
  });
771
776
  }
772
777
  if (flags.json) return writeJson(data);
@@ -1905,26 +1910,69 @@ function resolvePagePermissionMenuTargets(bound, flags = {}) {
1905
1910
  ...splitList(flags['menu-form-uuids']),
1906
1911
  ...splitList(flags['menu-ids']),
1907
1912
  ];
1908
- const fromMenuCodes = splitList(flags['menu-codes']).map(code => resolveMenuId(bound, code));
1913
+ const fromMenuCodes = splitList(flags['menu-codes']).flatMap(code => resolveMenuPermissionTargets(bound, code));
1909
1914
  const fromFormCodes = splitList(flags['form-codes']).map(code => resolveOptionalFormUuid(bound, code));
1910
- const fromPageCodes = splitList(flags['page-codes']).map(code => resolvePageMenuTarget(bound, code));
1915
+ const fromPageCodes = splitList(flags['page-codes']).flatMap(code => resolvePagePermissionTargets(bound, code));
1911
1916
  return unique([...direct, ...fromMenuCodes, ...fromFormCodes, ...fromPageCodes].filter(Boolean));
1912
1917
  }
1913
1918
 
1914
- function resolvePageMenuTarget(bound, pageCode) {
1919
+ function resolveMenuPermissionTargets(bound, menuCode) {
1920
+ const menuEntry = bound.resources?.menus?.[menuCode];
1921
+ const menuId = resolveMenuId(bound, menuCode);
1922
+ if (menuEntry?.formUuid) return [menuEntry.formUuid];
1923
+ // Custom code pages are checked by three platform surfaces: the admin tree
1924
+ // uses menu IDs, /view uses route keys, and bootstrap uses legacy PAGE IDs.
1925
+ if (menuEntry?.pageId || menuEntry?.pageCode || menuEntry?.routeKey || menuEntry?.legacyFormUuid) {
1926
+ return unique([menuId, ...resolveCodePagePermissionAliases(bound, menuEntry)]);
1927
+ }
1928
+ return [menuId];
1929
+ }
1930
+
1931
+ function resolvePagePermissionTargets(bound, pageCode) {
1915
1932
  const pageId = resolveOptionalPageId(bound, pageCode);
1916
1933
  const menuEntry = findMenuEntry(bound, entry => {
1917
1934
  if (!entry) return false;
1918
1935
  return entry.pageId === pageId || entry.pageCode === pageCode || entry.routeKey === pageCode;
1919
1936
  });
1920
- if (menuEntry?.menuId) return menuEntry.menuId;
1937
+ if (menuEntry?.menuId) {
1938
+ return unique([menuEntry.menuId, ...resolveCodePagePermissionAliases(bound, menuEntry, pageCode)]);
1939
+ }
1921
1940
  fail(`页面 ${pageCode} 未找到已绑定菜单。请先发布/创建菜单,或直接传 --menu-codes/--menu-ids。`);
1922
1941
  }
1923
1942
 
1943
+ function resolveCodePagePermissionAliases(bound, menuEntry = {}, pageCode) {
1944
+ const pageEntry = findPageEntry(bound, entry => {
1945
+ if (!entry) return false;
1946
+ return (
1947
+ entry.pageCode === pageCode ||
1948
+ entry.routeKey === pageCode ||
1949
+ entry.pageId === menuEntry.pageId ||
1950
+ entry.pageCode === menuEntry.pageCode ||
1951
+ entry.routeKey === menuEntry.routeKey ||
1952
+ entry.legacyFormUuid === menuEntry.legacyFormUuid
1953
+ );
1954
+ });
1955
+ return unique([
1956
+ pageCode,
1957
+ menuEntry.pageCode,
1958
+ menuEntry.routeKey,
1959
+ menuEntry.legacyFormUuid,
1960
+ pageEntry?.pageCode,
1961
+ pageEntry?.routeKey,
1962
+ pageEntry?.legacyFormUuid,
1963
+ ].filter(Boolean));
1964
+ }
1965
+
1924
1966
  function findMenuEntry(bound, predicate) {
1925
1967
  return Object.values(bound.resources?.menus || {}).find(predicate);
1926
1968
  }
1927
1969
 
1970
+ function findPageEntry(bound, predicate) {
1971
+ return Object.entries(bound.resources?.pages || {})
1972
+ .map(([pageCode, entry]) => ({ pageCode, ...(entry || {}) }))
1973
+ .find(predicate);
1974
+ }
1975
+
1928
1976
  function resolveSettingsFormUuid(bound, formKey, flags = {}) {
1929
1977
  const key = formKey || flags['form-code'] || flags['form-uuid'];
1930
1978
  if (!key && !flags['form-uuid']) {
@@ -369,11 +369,11 @@ Body:
369
369
  {
370
370
  "name": "销售可见页面",
371
371
  "roles": ["sales"],
372
- "menuFormUuids": ["FORM_XXX", "MENU_ID_FOR_CODE_PAGE"]
372
+ "menuFormUuids": ["FORM_XXX", "MENU_ID_FOR_CODE_PAGE", "CODE_PAGE_ROUTE_KEY", "PAGE_LEGACY_FORM_UUID"]
373
373
  }
374
374
  ```
375
375
 
376
- An empty `menuFormUuids` array means all menus/pages are visible to the matched roles. For form menus this field can contain form UUIDs; for custom code page menus use the actual menu ID returned by `/apps/:appType/menus`, not the code page `PAGE_...` legacy form UUID.
376
+ An empty `menuFormUuids` array means all menus/pages are visible to the matched roles. For form menus this field can contain form UUIDs. For custom code page menus, OpenXiangda CLI `--page-codes` / `--menu-codes` writes the actual menu ID used by the platform admin tree, the route key used by `/view`, and the legacy `PAGE_...` alias used by custom-page bootstrap.
377
377
 
378
378
  ### GET `/apps/:appType/page-permission-groups/:groupId`
379
379
 
@@ -18,13 +18,15 @@ Role IDs are platform-specific. Store them only in `.openxiangda/state.json` und
18
18
 
19
19
  ## Page Permission Groups
20
20
 
21
- Page permission groups map role codes to visible menu `formUuid` values:
21
+ Page permission groups map role codes to visible menu targets. Form menus use their `FORM_...`
22
+ form UUIDs; custom code page/display menus need the menu ID, route key, and legacy `PAGE_...`
23
+ alias because current platform surfaces check different identifiers:
22
24
 
23
25
  ```json
24
26
  {
25
27
  "name": "销售页面",
26
28
  "roles": ["sales"],
27
- "menuFormUuids": ["FORM_CUSTOMER", "FORM_ORDER", "MENU_ID_FOR_CODE_PAGE"]
29
+ "menuFormUuids": ["FORM_CUSTOMER", "FORM_ORDER", "MENU_ID_FOR_CODE_PAGE", "CODE_PAGE_ROUTE_KEY", "PAGE_LEGACY_FORM_UUID"]
28
30
  }
29
31
  ```
30
32
 
@@ -33,7 +35,7 @@ Rules:
33
35
  - `roles: []` means all roles can match.
34
36
  - `menuFormUuids: []` means all menus/pages are visible to matched roles.
35
37
  - Prefer `--form-codes` in CLI for form menus so each profile resolves its own form UUIDs.
36
- - Prefer `--page-codes` or `--menu-codes` in CLI for custom code page menus so each profile resolves to real menu IDs.
38
+ - Prefer `--page-codes` or `--menu-codes` in CLI for custom code page menus. The CLI writes the menu ID for the admin tree, the route key for `/view`, and the legacy `PAGE_...` alias for custom-page bootstrap.
37
39
 
38
40
  ## Form Permission Groups
39
41
 
@@ -43,7 +43,7 @@ openxiangda permission page-group-create sales_pages --name "销售页面" --rol
43
43
  openxiangda permission page-group-create portal_pages --name "门户页面" --page-codes portal_pc,portal_mobile --profile dev
44
44
  ```
45
45
 
46
- Use `--page-codes` or `--menu-codes` for custom code page menus; the CLI resolves code pages to their published menu IDs. Use `--form-codes` for form menus; the CLI resolves forms to profile-local form UUIDs. Empty target lists mean all menus/pages are visible to matched roles.
46
+ Use `--page-codes` or `--menu-codes` for custom code page menus; the CLI resolves code pages to the published menu ID plus the route key and legacy `PAGE_...` alias required by the platform's current admin tree, `/view` guard, and custom-page bootstrap checks. Use `--form-codes` for form menus; the CLI resolves forms to profile-local form UUIDs. Empty target lists mean all menus/pages are visible to matched roles.
47
47
 
48
48
  ## Form Permission Groups
49
49
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openxiangda",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
4
4
  "description": "OpenXiangda CLI, workspace build tools, runtime SDK, and form components.",
5
5
  "private": false,
6
6
  "bin": {