Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
I
internal_regulation_manager_new
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
David Yang
internal_regulation_manager_new
Commits
4a0c4abf
Commit
4a0c4abf
authored
Sep 15, 2026
by
drigle
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: 增加拓扑图多层级联流程筛选
parent
64fcb2ae
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
177 additions
and
0 deletions
+177
-0
ProcessCascade.jsx
src/components/ProcessCascade.jsx
+176
-0
RegulationGraph.jsx
src/pages/internal_regulation_manager/RegulationGraph.jsx
+0
-0
internal-regulation.business-flow.md
...l_regulation_manager/internal-regulation.business-flow.md
+1
-0
No files found.
src/components/ProcessCascade.jsx
0 → 100644
View file @
4a0c4abf
import
{
Button
,
Checkbox
,
Popover
}
from
'@heroui/react'
;
import
{
ChevronRight
,
Close
}
from
'@/components/AppIcons'
;
import
{
useEffect
,
useMemo
,
useState
}
from
'react'
;
function
collectDescendantIds
(
node
)
{
const
ids
=
[];
const
walk
=
(
item
)
=>
{
item
.
children
.
forEach
((
child
)
=>
{
ids
.
push
(
child
.
id
);
walk
(
child
);
});
};
walk
(
node
);
return
ids
;
}
export
default
function
ProcessCascade
({
tree
=
[],
value
=
[],
isDisabled
=
false
,
onChange
})
{
const
[
columns
,
setColumns
]
=
useState
([]);
const
[
open
,
setOpen
]
=
useState
(
false
);
const
{
itemsById
,
pathsById
}
=
useMemo
(()
=>
{
const
items
=
new
Map
();
const
paths
=
new
Map
();
const
walk
=
(
item
)
=>
{
items
.
set
(
item
.
id
,
item
);
paths
.
set
(
item
.
id
,
item
.
path
);
item
.
children
.
forEach
(
walk
);
};
tree
.
forEach
(
walk
);
return
{
itemsById
:
items
,
pathsById
:
paths
};
},
[
tree
]);
const
selectedPaths
=
useMemo
(
()
=>
value
.
map
((
id
)
=>
pathsById
.
get
(
String
(
id
))).
filter
(
Boolean
),
[
pathsById
,
value
],
);
const
checkedIds
=
useMemo
(()
=>
{
const
ids
=
new
Set
();
selectedPaths
.
forEach
((
path
)
=>
{
path
.
forEach
((
node
)
=>
ids
.
add
(
node
.
id
));
const
item
=
itemsById
.
get
(
path
[
path
.
length
-
1
].
id
);
if
(
item
)
collectDescendantIds
(
item
).
forEach
((
id
)
=>
ids
.
add
(
id
));
});
return
ids
;
},
[
itemsById
,
selectedPaths
]);
useEffect
(()
=>
{
setColumns
((
current
)
=>
{
const
next
=
[];
let
items
=
tree
;
for
(
const
id
of
current
)
{
const
item
=
items
.
find
((
entry
)
=>
entry
.
id
===
String
(
id
));
if
(
!
item
?.
children
.
length
)
break
;
next
.
push
(
item
.
id
);
items
=
item
.
children
;
}
return
next
;
});
},
[
tree
]);
useEffect
(()
=>
{
if
(
!
open
||
!
selectedPaths
.
length
)
return
;
const
path
=
selectedPaths
[
selectedPaths
.
length
-
1
];
setColumns
(
path
.
slice
(
0
,
-
1
).
map
((
node
)
=>
node
.
id
));
},
[
open
]);
const
activeColumns
=
useMemo
(()
=>
{
const
result
=
[
tree
];
columns
.
forEach
((
id
)
=>
{
const
item
=
itemsById
.
get
(
String
(
id
));
if
(
item
?.
children
.
length
)
result
.
push
(
item
.
children
);
});
return
result
;
},
[
columns
,
itemsById
,
tree
]);
const
selectedLabel
=
selectedPaths
.
length
?
selectedPaths
.
map
((
path
)
=>
path
[
path
.
length
-
1
]?.
title
).
join
(
'、'
)
:
'筛选流程'
;
const
expandColumn
=
(
depth
,
item
)
=>
{
setColumns
((
current
)
=>
current
.
slice
(
0
,
depth
).
concat
(
item
.
id
));
};
const
togglePath
=
(
path
)
=>
{
const
id
=
String
(
path
[
path
.
length
-
1
].
id
);
onChange
(
value
.
includes
(
id
)
?
value
.
filter
((
item
)
=>
item
!==
id
)
:
[...
value
,
id
]);
};
return
(
<
span
className=
"relative inline-flex max-w-full shrink-0"
>
<
Popover
isOpen=
{
open
}
onOpenChange=
{
setOpen
}
>
<
Popover
.
Trigger
>
<
Button
aria
-
label=
"筛选流程"
className=
"h-10 w-72 justify-between gap-2 px-3"
isDisabled=
{
isDisabled
}
variant=
"secondary"
>
<
span
className=
{
`min-w-0 flex-1 truncate text-left ${selectedPaths.length ? 'text-foreground' : 'text-muted'}`
}
>
{
selectedLabel
}
</
span
>
{
selectedPaths
.
length
?
<
span
className=
"shrink-0 text-xs text-muted"
>
{
selectedPaths
.
length
}
</
span
>
:
null
}
</
Button
>
</
Popover
.
Trigger
>
{
selectedPaths
.
length
?
(
<
button
aria
-
label=
"清空流程筛选"
className=
"absolute right-2 top-1/2 z-10 grid size-6 -translate-y-1/2 place-items-center rounded-full text-muted hover:bg-surface-secondary hover:text-foreground"
onClick=
{
()
=>
onChange
([])
}
type=
"button"
>
<
Close
size=
{
12
}
/>
</
button
>
)
:
null
}
<
Popover
.
Content
className=
"overflow-hidden rounded-xl border border-separator bg-background shadow-lg"
placement=
"bottom start"
>
<
Popover
.
Dialog
aria
-
label=
"筛选流程"
>
<
div
className=
"flex max-h-96 overflow-x-auto"
>
{
activeColumns
.
map
((
items
,
depth
)
=>
(
<
div
className=
"max-h-96 w-56 shrink-0 overflow-y-auto border-r border-separator bg-background py-1 last:border-r-0"
key=
{
`process-column-${depth}`
}
role=
"listbox"
aria
-
label=
{
`第 ${depth + 1} 级流程`
}
>
{
items
.
map
((
item
)
=>
{
const
checked
=
checkedIds
.
has
(
item
.
id
);
const
active
=
columns
[
depth
]
===
item
.
id
;
return
(
<
div
aria
-
checked=
{
checked
}
aria
-
selected=
{
active
}
className=
{
`flex min-h-10 cursor-pointer select-none items-center gap-2 px-3 text-sm hover:bg-surface-secondary ${active ? 'bg-surface-secondary/80' : ''}`
}
key=
{
item
.
id
}
onClick=
{
()
=>
item
.
children
.
length
&&
expandColumn
(
depth
,
item
)
}
role=
"option"
title=
{
item
.
title
}
>
<
span
className=
"inline-flex shrink-0"
onClick=
{
(
event
)
=>
event
.
stopPropagation
()
}
role=
"presentation"
>
<
Checkbox
aria
-
label=
{
`选择 ${item.title}`
}
className=
"pointer-events-auto"
isSelected=
{
checked
}
onChange=
{
()
=>
togglePath
(
item
.
path
)
}
variant=
"secondary"
>
<
Checkbox
.
Content
className=
"size-4"
>
<
Checkbox
.
Control
className=
"size-4 rounded-[4px]"
>
<
Checkbox
.
Indicator
/>
</
Checkbox
.
Control
>
</
Checkbox
.
Content
>
</
Checkbox
>
</
span
>
<
span
className=
{
`min-w-0 flex-1 truncate ${checked ? 'text-foreground' : 'text-foreground/85'}`
}
>
{
item
.
title
}
</
span
>
{
item
.
children
.
length
?
(
<
ChevronRight
className=
{
`size-4 shrink-0 transition-transform ${active ? 'text-foreground' : 'text-muted'}`
}
/>
)
:
null
}
</
div
>
);
})
}
</
div
>
))
}
</
div
>
</
Popover
.
Dialog
>
</
Popover
.
Content
>
</
Popover
>
</
span
>
);
}
src/pages/internal_regulation_manager/RegulationGraph.jsx
View file @
4a0c4abf
This diff is collapsed.
Click to expand it.
src/pages/internal_regulation_manager/internal-regulation.business-flow.md
View file @
4a0c4abf
...
@@ -32,6 +32,7 @@
...
@@ -32,6 +32,7 @@
-
拓扑图沿用旧版 React Flow + Dagre 的层级画布逻辑,左侧提供“全部 / 待分类 / 节点 / 删除节点”四个列表 Tab;“节点”和“删除节点”列表支持搜索和点击定位,点击隐藏层级中的节点时会先自动展开该节点的全部祖先路径,再将画布平滑移动到目标节点并打开详情。打开时默认展开根节点和第一层流程节点,第二层及更深节点按节点右侧计数按钮逐级展开。节点支持拖拽、缩放、邻接连线、展开/折叠和双击进入关联制度详情。
-
拓扑图沿用旧版 React Flow + Dagre 的层级画布逻辑,左侧提供“全部 / 待分类 / 节点 / 删除节点”四个列表 Tab;“节点”和“删除节点”列表支持搜索和点击定位,点击隐藏层级中的节点时会先自动展开该节点的全部祖先路径,再将画布平滑移动到目标节点并打开详情。打开时默认展开根节点和第一层流程节点,第二层及更深节点按节点右侧计数按钮逐级展开。节点支持拖拽、缩放、邻接连线、展开/折叠和双击进入关联制度详情。
-
拓扑页高度锁定为当前视口可用高度,标题、工具栏和画布保持在当前屏幕内;节点列表和详情区域在容器内部滚动,页面外层不因节点数量增长而整体向下延伸。
-
拓扑页高度锁定为当前视口可用高度,标题、工具栏和画布保持在当前屏幕内;节点列表和详情区域在容器内部滚动,页面外层不因节点数量增长而整体向下延伸。
-
工具栏支持现行制度显示、已移除节点显示、现行/待新增/待修订/待废止筛选、当前版本和归档版本切换;归档版本只读,不能导入或保存。
-
工具栏支持现行制度显示、已移除节点显示、现行/待新增/待修订/待废止筛选、当前版本和归档版本切换;归档版本只读,不能导入或保存。
-
流程筛选使用多层级联路径,不将全部节点平铺到单层下拉;用户从第一层流程开始逐级展开并勾选路径。筛选保留选中路径、路径祖先和最后一个节点的子孙,不会因保留根节点路径而放行同一父级下的其他流程分支。
-
右侧详情支持编辑标题和备注、查看流程路径/制度路径/历史版本、折叠子节点和打开关联制度;右键可添加流程节点或描述。
-
右侧详情支持编辑标题和备注、查看流程路径/制度路径/历史版本、折叠子节点和打开关联制度;右键可添加流程节点或描述。
-
当前版本支持上传
`.xmind`
(兼容
`content.json`
与
`content.xml`
),会将
`《制度名称》`
主题匹配到制度记录,生成流程节点及连线,并同步
`graph_process`
分类;也支持将待处理制度拖入选中节点下。
-
当前版本支持上传
`.xmind`
(兼容
`content.json`
与
`content.xml`
),会将
`《制度名称》`
主题匹配到制度记录,生成流程节点及连线,并同步
`graph_process`
分类;也支持将待处理制度拖入选中节点下。
-
保存写入
`internal_regulation_graph`
的
`graph_info.nodes/edges`
,导出生成制度列表 CSV;XMind 导入、节点编辑和拖拽归类均需保存后持久化图谱。
-
保存写入
`internal_regulation_graph`
的
`graph_info.nodes/edges`
,导出生成制度列表 CSV;XMind 导入、节点编辑和拖拽归类均需保存后持久化图谱。
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment