Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
O
oa_process_monitor
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
oa_process_monitor
Commits
70f36d82
Commit
70f36d82
authored
Sep 03, 2026
by
Andy-bubu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: refine xinyuan colors and list interactions
parent
bb0fb715
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
153 additions
and
58 deletions
+153
-58
UI_UX_AUDIT.md
docs/UI_UX_AUDIT.md
+1
-1
ui-architecture.md
docs/ui-architecture.md
+9
-1
xinyuan-design-system.md
docs/xinyuan-design-system.md
+16
-1
xinyuan-ui-audit.md
docs/xinyuan-ui-audit.md
+4
-2
shell.css
src/design-system/shell.css
+6
-1
theme.css
src/design-system/theme.css
+86
-24
tokens.css
src/design-system/tokens.css
+16
-13
ProcessMonitor.jsx
src/pages/process_monitor/ProcessMonitor.jsx
+6
-6
ProcessTemplateList.jsx
src/pages/process_monitor/ProcessTemplateList.jsx
+4
-4
process-monitor.business-flow.md
src/pages/process_monitor/process-monitor.business-flow.md
+3
-3
tailwind.css
src/tailwind.css
+2
-2
No files found.
docs/UI_UX_AUDIT.md
View file @
70f36d82
...
...
@@ -27,7 +27,7 @@
## 本轮迁移基线
-
主品牌色统一为
`#
9E1B1B`
,禁止将 sky/teal/cya
n/rose 作为可见品牌色。
-
主品牌色统一为
`#
DA241A`
,禁止将 sky/teal/cyan/gree
n/rose 作为可见品牌色。
-
使用本地完整 HeroUI Pro 镜像及 HeroUI 样式层。
-
同步已验收鑫元 Token、Shell 和组件 CSS。
-
登录页使用鑫元红 Logo、紧凑品牌区、统一输入高度和不透明浅红 filled/autofill 状态。
...
...
docs/ui-architecture.md
View file @
70f36d82
...
...
@@ -35,10 +35,18 @@
-
Surface 层级为 page background -> surface/default -> surface-secondary;overlay 是独立平面。
-
不在页面覆盖 HeroUI slot、BEM、伪元素、颜色、边框、圆角、阴影或交互状态。
## 品牌色与数据可视化
-
`src/design-system/theme.css`
中
`--accent`
、
`--focus`
、
`--primary`
固定为
`#DA241A`
,
由 HeroUI 官方状态变量承接按钮、选中、Hover、Pressed 和 Focus;页面不再声明另一套 Primary 色。
-
图表通过
`--rc-chart-*`
使用统一的品牌红、暖色、中性色和灰蓝色低冲突序列,禁止绿色系和随机彩虹色。
-
KPI compound API 的图标 tone 仅引用共享
`--rc-metric-tone-*`
,不在页面写入 hex/OKLCH 颜色。
## 列表与反馈
-
流程列表默认每页
10 条,并可通过 HeroUI Autocomplete 切换 10/
20/50/100 条,使用 Pro DataGrid 与 HeroUI compound Pagination。
-
流程列表默认每页
20 条,并可通过宽度 128px 的 HeroUI Autocomplete 切换
20/50/100 条,使用 Pro DataGrid 与 HeroUI compound Pagination。
-
列表模块使用基准的透明三层结构:独立数据集标题行、
`rc-page-toolbar`
命令行、
`rc-list-data-stack`
数据与分页;不使用 Card 或页面外观把三层框在一起。
-
DataGrid 列表外层使用
`rc-data-table-sticky`
,滚动容器使用
`data-table-scroll`
;横向 overscroll 在表格内消化,纵向 overscroll 允许向
`app-shell-content-scroll`
传递,滚到数据首尾后可继续浏览页面分页区域。
-
搜索位于左侧,业务操作在右,主操作最右;移动端搜索独占行。
-
成功反馈使用 HeroUI toast;需要用户处理的错误保留上下文 Alert。
-
查看详情使用单一 secondary Surface,编辑/确认使用 Modal 或 AlertDialog。
...
...
docs/xinyuan-design-system.md
View file @
70f36d82
...
...
@@ -6,6 +6,19 @@
-
视觉和交互唯一运行基准为已确认完成的“审计项目管理”应用。
-
页面不得自定义 HeroUI/HeroUI Pro 的颜色、背景、描边、圆角、阴影或交互状态。
## 品牌与图表配色(2026-09)
-
鑫元唯一 Primary Brand Color 为
`#DA241A`
。HeroUI 的
`accent`
、
`focus`
、
`primary`
及
`rc-brand-primary`
均固定到该值;Hover 使用
`#C91F17`
,Pressed 使用
`#B51B14`
,
Disabled 使用低透明度品牌红。浅色和深色模式不得由 HeroUI 默认主题改写品牌色。
-
图表只使用
`--xinyuan-chart-1`
到
`--xinyuan-chart-16`
/
`--rc-chart-*`
Token:
`#DA241A, #B83A32, #C95A52, #D47A70, #A65A45, #B87958, #C99772,
#6F6674, #807783, #938B96, #4F6380, #61758F, #74879A, #8A6F63,
#9A8174, #5F5A61`
。
-
色板按品牌红深浅、暖色、中性色、灰蓝色排序,禁止绿色、青色、荧光色和彩虹式高冲突相邻配色。
单系列图表使用
`--rc-chart-primary`
;同一指标使用同一语义 Token,分类数量增加时按稳定业务 key 分配颜色。
-
KPI 图标色也从同一克制色板取值,Card 主体保持中性,不以页面私有颜色覆盖共享 Token。
## 字体与样式入口
-
`.umirc.ts`
通过常驻
`<link>`
加载
`public/fonts/inter.css`
,字体文件固定为 Inter 400/500/600 拉丁字符子集。
...
...
@@ -37,6 +50,8 @@
-
三个以上筛选字段使用
`Surface variant="default"`
;内部字段统一
`secondary`
;一到两个字段不额外套 Surface。
-
一到两个结构化筛选字段与列表标题、工具栏、DataGrid 和 Pagination 归入同一个列表堆栈;少量高频字段使用紧凑行内筛选,单个低频字段可由列表工具栏的 HeroUI Popover 按需展开,不单独占用 Surface。
-
列表标题、工具栏与 Pagination 透明无框;DataGrid 自己拥有 20px 数据 Surface。
-
长列表使用 DataGrid 的
`data-table-scroll`
滚动容器:横向滚动保留在表格内,纵向使用
`overscroll-behavior-y: auto`
。滚到首行或末行后继续滚动会自然交给页面容器,确保顶部工具栏和底部分页始终可达。
-
页面一级模块间距 32px,普通模块 24px,紧密列表/KPI/工具栏 16px;移动端分别收敛为 24px/16px。
## 控件
...
...
@@ -46,7 +61,7 @@
-
普通业务文字 Button 不带装饰图标;主操作在最右。
-
详情/表单使用 HeroUI Modal;查看态整组字段放一个 secondary Surface,编辑态移除该 Surface。
-
DataGrid 使用原生 selection、排序、固定列、横向滚动、ActionBar、EmptyState 和 compound Pagination。
-
流程业务列表默认每页
10 条,分页条使用 HeroUI Autocomplete 提供 10/
20/50/100 条选择;通知中心仍固定每页 10 条。
-
流程业务列表默认每页
20 条,分页条使用宽度 128px 的 HeroUI Autocomplete 提供
20/50/100 条选择;通知中心仍固定每页 10 条。
## 主题与资产
...
...
docs/xinyuan-ui-audit.md
View file @
70f36d82
...
...
@@ -37,8 +37,10 @@
-
筛选使用 HeroUI SearchField/Autocomplete,弹窗使用 Modal/AlertDialog,分页固定 10 条并使用 compound Pagination。
-
详情查看态只保留一个
`Surface secondary`
;页面不再定义组件背景、颜色、描边、圆角、阴影或交互状态。
-
删除不可达的 Catalyst、RecordDetailDrawer、record-workbench、FilterSelect 和旧组件样式文件,旧组件引用扫描为零。
-
`theme.css`
与技能权威副本逐字节一致
;
`tokens.css`
、
`shell.css`
、
`tailwind.css`
与审计项目管理基准一致。
-
`theme.css`
沿用技能权威结构,并按本次鑫元品牌专项将 HeroUI 主色固定为
`#DA241A`
;
`tokens.css`
、
`shell.css`
、
`tailwind.css`
与审计项目管理基准一致。
-
本应用无业务图表页面,图表迁移和 Tooltip 验收标记为不适用,不新增虚构图表。
-
共享图表 Token 已专项收敛为鑫元红及低饱和暖色、中性色、灰蓝色序列;不存在绿色或彩虹式默认系列。
-
HeroUI
`accent/focus/primary`
和共享
`rc-brand-primary`
已固定为
`#DA241A`
,浅色/深色模式均保持一致。
## 本次共享同步
...
...
@@ -50,7 +52,7 @@
-
未改变路由、Subject、API URL、请求方法、payload、metadata 字段或 Reference ID-only 协议。
-
未改变模板同步、分组回写、取消监控、动态列生成、附件链接获取、权限判定、保存回调或请求时机。
-
流程列表默认每页
10 条,并新增 HeroUI Autocomplete 条数选择器(10/
20/50/100);查询仍使用原有
`page`
/
`page_size`
协议。
-
流程列表默认每页
20 条,并新增 128px HeroUI Autocomplete 条数选择器(
20/50/100);查询仍使用原有
`page`
/
`page_size`
协议。
-
401 仍在相同响应时机清理登录态并跳转登录页,只修正为带 Umi base 的应用内地址。
## 通知中心审计
...
...
src/design-system/shell.css
View file @
70f36d82
...
...
@@ -744,7 +744,12 @@
max-height
:
min
(
60
dvh
,
42rem
);
overflow-x
:
auto
;
overflow-y
:
auto
;
overscroll-behavior
:
contain
;
/* Keep horizontal overflow inside the grid, but let vertical wheel/touch
scrolling continue into the page once the last row is reached. This
keeps the pagination area reachable without requiring a second gesture
surface or a nested scroll lock. */
overscroll-behavior-x
:
contain
;
overscroll-behavior-y
:
auto
;
}
/* DataGrid adds a non-scrolling resize wrapper. Let sticky headers use the
...
...
src/design-system/theme.css
View file @
70f36d82
...
...
@@ -11,7 +11,24 @@
[
data-theme
=
"light"
],
[
data-theme
=
"default"
]
{
/* Theme Colors (Light Mode) */
--accent
:
oklch
(
57.14%
0.2156
29.20
);
/* Xinyuan brand primary; HeroUI accent remains stable in every mode. */
--accent
:
#DA241A
;
--accent-hover
:
#C91F17
;
--accent-pressed
:
#B51B14
;
--accent-disabled
:
color-mix
(
in
srgb
,
#DA241A
42%
,
transparent
);
--primary
:
#DA241A
;
--primary-foreground
:
#ffffff
;
--primary-50
:
#FFF4F3
;
--primary-100
:
#FFE3E0
;
--primary-200
:
#FFC7C2
;
--primary-300
:
#F89A92
;
--primary-400
:
#EB675D
;
--primary-500
:
#DA241A
;
--primary-600
:
#C91F17
;
--primary-700
:
#B51B14
;
--primary-800
:
#8F1712
;
--primary-900
:
#6F120F
;
--primary-950
:
#480B09
;
--accent-foreground
:
oklch
(
99.11%
0
0
);
--background
:
oklch
(
97.02%
0.0000
29.20
);
--border
:
oklch
(
90.00%
0.0000
29.20
);
...
...
@@ -23,7 +40,7 @@
--field-border
:
transparent
;
--field-foreground
:
oklch
(
21.03%
0.0000
29.20
);
--field-placeholder
:
oklch
(
55.17%
0.0000
29.20
);
--focus
:
oklch
(
57.14%
0.2156
29.20
)
;
--focus
:
#DA241A
;
--foreground
:
oklch
(
21.03%
0.0000
29.20
);
--muted
:
oklch
(
55.17%
0.0000
29.20
);
--overlay
:
oklch
(
100.00%
0.0000
29.20
);
...
...
@@ -32,8 +49,8 @@
--segment
:
oklch
(
100.00%
0.0000
29.20
);
--segment-foreground
:
oklch
(
21.03%
0.0000
29.20
);
--separator
:
oklch
(
92.00%
0.0000
29.20
);
--success
:
oklch
(
73.29%
0.1935
123.85
)
;
--success-foreground
:
oklch
(
21.03%
0.0059
123.85
)
;
--success
:
#61758F
;
--success-foreground
:
#ffffff
;
--surface
:
oklch
(
100.00%
0.0000
29.20
);
--surface-foreground
:
oklch
(
21.03%
0.0000
29.20
);
--surface-secondary
:
oklch
(
95.24%
0.0000
29.20
);
...
...
@@ -70,22 +87,23 @@
* Ant Design remains the icon source. Resolve these CSS variables to
* concrete colors before assigning them to an ECharts option object.
*/
--xinyuan-chart-1
:
#d92d20
;
--xinyuan-chart-2
:
#ef4444
;
--xinyuan-chart-3
:
#f97316
;
--xinyuan-chart-4
:
#f59e0b
;
--xinyuan-chart-5
:
#22c55e
;
--xinyuan-chart-6
:
#14b87a
;
--xinyuan-chart-7
:
#06b6d4
;
--xinyuan-chart-8
:
#0ea5e9
;
--xinyuan-chart-9
:
#3b82f6
;
--xinyuan-chart-10
:
#6366f1
;
--xinyuan-chart-11
:
#8b5cf6
;
--xinyuan-chart-12
:
#7c3aed
;
--xinyuan-chart-13
:
#b42318
;
--xinyuan-chart-14
:
#84cc16
;
--xinyuan-chart-15
:
#a855f7
;
--xinyuan-chart-16
:
#64748b
;
/* Ordered low-conflict palette: brand red, warm neutrals, gray-blue. */
--xinyuan-chart-1
:
#DA241A
;
--xinyuan-chart-2
:
#B83A32
;
--xinyuan-chart-3
:
#C95A52
;
--xinyuan-chart-4
:
#D47A70
;
--xinyuan-chart-5
:
#A65A45
;
--xinyuan-chart-6
:
#B87958
;
--xinyuan-chart-7
:
#C99772
;
--xinyuan-chart-8
:
#6F6674
;
--xinyuan-chart-9
:
#807783
;
--xinyuan-chart-10
:
#938B96
;
--xinyuan-chart-11
:
#4F6380
;
--xinyuan-chart-12
:
#61758F
;
--xinyuan-chart-13
:
#74879A
;
--xinyuan-chart-14
:
#8A6F63
;
--xinyuan-chart-15
:
#9A8174
;
--xinyuan-chart-16
:
#5F5A61
;
--xinyuan-chart-grid
:
#e8e8e8
;
--xinyuan-chart-axis
:
#737373
;
--xinyuan-chart-label
:
#737373
;
...
...
@@ -101,7 +119,24 @@
[
data-theme
=
"dark"
]
{
color-scheme
:
dark
;
/* Theme Colors (Dark Mode) */
--accent
:
oklch
(
57.14%
0.2156
29.20
);
/* Keep brand identity fixed in dark mode; surfaces provide contrast. */
--accent
:
#DA241A
;
--accent-hover
:
#C91F17
;
--accent-pressed
:
#B51B14
;
--accent-disabled
:
color-mix
(
in
srgb
,
#DA241A
42%
,
transparent
);
--primary
:
#DA241A
;
--primary-foreground
:
#ffffff
;
--primary-50
:
#FFF4F3
;
--primary-100
:
#FFE3E0
;
--primary-200
:
#FFC7C2
;
--primary-300
:
#F89A92
;
--primary-400
:
#EB675D
;
--primary-500
:
#DA241A
;
--primary-600
:
#C91F17
;
--primary-700
:
#B51B14
;
--primary-800
:
#8F1712
;
--primary-900
:
#6F120F
;
--primary-950
:
#480B09
;
--accent-foreground
:
oklch
(
99.11%
0
0
);
--background
:
oklch
(
12.00%
0.0000
29.20
);
--border
:
oklch
(
28.00%
0.0000
29.20
);
...
...
@@ -113,7 +148,7 @@
--field-border
:
transparent
;
--field-foreground
:
oklch
(
99.11%
0.0000
29.20
);
--field-placeholder
:
oklch
(
70.50%
0.0000
29.20
);
--focus
:
oklch
(
57.14%
0.2156
29.20
)
;
--focus
:
#DA241A
;
--foreground
:
oklch
(
99.11%
0.0000
29.20
);
--muted
:
oklch
(
70.50%
0.0000
29.20
);
--overlay
:
oklch
(
21.03%
0.0000
29.20
);
...
...
@@ -122,8 +157,8 @@
--segment
:
oklch
(
39.64%
0.0000
29.20
);
--segment-foreground
:
oklch
(
99.11%
0.0000
29.20
);
--separator
:
oklch
(
25.00%
0.0000
29.20
);
--success
:
oklch
(
73.29%
0.1935
123.85
)
;
--success-foreground
:
oklch
(
21.03%
0.0059
123.85
)
;
--success
:
#74879A
;
--success-foreground
:
#ffffff
;
--surface
:
oklch
(
21.03%
0.0000
29.20
);
--surface-foreground
:
oklch
(
99.11%
0.0000
29.20
);
--surface-secondary
:
oklch
(
25.70%
0.0000
29.20
);
...
...
@@ -132,4 +167,31 @@
--surface-tertiary-foreground
:
oklch
(
99.11%
0.0000
29.20
);
--warning
:
oklch
(
82.03%
0.1388
49.38
);
--warning-foreground
:
oklch
(
21.03%
0.0059
49.38
);
/* Chart tokens stay identical across light and dark modes. */
--xinyuan-chart-1
:
#DA241A
;
--xinyuan-chart-2
:
#B83A32
;
--xinyuan-chart-3
:
#C95A52
;
--xinyuan-chart-4
:
#D47A70
;
--xinyuan-chart-5
:
#A65A45
;
--xinyuan-chart-6
:
#B87958
;
--xinyuan-chart-7
:
#C99772
;
--xinyuan-chart-8
:
#6F6674
;
--xinyuan-chart-9
:
#807783
;
--xinyuan-chart-10
:
#938B96
;
--xinyuan-chart-11
:
#4F6380
;
--xinyuan-chart-12
:
#61758F
;
--xinyuan-chart-13
:
#74879A
;
--xinyuan-chart-14
:
#8A6F63
;
--xinyuan-chart-15
:
#9A8174
;
--xinyuan-chart-16
:
#5F5A61
;
--xinyuan-chart-grid
:
#e8e8e8
;
--xinyuan-chart-axis
:
#737373
;
--xinyuan-chart-label
:
#737373
;
--xinyuan-chart-tooltip-background
:
#ffffff
;
--xinyuan-chart-tooltip-border
:
#dedede
;
--xinyuan-chart-tooltip-foreground
:
#222222
;
--xinyuan-chart-tooltip-shadow
:
0
16px
40px
rgb
(
15
23
42
/
14%
);
--xinyuan-chart-legend-font-size
:
0.75rem
;
--xinyuan-chart-legend-line-height
:
1rem
;
}
src/design-system/tokens.css
View file @
70f36d82
...
...
@@ -2,9 +2,12 @@
.light
,
.default
,
[
data-theme
=
'light'
],
[
data-theme
=
'default'
]
{
[
data-theme
=
'default'
],
.dark
,
[
data-theme
=
'dark'
]
{
/* Xinyuan aliases and extension tokens. HeroUI core tokens are owned by theme.css. */
--rc-brand-primary
:
var
(
--accent
);
--rc-brand-primary
:
#DA241A
;
--rc-brand-on-primary
:
#ffffff
;
--rc-brand-light
:
color-mix
(
in
oklab
,
var
(
--accent
)
84%
,
white
);
--rc-brand-dark
:
color-mix
(
in
oklab
,
var
(
--accent
)
82%
,
black
);
...
...
@@ -92,14 +95,14 @@
0
4px
12px
rgb
(
15
23
42
/
2%
);
/* KPI icon surfaces. Card bodies remain neutral; only the icon well carries tone. */
--rc-metric-tone-info
:
oklch
(
55%
0.14
255
);
--rc-metric-tone-success
:
oklch
(
54%
0.13
145
);
--rc-metric-tone-teal
:
oklch
(
55%
0.1
205
);
--rc-metric-tone-danger
:
oklch
(
52%
0.17
25
);
--rc-metric-tone-warning
:
oklch
(
62%
0.12
75
);
--rc-metric-tone-violet
:
oklch
(
56%
0.12
300
);
--rc-metric-tone-indigo
:
oklch
(
53%
0.13
275
);
--rc-metric-tone-coral
:
oklch
(
60%
0.12
48
);
--rc-metric-tone-info
:
var
(
--rc-chart-11
);
--rc-metric-tone-success
:
var
(
--rc-chart-2
);
--rc-metric-tone-teal
:
var
(
--rc-chart-9
);
--rc-metric-tone-danger
:
var
(
--rc-chart-1
);
--rc-metric-tone-warning
:
var
(
--rc-chart-6
);
--rc-metric-tone-violet
:
var
(
--rc-chart-8
);
--rc-metric-tone-indigo
:
var
(
--rc-chart-12
);
--rc-metric-tone-coral
:
var
(
--rc-chart-3
);
--rc-metric-tone-neutral
:
var
(
--muted
);
--rc-metric-tone-info-soft
:
color-mix
(
in
oklab
,
...
...
@@ -167,9 +170,9 @@
--rc-chart-primary
:
var
(
--rc-chart-1
);
--rc-chart-risk
:
var
(
--rc-chart-1
);
--rc-chart-warning
:
var
(
--rc-chart-3
);
--rc-chart-positive
:
var
(
--rc-chart-
7
);
--rc-chart-comparison
:
var
(
--rc-chart-
5
);
--rc-chart-neutral
:
var
(
--rc-chart-
8
);
--rc-chart-positive
:
var
(
--rc-chart-
2
);
--rc-chart-comparison
:
var
(
--rc-chart-
11
);
--rc-chart-neutral
:
var
(
--rc-chart-
9
);
--rc-chart-legend-font-size
:
var
(
--xinyuan-chart-legend-font-size
);
--rc-chart-legend-line-height
:
var
(
--xinyuan-chart-legend-line-height
);
}
src/pages/process_monitor/ProcessMonitor.jsx
View file @
70f36d82
...
...
@@ -10,8 +10,8 @@ import { addTemplatesToGroup, createProcessGroup, loadProcessGroup, loadProcessM
import
{
useEffect
,
useMemo
,
useState
}
from
'react'
;
import
{
useNavigate
,
useSearchParams
}
from
'umi'
;
const
PAGE_SIZE
=
1
0
;
const
PAGE_SIZE_OPTIONS
=
[
10
,
20
,
50
,
100
];
const
PAGE_SIZE
=
2
0
;
const
PAGE_SIZE_OPTIONS
=
[
20
,
50
,
100
];
const
EMPTY_DEPARTMENT_KEY
=
'__all_departments__'
;
function
Metric
({
label
,
value
,
icon
:
Icon
,
tone
})
{
...
...
@@ -44,7 +44,7 @@ function PagePagination({ page, pageSize, total, onPageChange, onPageSizeChange
<
div
className=
"flex min-w-0 flex-wrap items-center justify-between gap-3"
>
<
div
className=
"flex min-w-0 shrink-0 items-center gap-3"
>
<
span
className=
"min-w-0 text-sm text-muted"
>
共
{
total
}
条,第
{
total
?
page
+
1
:
0
}
/
{
total
?
totalPages
:
0
}
页
</
span
>
<
XinyuanAutocomplete
aria
-
label=
"每页条数"
className=
"w-
24
shrink-0"
options=
{
PAGE_SIZE_OPTIONS
.
map
((
value
)
=>
({
id
:
String
(
value
),
label
:
`${value} 条/页`
}))
}
placeholder=
"每页条数"
selectedKey=
{
String
(
pageSize
)
}
showSearch=
{
false
}
valueText=
{
`${pageSize} 条/页`
}
variant=
"secondary"
onSelectionChange=
{
(
key
)
=>
onPageSizeChange
(
Number
(
key
))
}
/>
<
XinyuanAutocomplete
aria
-
label=
"每页条数"
className=
"w-
32
shrink-0"
options=
{
PAGE_SIZE_OPTIONS
.
map
((
value
)
=>
({
id
:
String
(
value
),
label
:
`${value} 条/页`
}))
}
placeholder=
"每页条数"
selectedKey=
{
String
(
pageSize
)
}
showSearch=
{
false
}
valueText=
{
`${pageSize} 条/页`
}
variant=
"secondary"
onSelectionChange=
{
(
key
)
=>
onPageSizeChange
(
Number
(
key
))
}
/>
</
div
>
<
Pagination
className=
"ml-auto w-auto shrink-0"
size=
"sm"
>
<
Pagination
.
Content
>
...
...
@@ -240,15 +240,15 @@ export default function ProcessMonitorPage() {
</div>
<div className="rc-list-data-stack">
<section className="rc-list-data-grid
"><DataGrid allowsColumnResize aria-label="流程监控模板列表" className="pm-data-grid" columns={listColumns} contentClassName="min-w-[1074px]" data={loading ? [] : pagedTemplates} getRowId={(template) => template._id || template.name} renderEmptyState={() => loading ? <div className="py-8 text-sm text-muted">正在加载流程监控列表...</div> : <DataEmptyState title={activeGroup ? '当前分组还没有监控模板' : '暂无可展示模板'} action={canManage && activeGroup ? <Button size="sm" variant="secondary" onPress={() => setAddTemplateOpen(true)}>添加监控模板</Button> : null} />} scrollContainerClassName="pm-data-grid
-scroll" verticalAlign="middle" /></section>
<section className="rc-list-data-grid
rc-data-table-sticky"><DataGrid allowsColumnResize aria-label="流程监控模板列表" className="pm-data-grid" columns={listColumns} contentClassName="min-w-[1074px]" data={loading ? [] : pagedTemplates} getRowId={(template) => template._id || template.name} renderEmptyState={() => loading ? <div className="py-8 text-sm text-muted">正在加载流程监控列表...</div> : <DataEmptyState title={activeGroup ? '当前分组还没有监控模板' : '暂无可展示模板'} action={canManage && activeGroup ? <Button size="sm" variant="secondary" onPress={() => setAddTemplateOpen(true)}>添加监控模板</Button> : null} />} scrollContainerClassName="data-table
-scroll" verticalAlign="middle" /></section>
{!loading ? <div className="pm-pagination-bar"><PagePagination page={listPage} pageSize={pageSize} total={filteredTemplates.length} onPageChange={setListPage} onPageSizeChange={(nextPageSize) => { if (PAGE_SIZE_OPTIONS.includes(nextPageSize)) setPageSize(nextPageSize); }} /></div> : null}
</div>
</section>
<FormModal isOpen={createGroupOpen} onOpenChange={setCreateGroupOpen} title="新建流程监控分组" footer={<><Button isDisabled={submitting} size="sm" variant="secondary" onPress={() => setCreateGroupOpen(false)}>取消</Button><Button isPending={submitting} size="sm" variant="primary" onPress={handleCreateGroup}>创建分组</Button></>}><div className="grid gap-1.5"><Label>分组名称</Label><Input fullWidth variant="secondary" value={createGroupTitle} onChange={(event) => setCreateGroupTitle(event.target.value)} placeholder="例如:投资业务流程" /></div></FormModal>
<FormModal isOpen={addTemplateOpen} onOpenChange={(open) => { setAddTemplateOpen(open); if (!open) { setSelectedTemplateIds([]); setTemplatePickerKeyword(''); } }} size="
4
xl" title="添加流程监控模板" footer={<><Button isDisabled={submitting} size="sm" variant="secondary" onPress={() => setAddTemplateOpen(false)}>取消</Button><Button isDisabled={!activeGroup} isPending={submitting} size="sm" variant="primary" onPress={handleAddTemplates}>确认添加</Button></>}>
<div className="grid gap-4"><SearchField fullWidth value={templatePickerKeyword} variant="secondary" onChange={setTemplatePickerKeyword}><SearchField.Group><SearchField.SearchIcon><Search size={16} /></SearchField.SearchIcon><SearchField.Input placeholder="搜索模板标题" /><SearchField.ClearButton aria-label="清空搜索"><Close size={14} /></SearchField.ClearButton></SearchField.Group></SearchField><Surface className="max-h-80 overflow-y-auto
p-3" variant="secondary
"><div className="grid gap-2">{pickerTemplates.map((template) => { const isDisabled = currentGroupExternalIds.has(template._id); const isSelected = selectedTemplateIds.includes(template._id); return <Checkbox key={template._id} isDisabled={isDisabled} isSelected={isSelected} onChange={(selected) => setSelectedTemplateIds((current) => selected ? [...current, template._id] : current.filter((id) => id !== template._id))}><Checkbox.Content><Checkbox.Control><Checkbox.Indicator><Check size={12} /></Checkbox.Indicator></Checkbox.Control><span className="min-w-0"><span className="block truncate text-sm">{template.title}</span><span className="block truncate text-xs text-muted">模板 ID:{template._id}{isDisabled ? ' · 当前分组已添加' : ''}</span></span></Checkbox.Content></Checkbox>; })}{!pickerTemplates.length ? <div className="py-5 text-center text-sm text-muted">没有找到匹配的模板</div> : null}</div></Surface></div>
<FormModal isOpen={addTemplateOpen} onOpenChange={(open) => { setAddTemplateOpen(open); if (!open) { setSelectedTemplateIds([]); setTemplatePickerKeyword(''); } }} size="
2
xl" title="添加流程监控模板" footer={<><Button isDisabled={submitting} size="sm" variant="secondary" onPress={() => setAddTemplateOpen(false)}>取消</Button><Button isDisabled={!activeGroup} isPending={submitting} size="sm" variant="primary" onPress={handleAddTemplates}>确认添加</Button></>}>
<div className="grid gap-4"><SearchField fullWidth value={templatePickerKeyword} variant="secondary" onChange={setTemplatePickerKeyword}><SearchField.Group><SearchField.SearchIcon><Search size={16} /></SearchField.SearchIcon><SearchField.Input placeholder="搜索模板标题" /><SearchField.ClearButton aria-label="清空搜索"><Close size={14} /></SearchField.ClearButton></SearchField.Group></SearchField><Surface className="max-h-80 overflow-y-auto
rounded-2xl p-3" variant="default
"><div className="grid gap-2">{pickerTemplates.map((template) => { const isDisabled = currentGroupExternalIds.has(template._id); const isSelected = selectedTemplateIds.includes(template._id); return <Checkbox key={template._id} isDisabled={isDisabled} isSelected={isSelected} onChange={(selected) => setSelectedTemplateIds((current) => selected ? [...current, template._id] : current.filter((id) => id !== template._id))}><Checkbox.Content><Checkbox.Control><Checkbox.Indicator><Check size={12} /></Checkbox.Indicator></Checkbox.Control><span className="min-w-0"><span className="block truncate text-sm">{template.title}</span><span className="block truncate text-xs text-muted">模板 ID:{template._id}{isDisabled ? ' · 当前分组已添加' : ''}</span></span></Checkbox.Content></Checkbox>; })}{!pickerTemplates.length ? <div className="py-5 text-center text-sm text-muted">没有找到匹配的模板</div> : null}</div></Surface></div>
</FormModal>
<FormModal isOpen={editTemplateOpen} onOpenChange={setEditTemplateOpen} size="2xl" title="编辑模板监控配置" footer={<><Button isDisabled={submitting} size="sm" variant="secondary" onPress={() => setEditTemplateOpen(false)}>取消</Button><Button isPending={submitting} size="sm" variant="primary" onPress={handleUpdateTemplate}>保存配置</Button></>}>
...
...
src/pages/process_monitor/ProcessTemplateList.jsx
View file @
70f36d82
...
...
@@ -23,8 +23,8 @@ import {
import
{
useEffect
,
useMemo
,
useState
}
from
'react'
;
import
{
useParams
,
useSearchParams
}
from
'umi'
;
const
PAGE_SIZE
=
1
0
;
const
PAGE_SIZE_OPTIONS
=
[
10
,
20
,
50
,
100
];
const
PAGE_SIZE
=
2
0
;
const
PAGE_SIZE_OPTIONS
=
[
20
,
50
,
100
];
const
FIELD_TYPE_OPTIONS
=
[
{
id
:
'text'
,
label
:
'文本'
},
{
id
:
'member'
,
label
:
'人员'
},
...
...
@@ -81,7 +81,7 @@ function PagePagination({ page, pageSize, total, onPageChange, onPageSizeChange
<
div
className=
"flex min-w-0 flex-wrap items-center justify-between gap-3"
>
<
div
className=
"flex min-w-0 shrink-0 items-center gap-3"
>
<
span
className=
"min-w-0 text-sm text-muted"
>
共
{
total
}
条,第
{
total
?
page
:
0
}
/
{
total
?
totalPages
:
0
}
页
</
span
>
<
XinyuanAutocomplete
aria
-
label=
"每页条数"
className=
"w-
24
shrink-0"
options=
{
PAGE_SIZE_OPTIONS
.
map
((
value
)
=>
({
id
:
String
(
value
),
label
:
`${value} 条/页`
}))
}
placeholder=
"每页条数"
selectedKey=
{
String
(
pageSize
)
}
showSearch=
{
false
}
valueText=
{
`${pageSize} 条/页`
}
variant=
"secondary"
onSelectionChange=
{
(
key
)
=>
onPageSizeChange
(
Number
(
key
))
}
/>
<
XinyuanAutocomplete
aria
-
label=
"每页条数"
className=
"w-
32
shrink-0"
options=
{
PAGE_SIZE_OPTIONS
.
map
((
value
)
=>
({
id
:
String
(
value
),
label
:
`${value} 条/页`
}))
}
placeholder=
"每页条数"
selectedKey=
{
String
(
pageSize
)
}
showSearch=
{
false
}
valueText=
{
`${pageSize} 条/页`
}
variant=
"secondary"
onSelectionChange=
{
(
key
)
=>
onPageSizeChange
(
Number
(
key
))
}
/>
</
div
>
<
Pagination
className=
"ml-auto w-auto shrink-0"
size=
"sm"
>
<
Pagination
.
Content
>
...
...
@@ -188,7 +188,7 @@ export default function ProcessTemplateListPage() {
<
div
className=
"rc-list-action-bar"
><
div
className=
"flex items-center gap-1.5"
><
h2
>
实例列表
</
h2
><
TitleInfo
label=
"实例列表"
content=
"按模板展示实际提交的流程实例,可通过操作列查看单条详情。"
/></
div
></
div
>
<
div
className=
"flex flex-wrap items-center justify-between gap-3"
><
SearchField
aria
-
label=
"搜索表单名称"
className=
"w-full sm:w-96"
value=
{
keyword
}
onChange=
{
(
value
)
=>
{
setPage
(
1
);
setKeyword
(
value
);
}
}
><
SearchField
.
Group
><
SearchField
.
SearchIcon
><
Search
size=
{
16
}
/></
SearchField
.
SearchIcon
><
SearchField
.
Input
placeholder=
"搜索表单名称"
/><
SearchField
.
ClearButton
aria
-
label=
"清空关键词"
><
Close
size=
{
14
}
/></
SearchField
.
ClearButton
></
SearchField
.
Group
></
SearchField
></
div
>
<
div
className=
"rc-list-data-stack"
>
<
section
className=
"rc-list-data-grid
"
><
DataGrid
allowsColumnResize
aria
-
label=
"流程实例列表"
className=
"pm-data-grid"
columns=
{
instanceColumns
}
contentClassName=
"min-w-[760px]"
data=
{
loading
?
[]
:
instances
}
getRowId=
{
(
record
)
=>
record
.
_id
||
record
.
name
}
renderEmptyState=
{
()
=>
loading
?
<
div
className=
"py-8 text-sm text-muted"
>
正在加载模板实例...
</
div
>
:
<
DataEmptyState
/>
}
scrollContainerClassName=
"pm-data-grid
-scroll"
verticalAlign=
"middle"
/></
section
>
<
section
className=
"rc-list-data-grid
rc-data-table-sticky"
><
DataGrid
allowsColumnResize
aria
-
label=
"流程实例列表"
className=
"pm-data-grid"
columns=
{
instanceColumns
}
contentClassName=
"min-w-[760px]"
data=
{
loading
?
[]
:
instances
}
getRowId=
{
(
record
)
=>
record
.
_id
||
record
.
name
}
renderEmptyState=
{
()
=>
loading
?
<
div
className=
"py-8 text-sm text-muted"
>
正在加载模板实例...
</
div
>
:
<
DataEmptyState
/>
}
scrollContainerClassName=
"data-table
-scroll"
verticalAlign=
"middle"
/></
section
>
{
!
loading
?
<
div
className=
"pm-pagination-bar"
><
PagePagination
page=
{
page
}
pageSize=
{
pageSize
}
total=
{
total
}
onPageChange=
{
setPage
}
onPageSizeChange=
{
(
nextPageSize
)
=>
{
if
(
PAGE_SIZE_OPTIONS
.
includes
(
nextPageSize
))
{
setPageSize
(
nextPageSize
);
setPage
(
1
);
}
}
}
/></
div
>
:
null
}
</
div
>
</
section
>
...
...
src/pages/process_monitor/process-monitor.business-flow.md
View file @
70f36d82
...
...
@@ -118,7 +118,7 @@ Shell 中的应用切换入口继续读取当前登录用户可访问应用,
-
读取当前监控模板记录
`audit_related_progress`
-
根据模板的
`metadata.fields_definition`
动态生成列表列
-
查询
`audit_progress_info`
并按
`metadata.related_progress`
过滤
-
支持关键字搜索和每页
10/20/50/100 条的分页切换,默认每页 1
0 条
-
支持关键字搜索和每页
20/50/100 条的分页切换,默认每页 2
0 条
-
支持批量触发附件下载
-
支持维护实例列表的显示字段定义
-
打开“定义显示字段”时,已有字段按配置回显;无字段配置时默认展示一行空字段,字段名和字段类型分别使用“请输入字段名”“请选择”提示,不额外展示重复的字段表头
...
...
@@ -134,7 +134,7 @@ Shell 中的应用切换入口继续读取当前登录用户可访问应用,
-
使用 HeroUI Pro DataGrid 生成动态列并承载选择状态
-
表单名称列仅展示文本,通过操作列的“查看”图标在当前列表页打开单条流程实例详情 Modal;详情路由仍保留用于直接访问和兼容既有链接
-
Pagination 保留原有页码语义和
`page`
/
`page_size`
请求参数,条数选择器支持
10/20/50/100 条
-
Pagination 保留原有页码语义和
`page`
/
`page_size`
请求参数,条数选择器支持
20/50/100 条,宽度为 128px
-
有选中记录时由 HeroUI Pro ActionBar 承载批量附件下载;空数据使用 HeroUI Pro EmptyState
### 5.3 流程实例详情页
...
...
@@ -172,7 +172,7 @@ Shell 中的应用切换入口继续读取当前登录用户可访问应用,
-
旧版实例列表批量下载会打包 zip;当前迁移版使用逐个触发浏览器下载,保持“批量下载附件”能力但不强依赖额外前端压缩库
-
旧版详情页曾预留字段类型即时修改能力,但实际入口已注释;当前迁移版不开放详情页内字段类型编辑,统一回到模板实例列表页的“定义显示字段”
-
列表按统一设计合同默认每页
10 条,并通过 HeroUI 条数选择器支持 10/
20/50/100 条;后端分页协议没有变化
-
列表按统一设计合同默认每页
20 条,并通过 HeroUI 条数选择器支持
20/50/100 条;后端分页协议没有变化
-
401 响应仍在原时机清理登录态,只将登录跳转修正为包含
`/oa_process_monitor_new/`
base 的应用内地址
---
...
...
src/tailwind.css
View file @
70f36d82
...
...
@@ -82,8 +82,8 @@ body .login-page {
--rc-login-field-filled-background
:
#fbf1f1
;
--rc-login-field-filled-background-hover
:
#faeaea
;
--rc-login-field-autofill-background
:
#fbf1f1
;
--rc-login-field-border-hover
:
rgb
(
158
27
27
/
24%
);
--rc-login-field-focus-ring
:
rgb
(
158
27
27
/
16%
);
--rc-login-field-border-hover
:
color-mix
(
in
srgb
,
var
(
--rc-brand-primary
)
24%
,
transparent
);
--rc-login-field-focus-ring
:
color-mix
(
in
srgb
,
var
(
--rc-brand-primary
)
16%
,
transparent
);
}
body
.login-brand
img
{
...
...
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