amis
amis copied to clipboard
fix setPages: 确保在子节点没有设置url的时候,正确拼接父级路径。
What
修复 setPages 中页面路径生成逻辑,确保在子节点没有设置url的时候,正确拼接父级路径。
Why
当前状态下,如果父节点设置了url但是字节点没有设置,那么子节点不会使用父节点的url,而会变成page-n/page-n的格式
[
{
"label": "分组2",
"url": "/dashboard",
"children": [
{
"label": "用户管理",
"schema": {
"type": "page",
"title": "用户管理",
"body": "页面C"
}
},
{
"label": "部门管理",
"url": "3",
"schemaApi": "${API_HOST}/api/amis-mock/mock2/service/form?tpl=tpl3"
},
]
}
]
如上的的用户管理会返回 page-1/page-1 而不是/dashboard/page-1
How
修改
path =
item.url ||
`/${paths
.map(item => item.index)
.concat(index)
.map(index => `page-${index + 1}`)
.join('/')}`;
为
path = item.url || `page-${index + 1}`;
Test Script
function mapTree<T extends TreeItem>(
tree: Array<T>,
iterator: (
item: T,
key: number,
level: number,
paths: Array<T>,
indexes: Array<number>
) => T,
level: number = 1,
depthFirst: boolean = false,
paths: Array<T> = [],
indexes: Array<number> = []
) {
return tree.map((item: any, index) => {
if (depthFirst) {
let children: TreeArray | undefined = item.children
? mapTree(
item.children,
iterator,
level + 1,
depthFirst,
paths.concat(item),
indexes.concat(index)
)
: undefined;
children && (item = {...item, children: children});
item = iterator(item, index, level, paths, indexes.concat(index)) || {
...(item as object)
};
return item;
}
item = iterator(item, index, level, paths, indexes.concat(index)) || {
...(item as object)
};
if (item.children && item.children.splice) {
item.children = mapTree(
item.children,
iterator,
level + 1,
depthFirst,
paths.concat(item),
indexes.concat(index)
);
}
return item;
});
}
let setPages = (pages: any) => {
if (pages && !Array.isArray(pages)) {
pages = [pages];
} else if (!Array.isArray(pages)) {
return;
}
pages = mapTree(pages, (item, index, level, paths) => {
let path = item.link || item.url;
if (item.schema || item.schemaApi) {
path = item.url || `page-${index + 1}`;
// path =
// item.url ||
// `/${paths
// .map(item => item.index)
// .concat(index)
// .map(index => `page-${index + 1}`)
// .join('/')}`;
// path exists and start with /
if (path && path[0] !== '/') {
let parentPath = '/';
let index = paths.length;
while (index > 0) {
const item = paths[index - 1];
if (item?.path) {
parentPath = item.path + '/';
break;
}
index--;
}
path = parentPath + path;
}
}
return {
...item,
index,
id: item.id ,
label: item.label,
icon: item.icon,
path
};
});
return pages;
}
let pages = [
{
"label": "示例",
"url": "/dashboard",
"children": [
{
"label": "页面A",
"url": "index",
"schema": {
"type": "page",
"title": "页面A",
"body": "页面A"
},
"children": [
{
"label": "页面A-1",
"url": "1",
"schema": {
"type": "page",
"title": "页面A-1",
"body": "页面A-1"
}
},
]
},
{
"label": "页面B",
"badge": 3,
"badgeClassName": "bg-info",
"schema": {
"type": "page",
"title": "页面B",
"body": "页面B"
},
"children": [
{
"label": "页面bbb-1",
"url": "aaa",
"schema": {
"type": "page",
"title": "页面A-1",
"body": "页面A-1"
}
},
{
"label": "页面bbb-1",
"url": "/aaaa",
"schema": {
"type": "page",
"title": "页面A-1",
"body": "页面A-1"
}
},
]
},
{
"label": "列表示例",
"url": "/crud",
"rewrite": "/crud/list",
"icon": "fa fa-cube",
"children": [
{
"label": "列表",
"url": "/crud/list",
"icon": "fa fa-list",
"schemaApi": "get:/pages/crud-list.json"
},
{
"label": "新增",
"url": "new",
"icon": "fa fa-plus",
"schemaApi": "get:/pages/crud-new.json"
}
]
}
]
},
{
"label": "分组2",
"url": "/dashboard",
"children": [
{
"label": "用户管理",
"schema": {
"type": "page",
"title": "用户管理",
"body": "页面C"
}
},
{
"label": "部门管理",
"url": "3",
"schemaApi": "${API_HOST}/api/amis-mock/mock2/service/form?tpl=tpl3"
},
]
}
]
console.log(JSON.stringify(setPages(pages), null, 4));
👍 Thanks for this! 🏷 I have applied any labels matching special text in your issue.
Please review the labels and make any necessary changes.
你好,之前时故意这么设定的,如果不带上层级,index 可能会冲突
你好,之前时故意这么设定的,如果不带上层级,index 可能会冲突
你好,我修改了代码,这样还有冲突么。
测试代码
function mapTree<T extends TreeItem>(
tree: Array<T>,
iterator: (
item: T,
key: number,
level: number,
paths: Array<T>,
indexes: Array<number>
) => T,
level: number = 1,
depthFirst: boolean = false,
paths: Array<T> = [],
indexes: Array<number> = []
) {
return tree.map((item: any, index) => {
if (depthFirst) {
let children: TreeArray | undefined = item.children
? mapTree(
item.children,
iterator,
level + 1,
depthFirst,
paths.concat(item),
indexes.concat(index)
)
: undefined;
children && (item = {...item, children: children});
item = iterator(item, index, level, paths, indexes.concat(index)) || {
...(item as object)
};
return item;
}
item = iterator(item, index, level, paths, indexes.concat(index)) || {
...(item as object)
};
if (item.children && item.children.splice) {
item.children = mapTree(
item.children,
iterator,
level + 1,
depthFirst,
paths.concat(item),
indexes.concat(index)
);
}
return item;
});
}
let setPages = (pages: any) => {
if (pages && !Array.isArray(pages)) {
pages = [pages];
} else if (!Array.isArray(pages)) {
return;
}
pages = mapTree(pages, (item, index, level, paths, indexes) => {
let path = item.link || item.url;
if (item.schema || item.schemaApi) {
// get current path either url exist or generated url page-index
let currentPath = item.url || `page-${index + 1}`;
// if start with '/', absolute path, return directly
if (currentPath.startsWith('/')) {
path = item.url;
} else {
let closestIndex = paths.length - 1;
let fullPaths: string[] = [currentPath];
while (closestIndex >= 0) {
const item = paths[closestIndex];
// if parent path exists
if (item?.path) {
fullPaths = fullPaths.concat(item.path);
// if its a scheme, the path might not be generated, so keep moving upwards
if (item.schema || item.schemaApi) {
break;
}
}else {
fullPaths = fullPaths.concat(`page-${indexes[closestIndex] + 1}`);
}
closestIndex--;
}
path = fullPaths.reverse().join("/");
// maybe add /??,
// if (path && path[0] !== '/') {
// path = `/${path}`;
// }
}
}else {
// the above code would be lot cleaner if we set path for no schema node here.
// but there might be other issue. keep as is.
}
return {
...item,
index,
id: item.id,
label: item.label,
icon: item.icon,
path
};
});
return pages;
}
let pages = [
{
"label": "1 顶层有url",
"url": "/dashboard",
"children": [
{
"label": "1.1 相对路径",
"url": "relative-1-1",
"schema": {
"type": "page"
},
"children": [
{
"label": "1.1.1 无url",
"schema": {
"type": "page"
}
},
{
"label": "1.1.2 相对路径",
"url": "relative-1-1-2",
"schema": {
"type": "page"
}
}
]
},
{
"label": "1.2 绝对路径",
"url": "/page-b",
"schema": {
"type": "page"
}
},
{
"label": "1.3 无url",
"schema": {
"type": "page"
},
children: [
{
"label": "1.3.1 相对",
"url": "relative-1-3-1",
"schema": {
"type": "page"
}
},
]
}
]
},
{
"label": "2 顶层带url 不带 /",
"url": "features",
"children": [
{
"label": "2.1 重复相对路径",
"url": "page-a",
"schemaApi": "get:/api/feature1"
},
{
"label": "2.2 无schema 绝对路径",
"url": "/external-link",
"children": [
{
"label": "2.2.1 子功能 绝对路径覆盖",
"url": "/sub-absolute-override",
"schema": {
"type": "page"
}
},
{
"label": "2.2.1 相对路径",
"url": "sub-relative",
"schema": {
"type": "page"
}
},
]
}, {
"label": "2.3 无schema 无url",
"children": [
{
"label": "2.3.1 绝对路径覆盖",
"url": "/abosolute-2-3-1",
"schema": {
"type": "page"
}
},
{
"label": "2.3.2 相对路径 ",
"url": "relative-2-3-2",
"schema": {
"type": "page"
}
},
{
"label": "2.3.3 相对路径 无schema",
"url": "relative-2-3-3",
"children": [
{
"label": "2.3.3.1 无url",
"schema": {
"type": "page"
}
},
]
},
]
}
]
},
{
"label": "3 无URL的顶层",
"children": [
{
"label": "3.1 无url",
"schema": {
"type": "page"
}
},
{
"label": "3.2 无url",
"children": [
{
"label": "3.2.1 相对",
"url": "relative-3-2-1",
"schema": {
"type": "page"
}
},
]
}
]
},
{
"label": "4 另一个无URL的顶层",
"children": [
{
"label": "4.1 子页面(无url,依赖父索引)",
"schema": {
"type": "page"
}
},
{
"label": "4.2 有url",
"url": "relative-4-2",
"schema": {
"type": "page"
}
},
{
"label": "4.3 有url",
"url": "relative-4-3",
"children": [
{
"label": "4.3.1 无url",
"schema": {
"type": "page"
}
},
]
},
]
}
]
function printPathWithUrl(pages: any, prefix = '') {
if (!Array.isArray(pages)) {
return;
}
pages.forEach(page => {
const originalUrl = page.url ? `url: ${page.url}` : 'url: null';
const generatedPath = `path: ${page.path || '无'}`;
const hasSchema = `schema: ${page.schema || page.schemaApi ? 'yes' : 'no'}`;
console.log(`${prefix}├─ ${page.label} (${originalUrl}, ${generatedPath}, ${hasSchema})`);
if (page.children && page.children.length > 0) {
printPathWithUrl(page.children, prefix + ' ');
}
});
}
printPathWithUrl(setPages(pages));
├─ 1 顶层有url (url: /dashboard, path: /dashboard, schema: no)
├─ 1.1 相对路径 (url: relative-1-1, path: /dashboard/relative-1-1, schema: yes)
├─ 1.1.1 无url (url: null, path: /dashboard/relative-1-1/page-1, schema: yes)
├─ 1.1.2 相对路径 (url: relative-1-1-2, path: /dashboard/relative-1-1/relative-1-1-2, schema: yes)
├─ 1.2 绝对路径 (url: /page-b, path: /page-b, schema: yes)
├─ 1.3 无url (url: null, path: /dashboard/page-3, schema: yes)
├─ 1.3.1 相对 (url: relative-1-3-1, path: /dashboard/page-3/relative-1-3-1, schema: yes)
├─ 2 顶层带url 不带 / (url: features, path: features, schema: no)
├─ 2.1 重复相对路径 (url: page-a, path: features/page-a, schema: yes)
├─ 2.2 无schema 绝对路径 (url: /external-link, path: /external-link, schema: no)
├─ 2.2.1 子功能 绝对路径覆盖 (url: /sub-absolute-override, path: /sub-absolute-override, schema: yes)
├─ 2.2.1 相对路径 (url: sub-relative, path: features//external-link/sub-relative, schema: yes)
├─ 2.3 无schema 无url (url: null, path: 无, schema: no)
├─ 2.3.1 绝对路径覆盖 (url: /abosolute-2-3-1, path: /abosolute-2-3-1, schema: yes)
├─ 2.3.2 相对路径 (url: relative-2-3-2, path: features/page-3/relative-2-3-2, schema: yes)
├─ 2.3.3 相对路径 无schema (url: relative-2-3-3, path: relative-2-3-3, schema: no)
├─ 2.3.3.1 无url (url: null, path: features/page-3/relative-2-3-3/page-1, schema: yes)
├─ 3 无URL的顶层 (url: null, path: 无, schema: no)
├─ 3.1 无url (url: null, path: page-3/page-1, schema: yes)
├─ 3.2 无url (url: null, path: 无, schema: no)
├─ 3.2.1 相对 (url: relative-3-2-1, path: page-3/page-2/relative-3-2-1, schema: yes)
├─ 4 另一个无URL的顶层 (url: null, path: 无, schema: no)
├─ 4.1 子页面(无url,依赖父索引) (url: null, path: page-4/page-1, schema: yes)
├─ 4.2 有url (url: relative-4-2, path: page-4/relative-4-2, schema: yes)
├─ 4.3 有url (url: relative-4-3, path: relative-4-3, schema: no)
├─ 4.3.1 无url (url: null, path: page-4/relative-4-3/page-1, schema: yes)