openxiangda 1.0.8 → 1.0.10
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,6 +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;
|
|
748
|
+
const formUuid = flags['form-uuid'] || resolveOptionalFormUuid(target.bound, flags['form-code']);
|
|
749
|
+
const pageId = flags['page-id'] || resolveOptionalPageId(target.bound, pageCode);
|
|
746
750
|
const data = await requestWithAuth(
|
|
747
751
|
config,
|
|
748
752
|
target.profileName,
|
|
@@ -752,14 +756,24 @@ async function menu(args) {
|
|
|
752
756
|
body: {
|
|
753
757
|
name,
|
|
754
758
|
type: flags.type || 'nav',
|
|
755
|
-
formUuid
|
|
756
|
-
pageId
|
|
759
|
+
formUuid,
|
|
760
|
+
pageId,
|
|
757
761
|
parentId: flags['parent-id'] || null,
|
|
758
762
|
icon: flags.icon || null,
|
|
759
763
|
},
|
|
760
764
|
}
|
|
761
765
|
);
|
|
762
|
-
if (data?.id)
|
|
766
|
+
if (data?.id) {
|
|
767
|
+
saveMenuResource(target, menuCode, data.id, {
|
|
768
|
+
name,
|
|
769
|
+
type: flags.type || 'nav',
|
|
770
|
+
...(formUuid ? { formUuid } : {}),
|
|
771
|
+
...(pageId ? { pageId } : {}),
|
|
772
|
+
...(pageCode ? { pageCode } : {}),
|
|
773
|
+
...(pageEntry?.routeKey ? { routeKey: pageEntry.routeKey } : pageCode ? { routeKey: pageCode } : {}),
|
|
774
|
+
...(pageEntry?.legacyFormUuid ? { legacyFormUuid: pageEntry.legacyFormUuid } : {}),
|
|
775
|
+
});
|
|
776
|
+
}
|
|
763
777
|
if (flags.json) return writeJson(data);
|
|
764
778
|
print(JSON.stringify(data, null, 2));
|
|
765
779
|
return;
|
|
@@ -1308,7 +1322,7 @@ async function permission(args) {
|
|
|
1308
1322
|
const [groupCode] = positional;
|
|
1309
1323
|
const name = flags.name || positional.slice(1).join(' ') || groupCode;
|
|
1310
1324
|
if (!groupCode || !name) {
|
|
1311
|
-
fail('用法: openxiangda permission page-group-create <groupCode> --name <text>');
|
|
1325
|
+
fail('用法: openxiangda permission page-group-create <groupCode> --name <text> [--menu-codes <menuCode...>|--page-codes <pageCode...>|--form-codes <formCode...>|--menu-ids <id...>]');
|
|
1312
1326
|
}
|
|
1313
1327
|
const target = getWorkspaceTarget(config, profileName, flags);
|
|
1314
1328
|
const data = await requestWithAuth(
|
|
@@ -1320,7 +1334,7 @@ async function permission(args) {
|
|
|
1320
1334
|
body: {
|
|
1321
1335
|
name,
|
|
1322
1336
|
roles: splitList(flags.roles),
|
|
1323
|
-
menuFormUuids:
|
|
1337
|
+
menuFormUuids: resolvePagePermissionMenuTargets(target.bound, flags),
|
|
1324
1338
|
},
|
|
1325
1339
|
}
|
|
1326
1340
|
);
|
|
@@ -1891,10 +1905,70 @@ function resolveRoleId(bound, roleKey, flags = {}) {
|
|
|
1891
1905
|
return mapped || roleKey;
|
|
1892
1906
|
}
|
|
1893
1907
|
|
|
1894
|
-
function
|
|
1895
|
-
const direct =
|
|
1896
|
-
|
|
1897
|
-
|
|
1908
|
+
function resolvePagePermissionMenuTargets(bound, flags = {}) {
|
|
1909
|
+
const direct = [
|
|
1910
|
+
...splitList(flags['menu-form-uuids']),
|
|
1911
|
+
...splitList(flags['menu-ids']),
|
|
1912
|
+
];
|
|
1913
|
+
const fromMenuCodes = splitList(flags['menu-codes']).flatMap(code => resolveMenuPermissionTargets(bound, code));
|
|
1914
|
+
const fromFormCodes = splitList(flags['form-codes']).map(code => resolveOptionalFormUuid(bound, code));
|
|
1915
|
+
const fromPageCodes = splitList(flags['page-codes']).flatMap(code => resolvePagePermissionTargets(bound, code));
|
|
1916
|
+
return unique([...direct, ...fromMenuCodes, ...fromFormCodes, ...fromPageCodes].filter(Boolean));
|
|
1917
|
+
}
|
|
1918
|
+
|
|
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
|
+
if (menuEntry?.pageId || menuEntry?.pageCode || menuEntry?.routeKey || menuEntry?.legacyFormUuid) {
|
|
1924
|
+
return unique([menuId, ...resolveCodePagePermissionAliases(bound, menuEntry)]);
|
|
1925
|
+
}
|
|
1926
|
+
return [menuId];
|
|
1927
|
+
}
|
|
1928
|
+
|
|
1929
|
+
function resolvePagePermissionTargets(bound, pageCode) {
|
|
1930
|
+
const pageId = resolveOptionalPageId(bound, pageCode);
|
|
1931
|
+
const menuEntry = findMenuEntry(bound, entry => {
|
|
1932
|
+
if (!entry) return false;
|
|
1933
|
+
return entry.pageId === pageId || entry.pageCode === pageCode || entry.routeKey === pageCode;
|
|
1934
|
+
});
|
|
1935
|
+
if (menuEntry?.menuId) {
|
|
1936
|
+
return unique([menuEntry.menuId, ...resolveCodePagePermissionAliases(bound, menuEntry, pageCode)]);
|
|
1937
|
+
}
|
|
1938
|
+
fail(`页面 ${pageCode} 未找到已绑定菜单。请先发布/创建菜单,或直接传 --menu-codes/--menu-ids。`);
|
|
1939
|
+
}
|
|
1940
|
+
|
|
1941
|
+
function resolveCodePagePermissionAliases(bound, menuEntry = {}, pageCode) {
|
|
1942
|
+
const pageEntry = findPageEntry(bound, entry => {
|
|
1943
|
+
if (!entry) return false;
|
|
1944
|
+
return (
|
|
1945
|
+
entry.pageCode === pageCode ||
|
|
1946
|
+
entry.routeKey === pageCode ||
|
|
1947
|
+
entry.pageId === menuEntry.pageId ||
|
|
1948
|
+
entry.pageCode === menuEntry.pageCode ||
|
|
1949
|
+
entry.routeKey === menuEntry.routeKey ||
|
|
1950
|
+
entry.legacyFormUuid === menuEntry.legacyFormUuid
|
|
1951
|
+
);
|
|
1952
|
+
});
|
|
1953
|
+
return unique([
|
|
1954
|
+
pageCode,
|
|
1955
|
+
menuEntry.pageCode,
|
|
1956
|
+
menuEntry.routeKey,
|
|
1957
|
+
menuEntry.legacyFormUuid,
|
|
1958
|
+
pageEntry?.pageCode,
|
|
1959
|
+
pageEntry?.routeKey,
|
|
1960
|
+
pageEntry?.legacyFormUuid,
|
|
1961
|
+
].filter(Boolean));
|
|
1962
|
+
}
|
|
1963
|
+
|
|
1964
|
+
function findMenuEntry(bound, predicate) {
|
|
1965
|
+
return Object.values(bound.resources?.menus || {}).find(predicate);
|
|
1966
|
+
}
|
|
1967
|
+
|
|
1968
|
+
function findPageEntry(bound, predicate) {
|
|
1969
|
+
return Object.entries(bound.resources?.pages || {})
|
|
1970
|
+
.map(([pageCode, entry]) => ({ pageCode, ...(entry || {}) }))
|
|
1971
|
+
.find(predicate);
|
|
1898
1972
|
}
|
|
1899
1973
|
|
|
1900
1974
|
function resolveSettingsFormUuid(bound, formKey, flags = {}) {
|
|
@@ -2249,6 +2323,10 @@ function splitList(value) {
|
|
|
2249
2323
|
.filter(Boolean);
|
|
2250
2324
|
}
|
|
2251
2325
|
|
|
2326
|
+
function unique(values) {
|
|
2327
|
+
return [...new Set(values)];
|
|
2328
|
+
}
|
|
2329
|
+
|
|
2252
2330
|
function renderTerminalQr(text) {
|
|
2253
2331
|
try {
|
|
2254
2332
|
require('qrcode-terminal').generate(text, { small: true });
|
|
@@ -369,11 +369,11 @@ Body:
|
|
|
369
369
|
{
|
|
370
370
|
"name": "销售可见页面",
|
|
371
371
|
"roles": ["sales"],
|
|
372
|
-
"menuFormUuids": ["FORM_XXX"]
|
|
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.
|
|
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, current platform runtimes may check different identifiers at different layers, so OpenXiangda CLI `--page-codes` / `--menu-codes` writes the actual menu ID, the code page route key, and the legacy `PAGE_...` form UUID alias.
|
|
377
377
|
|
|
378
378
|
### GET `/apps/:appType/page-permission-groups/:groupId`
|
|
379
379
|
|
|
@@ -24,7 +24,7 @@ Page permission groups map role codes to visible menu `formUuid` values:
|
|
|
24
24
|
{
|
|
25
25
|
"name": "销售页面",
|
|
26
26
|
"roles": ["sales"],
|
|
27
|
-
"menuFormUuids": ["FORM_CUSTOMER", "FORM_ORDER"]
|
|
27
|
+
"menuFormUuids": ["FORM_CUSTOMER", "FORM_ORDER", "MENU_ID_FOR_CODE_PAGE", "CODE_PAGE_ROUTE_KEY", "PAGE_LEGACY_FORM_UUID"]
|
|
28
28
|
}
|
|
29
29
|
```
|
|
30
30
|
|
|
@@ -32,7 +32,8 @@ Rules:
|
|
|
32
32
|
|
|
33
33
|
- `roles: []` means all roles can match.
|
|
34
34
|
- `menuFormUuids: []` means all menus/pages are visible to matched roles.
|
|
35
|
-
- Prefer `--form-codes` in CLI so each profile resolves its own form UUIDs.
|
|
35
|
+
- 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. The CLI writes the menu ID plus the code page route key and legacy `PAGE_...` alias required by current `/view` and custom-page runtime permission checks.
|
|
36
37
|
|
|
37
38
|
## Form Permission Groups
|
|
38
39
|
|
|
@@ -40,9 +40,10 @@ Page permission groups control menu/page visibility:
|
|
|
40
40
|
|
|
41
41
|
```bash
|
|
42
42
|
openxiangda permission page-group-create sales_pages --name "销售页面" --roles sales --form-codes customer,orders --profile dev
|
|
43
|
+
openxiangda permission page-group-create portal_pages --name "门户页面" --page-codes portal_pc,portal_mobile --profile dev
|
|
43
44
|
```
|
|
44
45
|
|
|
45
|
-
|
|
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 current runtime permission 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.
|
|
46
47
|
|
|
47
48
|
## Form Permission Groups
|
|
48
49
|
|