Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
I
integrity_risk_prevention
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
integrity_risk_prevention
Commits
394be253
Commit
394be253
authored
Aug 27, 2026
by
Andy-bubu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: align grouped list headers and interactions
parent
cb8971aa
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
72 additions
and
7 deletions
+72
-7
ui-architecture.md
docs/ui-architecture.md
+1
-0
xinyuan-design-system.md
docs/xinyuan-design-system.md
+1
-0
index.jsx
src/components/record-workbench/index.jsx
+68
-7
integrity-risk-prevention.business-flow.md
...isk_prevention/integrity-risk-prevention.business-flow.md
+2
-0
No files found.
docs/ui-architecture.md
View file @
394be253
...
...
@@ -25,6 +25,7 @@
-
Modal 是独立 Overlay/L1 平面;查看态字段组使用
`Surface secondary`
/L2。详情中的关联记录是 L2 内的静态 L3 子区域,使用 HeroUI
`Surface tertiary`
包裹共享
`DataTable`
,并通过 HeroUI Pro DataGrid 官方
`secondary`
variant 区分表头和 L3 背景;页面不得覆盖 DataGrid 的 BEM、slot、背景或圆角。
-
业务列表页面标题由 Shell 的 HeroUI Pro Navbar 统一呈现,
`RecordWorkbench`
内容区不再重复渲染同名
`<h2>`
,以避免标题重复并让搜索/工具栏保持首屏优先级。
-
`DataTable`
是唯一业务表格边界:它负责列宽计算、真实宽表检测、内部滚动、状态类、原生选择、ActionBar、空/加载状态、Pagination 和统一排版 Token;页面只提供业务列与回调。
`src/design-system/data-grid.css`
只负责共享几何与排版,不绘制 DataGrid 背景、描边、圆角、阴影或状态。
-
`RecordWorkbench`
从当前 Grid View 的
`settings.groups`
派生列分组、列数、字段摘要和两层表头;分组按钮的 Hover/Focus 预览与点击显隐只影响共享 DataGrid 的呈现列,不修改 View 配置、查询字段或业务记录。表头预览使用 HeroUI 语义 Token,不由页面 CSS 重画。
-
`XinyuanModal`
与直接 HeroUI Modal 页面均使用
`rc-dialog-panel--{size}`
共享宽度阶梯;不得在页面里通过颜色、阴影、圆角或旧 BEM class 重画弹窗。
-
弹窗头部说明由 HeroUI
`Description`
负责;字段标签由共享
`getFieldDisplayLabel`
从字段定义和中文别名表解析,
`metadata.*`
只存在于数据层。文本、选择、日期、人员/引用和附件的提示均由对应 HeroUI 控件在内部展示,禁止再在控件下方复制同一句自动提示。
-
4xl 动态表单由共享
`DynamicRecordDialog`
负责等宽双列编排,字段类型决定是否跨列;独立流程页没有 AppShell 时保留
`RecordWorkbench`
内容标题,主应用列表通过
`showContentTitle={false}`
只使用 Navbar 标题。
...
...
docs/xinyuan-design-system.md
View file @
394be253
...
...
@@ -31,6 +31,7 @@
-
全局
`DataTable`
必须向 HeroUI Pro
`DataGrid`
传递 populated/loading/empty 状态类;populated 状态的 root、scroll、resizable、content 链使用
`min-height: 0`
并按真实表格高度收缩,不能保留空状态的最小高度。
-
DataGrid 普通字段单行截断,详情关联表的长文本最多两行;完整值通过共享 HeroUI
`Tooltip`
提供。页面不得使用
`whitespace-normal`
、
`font-mono`
或原生
`title`
来替代表格文本契约。
-
DataGrid 表头、普通字段、主字段、次字段和 Chip 统一使用
`--rc-data-grid-*`
Token 与
`pm-data-grid-*`
共享排版类,页面不得单独声明表格字重或颜色。
-
View
`settings.groups`
驱动列分组:工具栏分组按钮显示真实分组名与列数,Tooltip 列出所含字段;Hover/Focus 时仅通过语义 Token 联动高亮该组表头,点击切换整组列显隐。分组字段的 DataGrid 表头采用“分组名 + 字段名”两层结构,分组名称按
`label`
、
`title`
、
`name`
的顺序解析,不得硬编码业务组名或另建页面状态。
-
DataGrid 的最小列宽总和超过 viewport 时,只允许共享 DataGrid 内部横向滚动;页面和 Modal 不得被宽表撑出。宽度链必须保持
`width: 100%`
与实际内容
`min-width: 100%`
。
## 验收补充
...
...
src/components/record-workbench/index.jsx
View file @
394be253
...
...
@@ -21,7 +21,7 @@ import {
}
from
'@/components/AppIcons'
;
import
FilterSelect
from
'@/components/FilterSelect'
;
import
FormDatePicker
from
'@/components/FormDatePicker'
;
import
{
formatFieldValue
,
getFieldValue
}
from
'@/utils/subjectView'
;
import
{
formatFieldValue
,
getFieldValue
,
normalizeText
}
from
'@/utils/subjectView'
;
import
{
Alert
,
Button
,
...
...
@@ -156,8 +156,16 @@ function buildColumnGroupMeta(columnGroups = [], columns = []) {
return
{
...
group
,
id
,
name
:
group
?.
name
||
id
,
name
:
normalizeText
(
group
?.
label
)
||
normalizeText
(
group
?.
title
)
||
normalizeText
(
group
?.
name
)
||
id
,
children
,
columnLabels
:
children
.
map
((
field
)
=>
{
const
column
=
columns
.
find
((
item
)
=>
item
.
field
===
field
);
return
String
(
column
?.
label
||
field
).
trim
();
}),
};
})
.
filter
((
group
)
=>
group
.
children
.
length
>
0
);
...
...
@@ -332,28 +340,65 @@ function getWorkbenchColumnWidth(column, stickyMeta) {
return
Math
.
min
(
readableWidth
,
280
);
}
function
ColumnGroupControl
({
group
,
collapsed
,
index
,
onToggle
})
{
function
ColumnGroupControl
({
group
,
collapsed
,
index
,
onPreviewChange
,
onToggle
,
})
{
const
Icon
=
index
%
2
===
0
?
Group
:
ChartBarSquareIcon
;
const
actionLabel
=
`
${
collapsed
?
'显示'
:
'隐藏'
}${
group
.
name
}
列`
;
const
columnSummary
=
group
.
columnLabels
.
join
(
'、'
);
return
(
<
Tooltip
delay=
{
30
0
}
>
<
Tooltip
closeDelay=
{
80
}
delay=
{
15
0
}
>
<
ToggleButton
size=
"sm"
isSelected=
{
collapsed
}
onChange=
{
onToggle
}
onBlur=
{
()
=>
onPreviewChange
(
null
)
}
onFocus=
{
()
=>
onPreviewChange
(
group
.
id
)
}
onHoverEnd=
{
()
=>
onPreviewChange
(
null
)
}
onHoverStart=
{
()
=>
onPreviewChange
(
group
.
id
)
}
aria
-
label=
{
actionLabel
}
>
<
Icon
size=
{
16
}
/>
<
span
>
{
group
.
name
}
</
span
>
<
span
aria
-
hidden=
"true"
className=
"text-xs opacity-70"
>
{
group
.
children
.
length
}
列
</
span
>
</
ToggleButton
>
<
Tooltip
.
Content
>
{
actionLabel
}
(共
{
group
.
children
.
length
}
个字段)
<
Tooltip
.
Content
className=
"max-w-80"
placement=
"bottom"
>
<
div
className=
"space-y-1"
>
<
div
className=
"font-medium"
>
{
actionLabel
}
</
div
>
<
div
className=
"text-xs opacity-80"
>
包含:
{
columnSummary
}
</
div
>
</
div
>
</
Tooltip
.
Content
>
</
Tooltip
>
);
}
function
ColumnHeaderLabel
({
label
,
groupName
})
{
if
(
!
groupName
)
{
return
label
;
}
return
(
<
span
className=
"flex min-w-0 flex-col items-start gap-0.5 py-0.5"
>
<
span
aria
-
hidden=
"true"
className=
"text-[11px] font-normal leading-4 text-muted"
>
{
groupName
}
</
span
>
<
span
className=
"text-xs font-medium leading-4 text-foreground"
>
{
label
}
</
span
>
</
span
>
);
}
function
renderRowActionButton
({
action
,
isDisabled
,
onPress
})
{
const
Icon
=
action
.
icon
||
DEFAULT_ROW_ACTION_ICONS
[
action
.
key
];
...
...
@@ -450,6 +495,7 @@ export default function RecordWorkbench({
const
[
drawerDirty
,
setDrawerDirty
]
=
useState
(
false
);
const
[
filtersExpanded
,
setFiltersExpanded
]
=
useState
(
false
);
const
[
collapsedColumnGroups
,
setCollapsedColumnGroups
]
=
useState
({});
const
[
previewColumnGroupId
,
setPreviewColumnGroupId
]
=
useState
(
null
);
const
[
columnGroupAnnouncement
,
setColumnGroupAnnouncement
]
=
useState
(
''
);
const
[
expandedRowIds
,
setExpandedRowIds
]
=
useState
({});
const
filterFieldVariant
=
'secondary'
;
...
...
@@ -745,9 +791,23 @@ export default function RecordWorkbench({
: []),
...stickyColumns.orderedColumns.map((column, columnIndex) => {
const stickyMeta = stickyColumns.stickyMeta[column.field];
const columnGroupId = columnGroupMeta.fieldToGroup[column.field];
const columnGroup = columnGroupId
? columnGroupMeta.groupById[columnGroupId]
: null;
const isPreviewedGroupColumn = columnGroupId === previewColumnGroupId;
return {
key: column.field,
title: column.label,
title: (
<ColumnHeaderLabel
groupName={columnGroup?.name}
label={column.label}
/>
),
headerClassName: clsx(
column.headerClassName,
isPreviewedGroupColumn && 'bg-accent-soft text-accent-soft-foreground',
),
width: getWorkbenchColumnWidth(column, stickyMeta),
minWidth: getWorkbenchColumnWidth(column, stickyMeta),
pin:
...
...
@@ -1064,6 +1124,7 @@ export default function RecordWorkbench({
group={group}
collapsed={Boolean(collapsedColumnGroups[group.id])}
index={index}
onPreviewChange={setPreviewColumnGroupId}
onToggle={() => toggleColumnGroup(group.id)}
/>
))}
...
...
src/pages/integrity_risk_prevention/integrity-risk-prevention.business-flow.md
View file @
394be253
...
...
@@ -21,6 +21,8 @@
1.
四个列表页继续使用当前项目的
`SubjectRecordWorkbench`
和
`RecordWorkbench`
。
2.
表格列、分组、排序、筛选、视图限制和字段选项由线上 Subject/View 配置驱动。
`settings.groups`
的分组入口显示真实组名、列数和字段清单;Hover/Focus 会预览对应表头,
点击只切换该组列的显示状态。分组字段表头同时展示分组名和字段名,不改变查询或记录数据。
3.
详情继续使用当前
`RecordDetailDrawer`
,列表页不复制或改写详情抽屉逻辑;可编辑页面
的字段维护统一从详情侧栏进入。
4.
新建、复制和软删除沿用工作台既有行为;列表行内不提供独立编辑按钮,业务字段写入
...
...
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