Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
R
risk_case_library
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
risk_case_library
Commits
4abbdebf
Commit
4abbdebf
authored
Aug 26, 2026
by
Andy-bubu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: align application switcher with Xinyuan standard
parent
1596daf0
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
149 additions
and
33 deletions
+149
-33
ui-architecture.md
docs/ui-architecture.md
+1
-0
ui-migration-checklist.md
docs/ui-migration-checklist.md
+4
-2
xinyuan-design-system.md
docs/xinyuan-design-system.md
+1
-1
xinyuan-ui-audit.md
docs/xinyuan-ui-audit.md
+6
-6
shell.css
src/design-system/shell.css
+15
-0
ApplicationSwitcherDialog.jsx
src/pages/project_manager_xy/ApplicationSwitcherDialog.jsx
+115
-24
audit-material-center.business-flow.md
...project_manager_xy/audit-material-center.business-flow.md
+1
-0
index.jsx
src/pages/project_manager_xy/resource-booking/index.jsx
+6
-0
No files found.
docs/ui-architecture.md
View file @
4abbdebf
...
@@ -10,6 +10,7 @@
...
@@ -10,6 +10,7 @@
-
共享组合只可封装重复布局、可访问性与当前 HeroUI value/selection/event 模型,不得复刻 Catalyst props、DOM event 或旧 CSS hook。
-
共享组合只可封装重复布局、可访问性与当前 HeroUI value/selection/event 模型,不得复刻 Catalyst props、DOM event 或旧 CSS hook。
-
DataGrid 组合映射列定义并转发原生 selection/fixed-column/ActionBar/Pagination;分页容量继续保持 20/50/100,并使用 HeroUI Autocomplete compound API。
-
DataGrid 组合映射列定义并转发原生 selection/fixed-column/ActionBar/Pagination;分页容量继续保持 20/50/100,并使用 HeroUI Autocomplete compound API。
-
文件上传采用 HeroUI Pro DropZone 的
`File[]`
协议;页面边界继续只取既有单文件值。
-
文件上传采用 HeroUI Pro DropZone 的
`File[]`
协议;页面边界继续只取既有单文件值。
-
应用切换直接组合 HeroUI Modal/Card/Surface/Avatar 与 HeroUI Pro EmptyState;分组只读取现有
`SiteContext`
的
`/info -> site.group`
,应用仍合并
`/application/info`
与当前用户权限数据,不引入硬编码分组或应用。
## 依赖来源
## 依赖来源
...
...
docs/ui-migration-checklist.md
View file @
4abbdebf
...
@@ -12,6 +12,7 @@
...
@@ -12,6 +12,7 @@
-
[
x
]
Login:问题整改几何、字段节奏、验证码、filled/autofill、浅/深色
-
[
x
]
Login:问题整改几何、字段节奏、验证码、filled/autofill、浅/深色
-
[
x
]
Shell:Sidebar/Navbar/退出/应用切换/主题/offcanvas(代码结构)
-
[
x
]
Shell:Sidebar/Navbar/退出/应用切换/主题/offcanvas(代码结构)
-
[
x
]
应用切换:同步
`model_analysis`
Modal 几何、动态分组/计数、其他/全部回退、两列 Card 与 identity well(代码结构)
-
[
x
]
驾驶舱:Pro KPI、PieChart、BarChart、ComposedChart、ChartTooltip(代码结构)
-
[
x
]
驾驶舱:Pro KPI、PieChart、BarChart、ComposedChart、ChartTooltip(代码结构)
-
[
x
]
案例管理:Tabs、筛选工具栏、DataGrid、Pagination、ActionBar、EmptyState(代码结构)
-
[
x
]
案例管理:Tabs、筛选工具栏、DataGrid、Pagination、ActionBar、EmptyState(代码结构)
-
[
x
]
弹窗:新建、查看/编辑、批量修改、导入、删除确认(代码结构)
-
[
x
]
弹窗:新建、查看/编辑、批量修改、导入、删除确认(代码结构)
...
@@ -23,7 +24,8 @@
...
@@ -23,7 +24,8 @@
-
[
x
]
Login 1280x720 light/dark
-
[
x
]
Login 1280x720 light/dark
-
[
x
]
Login 768x1024 light/dark
-
[
x
]
Login 768x1024 light/dark
-
[
x
]
Login 390x844 light/dark
-
[
x
]
Login 390x844 light/dark
-
[
]
打开 Sidebar、用户退出菜单、应用切换、Dropdown/ListBox/DatePicker
-
[
x
]
应用切换 1440x900、1280x720、768x1024、390x844 light/dark:尺寸、两列/单列、动态分组、全部应用回退、唯一当前态、Body 滚动、Escape 与焦点回归
-
[
]
打开 Sidebar、用户退出菜单、应用切换真实动态分组、Dropdown/ListBox/DatePicker
-
[
]
验证 Tabs、筛选、Checkbox、DataGrid、Pagination、ActionBar、Modal、KPI、图表 Tooltip
-
[
]
验证 Tabs、筛选、Checkbox、DataGrid、Pagination、ActionBar、Modal、KPI、图表 Tooltip
-
[
x
]
Login 控制台 0 runtime/slot/provider/accessibility 错误或警告
-
[
x
]
Login 控制台 0 runtime/slot/provider/accessibility 错误或警告
...
@@ -38,4 +40,4 @@
...
@@ -38,4 +40,4 @@
-
[
x
]
HeroUI/React Aria 依赖树唯一
-
[
x
]
HeroUI/React Aria 依赖树唯一
-
[
x
]
HeroUI Pro 必需子路径通过 ESM 实际导入
-
[
x
]
HeroUI Pro 必需子路径通过 ESM 实际导入
未完成项只剩登录后真实浏览器状态。不得使用伪造 token、网络数据或测试数字替代真实验收
。
应用切换目标页打开态已验收;
`model_analysis`
隔离会话未登录,无法对其打开态做同屏像素测量。其余未勾选项仍需使用真实业务状态验收,不得使用伪造 token、网络数据或测试数字替代
。
docs/xinyuan-design-system.md
View file @
4abbdebf
...
@@ -13,7 +13,7 @@
...
@@ -13,7 +13,7 @@
## 页面规则
## 页面规则
-
Shell 使用 HeroUI Pro offcanvas Sidebar 与 Navbar;页面和 Navbar 使用 48/32/16px 对称 gutter。
-
Shell 使用 HeroUI Pro offcanvas Sidebar 与 Navbar;页面和 Navbar 使用 48/32/16px 对称 gutter。
-
应用切换
使用 HeroUI Modal,应用卡片在小屏单列、
`sm`
及以上固定两列,与“问题整改”保持一致
。
-
应用切换
严格使用
`model_analysis`
的 HeroUI Modal 基准:46rem 宽、42rem 最大高度、28px inset、Body 内滚动,小屏单列且
`sm`
及以上固定两列;分组读取
`/info -> site.group`
,按真实配置顺序展示分组与数量,未分组应用进入“其他应用”,无分组配置时使用“全部应用”
。
-
结构化筛选使用 HeroUI Surface,内部控件使用
`secondary`
;关键词搜索位于列表工具栏左侧。
-
结构化筛选使用 HeroUI Surface,内部控件使用
`secondary`
;关键词搜索位于列表工具栏左侧。
-
列表使用 HeroUI Pro DataGrid 原生选择、排序、固定列、ActionBar、EmptyState 与 compound Pagination。
-
列表使用 HeroUI Pro DataGrid 原生选择、排序、固定列、ActionBar、EmptyState 与 compound Pagination。
-
详情和内容型表单使用鑫元 4xl(1088px)Modal:HeroUI
`Modal.Container size="lg"`
保留官方交互与响应式结构,
`Modal.Dialog`
通过共享布局类限制为
`sm:max-w-[68rem]`
;不得把 HeroUI 不支持的
`4xl`
直接传给 Container。查看态只有一个
`Surface secondary`
字段组,编辑态直接放置
`secondary`
控件。
-
详情和内容型表单使用鑫元 4xl(1088px)Modal:HeroUI
`Modal.Container size="lg"`
保留官方交互与响应式结构,
`Modal.Dialog`
通过共享布局类限制为
`sm:max-w-[68rem]`
;不得把 HeroUI 不支持的
`4xl`
直接传给 Container。查看态只有一个
`Surface secondary`
字段组,编辑态直接放置
`secondary`
控件。
...
...
docs/xinyuan-ui-audit.md
View file @
4abbdebf
# 鑫元 UI 审计
# 鑫元 UI 审计
审计日期:2026-08-
19。目标仓库为 Umi 4 / React 19,部署基路径为
`/risk_case_library/`
。唯一实现基准为本机已确认的“问题整改”应用
`/Users/liuchenlong/Desktop/job/problem_rectification`
。
审计日期:2026-08-
26。目标仓库为 Umi 4 / React 19,部署基路径为
`/risk_case_library/`
。整体实现基准为“问题整改”,应用切换专项基准为
`model_analysis`
当前 HeroUI 实现
。
## 安装与运行基线
## 安装与运行基线
-
官方安装命令已在项目根目录执行成功,
`@heroui-pro/react`
解析为本项目
`node_modules`
内的
`1.0.0-beta.8`
,不是符号链接或跨项目
`file:`
依赖。
-
官方安装命令已在项目根目录执行成功,
`@heroui-pro/react`
解析为本项目
`node_modules`
内的
`1.0.0-beta.8`
,不是符号链接或跨项目
`file:`
依赖。
-
项目使用 npm,保留
`package-lock.json`
;旧
`pnpm-lock.yaml`
已删除。
-
项目使用 npm,保留
`package-lock.json`
;旧
`pnpm-lock.yaml`
已删除。
-
当前迁移实例运行于
`http://localhost:800
1
/risk_case_library/`
。
-
当前迁移实例运行于
`http://localhost:800
0
/risk_case_library/`
。
-
“问题整改”基准运行于
`http://localhost:800
0
/problem_rectification_new/`
。
-
“问题整改”基准运行于
`http://localhost:800
1
/problem_rectification_new/`
。
-
`HEAD`
原始业务基线通过独立临时工作树运行于
`http://localhost:8004/risk_case_library/`
。原始路由、鉴权、验证码、查询、保存、导入导出和分页协议以该实例及
`git show HEAD`
为准
。
-
应用切换专项基准
`model_analysis`
运行于
`http://localhost:8002/model_analysis/`
;该隔离浏览器会话停留在登录页,因此没有把未登录状态冒充为打开态对照
。
## 业务契约
## 业务契约
...
@@ -24,7 +24,7 @@
...
@@ -24,7 +24,7 @@
| --- | --- | --- |
| --- | --- | --- |
| Login | HeroUI;结构、尺寸、字段节奏与问题整改一致;可访问性告警已消除 | 四视口浅/深色对照通过 |
| Login | HeroUI;结构、尺寸、字段节奏与问题整改一致;可访问性告警已消除 | 四视口浅/深色对照通过 |
| Shell | HeroUI Pro Sidebar/Navbar,offcanvas、主题、用户退出与应用切换保留既有业务回调 | 代码与共享基准一致;登录后浏览器状态待真实凭证 |
| Shell | HeroUI Pro Sidebar/Navbar,offcanvas、主题、用户退出与应用切换保留既有业务回调 | 代码与共享基准一致;登录后浏览器状态待真实凭证 |
| 应用切换 | HeroUI Modal compound API
,桌面两列应用卡、Surface + Avatar identity well、当前态 | 登录后打开态待真实凭证
|
| 应用切换 | HeroUI Modal compound API
;46rem/42rem/28px 几何;读取
`/info -> site.group`
动态分组、真实计数与未分组回退;两列 Card、Surface + Avatar identity、唯一当前态 | 目标应用已在四视口浅/深色真实打开验收;动态分组和无配置回退均由真实会话覆盖,专项基准打开态因未登录仍不可复测
|
| 驾驶舱 | HeroUI Pro KPI、PieChart、BarChart、ComposedChart、ChartTooltipContent | 构建通过;真实图表 Tooltip 待登录验收 |
| 驾驶舱 | HeroUI Pro KPI、PieChart、BarChart、ComposedChart、ChartTooltipContent | 构建通过;真实图表 Tooltip 待登录验收 |
| 案例管理 | HeroUI Surface/Tabs/TextField/Autocomplete、Pro DataGrid/ActionBar/EmptyState | 默认 20、20/50/100 分页口径已保护;交互待登录验收 |
| 案例管理 | HeroUI Surface/Tabs/TextField/Autocomplete、Pro DataGrid/ActionBar/EmptyState | 默认 20、20/50/100 分页口径已保护;交互待登录验收 |
| 弹窗 | HeroUI Modal/Alert/DropZone,Container 使用官方
`lg`
、Dialog 映射鑫元 4xl/1088px,查看态使用单一 secondary Surface | 新建弹窗宽度已按问题整改基准修正;其他打开态待登录验收 |
| 弹窗 | HeroUI Modal/Alert/DropZone,Container 使用官方
`lg`
、Dialog 映射鑫元 4xl/1088px,查看态使用单一 secondary Surface | 新建弹窗宽度已按问题整改基准修正;其他打开态待登录验收 |
...
@@ -35,4 +35,4 @@
...
@@ -35,4 +35,4 @@
-
不改变 API URL、请求参数、响应映射、路由、权限、校验、请求时机、保存回调、登录退出或业务状态流。
-
不改变 API URL、请求参数、响应映射、路由、权限、校验、请求时机、保存回调、登录退出或业务状态流。
-
不在源码或浏览器中加入测试记录、伪造 token 或统计数字。
-
不在源码或浏览器中加入测试记录、伪造 token 或统计数字。
-
静态、构建与登录页浏览器门槛已完成;缺少真实登录凭证,因此 Sidebar、退出菜单、应用切换、业务列表、弹窗、KPI 和图表的登录后验收仍处于阻塞状态,不能标记全量
迁移完成。
-
应用切换已使用现有真实登录会话完成浅/深色四视口验收;未注入 token、应用、分组或业务数据。其他模块的既有未验收项仍按迁移清单保留,不能据此标记全量应用
迁移完成。
src/design-system/shell.css
View file @
4abbdebf
...
@@ -381,6 +381,21 @@
...
@@ -381,6 +381,21 @@
gap
:
var
(
--rc-space-2
);
gap
:
var
(
--rc-space-2
);
}
}
.xy-app-switcher-dialog
{
width
:
min
(
46rem
,
calc
(
100vw
-
2rem
));
max-width
:
min
(
46rem
,
calc
(
100vw
-
2rem
));
max-height
:
min
(
42rem
,
calc
(
100
dvh
-
2rem
));
}
.xy-app-identity-well
,
.xy-app-identity-avatar
{
border-radius
:
var
(
--rc-radius-control
);
}
.xy-app-identity-avatar
{
background
:
transparent
;
}
.rc-navbar-title
{
.rc-navbar-title
{
min-width
:
0
;
min-width
:
0
;
margin
:
0
;
margin
:
0
;
...
...
src/pages/project_manager_xy/ApplicationSwitcherDialog.jsx
View file @
4abbdebf
import
{
getApplications
}
from
'@/services/DataService'
;
import
{
getApplications
}
from
'@/services/DataService'
;
import
xinyuanLogo
from
'@/assets/identity/xy-logo-red.png'
;
import
{
import
{
APP_DISPLAY_NAME
,
APP_DISPLAY_NAME
,
APP_LOGIN_SUBTITLE
,
APP_LOGIN_SUBTITLE
,
APP_ROUTE_NAME
,
APP_ROUTE_NAME
,
}
from
'@/constants/app'
;
}
from
'@/constants/app'
;
import
WarningOutlined
from
'@ant-design/icons/WarningOutlined'
;
import
{
EmptyState
}
from
'@heroui-pro/react/empty-state'
;
import
{
EmptyState
}
from
'@heroui-pro/react/empty-state'
;
import
{
Alert
,
Avatar
,
Card
,
Chip
,
Description
,
Modal
,
Skeleton
,
Surface
}
from
'@heroui/react'
;
import
{
Alert
,
Avatar
,
Card
,
Chip
,
Description
,
Modal
,
Skeleton
,
Surface
}
from
'@heroui/react'
;
import
{
useEffect
,
useMemo
,
useState
}
from
'react'
;
import
{
useEffect
,
useMemo
,
useState
}
from
'react'
;
...
@@ -95,6 +97,18 @@ function mergeApplications(fetchedApplications, fallbackApplications) {
...
@@ -95,6 +97,18 @@ function mergeApplications(fetchedApplications, fallbackApplications) {
);
);
});
});
if
(
!
mergedMap
.
has
(
APP_ROUTE_NAME
))
{
mergedMap
.
set
(
APP_ROUTE_NAME
,
normalizeApplication
({
name
:
APP_ROUTE_NAME
,
title
:
APP_DISPLAY_NAME
,
description
:
APP_LOGIN_SUBTITLE
,
logo
:
xinyuanLogo
,
}),
);
}
return
Array
.
from
(
mergedMap
.
values
()).
sort
((
left
,
right
)
=>
{
return
Array
.
from
(
mergedMap
.
values
()).
sort
((
left
,
right
)
=>
{
const
orderDifference
=
Number
(
left
.
order
||
0
)
-
Number
(
right
.
order
||
0
);
const
orderDifference
=
Number
(
left
.
order
||
0
)
-
Number
(
right
.
order
||
0
);
if
(
orderDifference
!==
0
)
{
if
(
orderDifference
!==
0
)
{
...
@@ -125,6 +139,57 @@ function unwrapApplications(response) {
...
@@ -125,6 +139,57 @@ function unwrapApplications(response) {
return
[];
return
[];
}
}
function
buildApplicationSections
(
applications
,
applicationGroups
)
{
if
(
!
Array
.
isArray
(
applicationGroups
)
||
applicationGroups
.
length
===
0
)
{
return
[{
key
:
'all'
,
label
:
'全部应用'
,
applications
}];
}
const
applicationMap
=
new
Map
(
applications
.
map
((
application
)
=>
[
application
.
name
,
application
]),
);
const
groupedApplicationNames
=
new
Set
();
const
sections
=
applicationGroups
.
map
((
group
,
index
)
=>
{
const
groupApplications
=
Array
.
isArray
(
group
?.
applications
)
?
group
.
applications
.
map
((
name
)
=>
{
if
(
groupedApplicationNames
.
has
(
name
))
{
return
null
;
}
const
application
=
applicationMap
.
get
(
name
);
if
(
application
)
{
groupedApplicationNames
.
add
(
name
);
}
return
application
;
})
.
filter
(
Boolean
)
:
[];
return
{
key
:
group
?.
label
||
`group-
${
index
}
`
,
label
:
group
?.
label
||
'应用分组'
,
applications
:
groupApplications
,
};
})
.
filter
((
section
)
=>
section
.
applications
.
length
>
0
);
const
ungroupedApplications
=
applications
.
filter
(
(
application
)
=>
!
groupedApplicationNames
.
has
(
application
.
name
),
);
if
(
ungroupedApplications
.
length
>
0
)
{
sections
.
push
({
key
:
'ungrouped'
,
label
:
'其他应用'
,
applications
:
ungroupedApplications
,
});
}
return
sections
;
}
function
isCurrentApplication
(
application
)
{
function
isCurrentApplication
(
application
)
{
if
(
typeof
window
===
'undefined'
)
{
if
(
typeof
window
===
'undefined'
)
{
return
false
;
return
false
;
...
@@ -179,11 +244,11 @@ function ApplicationCard({ application }) {
...
@@ -179,11 +244,11 @@ function ApplicationCard({ application }) {
>
>
<
Surface
<
Surface
aria
-
hidden=
"true"
aria
-
hidden=
"true"
className=
"
grid size-9 shrink-0 place-items-center overflow-hidden rounded-[var(--rc-radius-control)]
"
className=
"
xy-app-identity-well grid size-9 shrink-0 place-items-center overflow-hidden
"
variant=
"tertiary"
variant=
"tertiary"
>
>
<
Avatar
<
Avatar
className=
"
size-full rounded-[var(--rc-radius-control)] bg-transparent
"
className=
"
xy-app-identity-avatar size-full
"
color=
"accent"
color=
"accent"
variant=
"soft"
variant=
"soft"
>
>
...
@@ -194,12 +259,15 @@ function ApplicationCard({ application }) {
...
@@ -194,12 +259,15 @@ function ApplicationCard({ application }) {
</
Avatar
>
</
Avatar
>
</
Surface
>
</
Surface
>
<
span
className=
"min-w-0 flex-1"
>
<
span
className=
"min-w-0 flex-1"
>
<
span
className=
"block
break-words
font-medium leading-5"
title=
{
application
.
title
}
>
<
span
className=
"block
truncate text-sm
font-medium leading-5"
title=
{
application
.
title
}
>
{
application
.
title
}
{
application
.
title
}
</
span
>
</
span
>
<
span
className=
"block truncate"
title=
{
application
.
description
}
>
<
Description
className=
"mt-0.5 block truncate leading-4"
title=
{
application
.
description
}
>
{
application
.
description
||
application
.
name
||
'应用'
}
{
application
.
description
||
application
.
name
||
'应用'
}
</
spa
n
>
</
Descriptio
n
>
</
span
>
</
span
>
{
current
?
<
Chip
color=
"accent"
size=
"sm"
>
当前
</
Chip
>
:
null
}
{
current
?
<
Chip
color=
"accent"
size=
"sm"
>
当前
</
Chip
>
:
null
}
</
a
>
</
a
>
...
@@ -214,10 +282,10 @@ function LoadingSkeleton() {
...
@@ -214,10 +282,10 @@ function LoadingSkeleton() {
{
Array
.
from
({
length
:
6
}).
map
((
_
,
index
)
=>
(
{
Array
.
from
({
length
:
6
}).
map
((
_
,
index
)
=>
(
<
Card
key=
{
index
}
variant=
"secondary"
>
<
Card
key=
{
index
}
variant=
"secondary"
>
<
Card
.
Content
className=
"flex items-center gap-3"
>
<
Card
.
Content
className=
"flex items-center gap-3"
>
<
Skeleton
className=
"size-9 shrink-0
rounded-[var(--rc-radius-control)]
"
/>
<
Skeleton
className=
"size-9 shrink-0"
/>
<
div
className=
"min-w-0 flex-1 space-y-2"
>
<
div
className=
"min-w-0 flex-1 space-y-2"
>
<
Skeleton
className=
"h-4 w-2/
5 rounded-full
"
/>
<
Skeleton
className=
"h-4 w-2/
3
"
/>
<
Skeleton
className=
"h-3 w-full
rounded-full
"
/>
<
Skeleton
className=
"h-3 w-full"
/>
</
div
>
</
div
>
</
Card
.
Content
>
</
Card
.
Content
>
</
Card
>
</
Card
>
...
@@ -229,6 +297,7 @@ function LoadingSkeleton() {
...
@@ -229,6 +297,7 @@ function LoadingSkeleton() {
export
default
function
ApplicationSwitcherDialog
({
export
default
function
ApplicationSwitcherDialog
({
open
,
open
,
onClose
,
onClose
,
siteInfo
,
userInfo
,
userInfo
,
})
{
})
{
const
fallbackApplications
=
useMemo
(()
=>
{
const
fallbackApplications
=
useMemo
(()
=>
{
...
@@ -253,6 +322,10 @@ export default function ApplicationSwitcherDialog({
...
@@ -253,6 +322,10 @@ export default function ApplicationSwitcherDialog({
fallbackApplications
.
length
>
0
?
'success'
:
'idle'
,
fallbackApplications
.
length
>
0
?
'success'
:
'idle'
,
);
);
const
[
errorMessage
,
setErrorMessage
]
=
useState
(
''
);
const
[
errorMessage
,
setErrorMessage
]
=
useState
(
''
);
const
applicationSections
=
useMemo
(
()
=>
buildApplicationSections
(
applications
,
siteInfo
?.
group
),
[
applications
,
siteInfo
?.
group
],
);
useEffect
(()
=>
{
useEffect
(()
=>
{
if
(
fallbackApplications
.
length
===
0
)
{
if
(
fallbackApplications
.
length
===
0
)
{
...
@@ -323,26 +396,30 @@ export default function ApplicationSwitcherDialog({
...
@@ -323,26 +396,30 @@ export default function ApplicationSwitcherDialog({
}
}
}
}
>
>
<
Modal
.
Container
<
Modal
.
Container
className=
"w-full
sm:w-full
"
className=
"w-full
p-4 sm:w-full sm:p-4
"
placement=
"center"
placement=
"center"
scroll=
"inside"
scroll=
"inside"
size=
"lg"
size=
"lg"
>
>
<
Modal
.
Dialog
<
Modal
.
Dialog
className=
"max-h-[min(42rem,calc(100dvh-2rem))]
"
aria
-
label=
"应用切换
"
style=
{
{
maxWidth
:
'min(46rem, calc(100vw - 2rem))'
}
}
className=
"xy-app-switcher-dialog p-7"
>
>
<
Modal
.
CloseTrigger
aria
-
label=
"关闭应用切换"
/>
<
Modal
.
CloseTrigger
aria
-
label=
"关闭应用切换"
style=
{
{
insetInlineEnd
:
'1.75rem'
,
top
:
'1.75rem'
}
}
/>
<
Modal
.
Header
>
<
Modal
.
Header
>
<
div
className=
"min-w-0"
>
<
Modal
.
Heading
>
应用切换
</
Modal
.
Heading
>
<
Modal
.
Heading
>
应用切换
</
Modal
.
Heading
>
<
Description
>
选择你可访问的应用
</
Description
>
<
Description
>
选择你可访问的应用
</
Description
>
</
div
>
</
Modal
.
Header
>
</
Modal
.
Header
>
<
Modal
.
Body
>
<
Modal
.
Body
style=
{
{
marginTop
:
'0.75rem'
}
}
>
{
status
===
'error'
&&
errorMessage
?
(
{
status
===
'error'
&&
errorMessage
?
(
<
Alert
className=
"mb-4"
status=
"warning"
>
<
Alert
status=
"warning"
>
<
Alert
.
Indicator
>
<
WarningOutlined
className=
"size-5"
/>
</
Alert
.
Indicator
>
<
Alert
.
Content
>
<
Alert
.
Content
>
<
Alert
.
Description
>
{
errorMessage
}
</
Alert
.
Description
>
<
Alert
.
Description
>
{
errorMessage
}
</
Alert
.
Description
>
</
Alert
.
Content
>
</
Alert
.
Content
>
...
@@ -352,12 +429,26 @@ export default function ApplicationSwitcherDialog({
...
@@ -352,12 +429,26 @@ export default function ApplicationSwitcherDialog({
{
status
===
'loading'
&&
applications
.
length
===
0
?
(
{
status
===
'loading'
&&
applications
.
length
===
0
?
(
<
LoadingSkeleton
/>
<
LoadingSkeleton
/>
)
:
applications
.
length
>
0
?
(
)
:
applications
.
length
>
0
?
(
<
div
className=
"grid gap-3 sm:grid-cols-2"
>
<
div
className=
"space-y-6"
>
{
applications
.
map
((
application
)
=>
(
{
applicationSections
.
map
((
section
)
=>
(
<
ApplicationCard
<
section
key=
{
section
.
key
}
>
key=
{
application
.
name
}
<
div
className=
"mb-3 flex items-center justify-between gap-3"
>
application=
{
application
}
<
h3
className=
"text-sm font-medium leading-5"
>
/>
{
section
.
label
}
</
h3
>
<
Description
>
{
section
.
applications
.
length
}
个应用
</
Description
>
</
div
>
<
div
className=
"grid gap-3 sm:grid-cols-2"
>
{
section
.
applications
.
map
((
application
)
=>
(
<
ApplicationCard
key=
{
application
.
name
}
application=
{
application
}
/>
))
}
</
div
>
</
section
>
))
}
))
}
</
div
>
</
div
>
)
:
(
)
:
(
...
...
src/pages/project_manager_xy/audit-material-center.business-flow.md
View file @
4abbdebf
...
@@ -32,6 +32,7 @@
...
@@ -32,6 +32,7 @@
-
桌面端侧栏展开时显示在应用标题右侧;侧栏收起后整体 offcanvas,不保留图标轨或应用入口
-
桌面端侧栏展开时显示在应用标题右侧;侧栏收起后整体 offcanvas,不保留图标轨或应用入口
-
移动端显示在顶部菜单栏右侧
-
移动端显示在顶部菜单栏右侧
-
点击后打开应用切换弹框,优先调用
`/application/info`
读取当前账号可见应用
-
点击后打开应用切换弹框,优先调用
`/application/info`
读取当前账号可见应用
-
按
`/info -> site.group`
的后台配置顺序展示非空应用分组和真实数量;未被配置引用的可访问应用归入“其他应用”,未配置分组时展示“全部应用”
-
应用列表加载失败时,回退展示当前登录用户信息中的
`applications`
-
应用列表加载失败时,回退展示当前登录用户信息中的
`applications`
-
点击应用卡片后跳转到对应应用根路径
-
点击应用卡片后跳转到对应应用根路径
-
`驾驶舱`
-
`驾驶舱`
...
...
src/pages/project_manager_xy/resource-booking/index.jsx
View file @
4abbdebf
...
@@ -1337,6 +1337,7 @@ export default function ResourceBookingPage() {
...
@@ -1337,6 +1337,7 @@ export default function ResourceBookingPage() {
)}
)}
<Modal.Root isOpen={isCreateOpen} onOpenChange={setIsCreateOpen}>
<Modal.Root isOpen={isCreateOpen} onOpenChange={setIsCreateOpen}>
<Modal.Trigger aria-hidden="true" className="sr-only" tabIndex={-1} />
<Modal.Backdrop>
<Modal.Backdrop>
<Modal.Container placement="center" scroll="inside" size="lg">
<Modal.Container placement="center" scroll="inside" size="lg">
<Modal.Dialog className={XINYUAN_4XL_DIALOG_CLASS}>
<Modal.Dialog className={XINYUAN_4XL_DIALOG_CLASS}>
...
@@ -1546,6 +1547,7 @@ export default function ResourceBookingPage() {
...
@@ -1546,6 +1547,7 @@ export default function ResourceBookingPage() {
</Modal.Root>
</Modal.Root>
<Modal.Root isOpen={isDetailOpen} onOpenChange={handleDetailOpenChange}>
<Modal.Root isOpen={isDetailOpen} onOpenChange={handleDetailOpenChange}>
<Modal.Trigger aria-hidden="true" className="sr-only" tabIndex={-1} />
<Modal.Backdrop>
<Modal.Backdrop>
<Modal.Container placement="center" scroll="inside" size="lg">
<Modal.Container placement="center" scroll="inside" size="lg">
<Modal.Dialog className={XINYUAN_4XL_DIALOG_CLASS}>
<Modal.Dialog className={XINYUAN_4XL_DIALOG_CLASS}>
...
@@ -1821,6 +1823,7 @@ export default function ResourceBookingPage() {
...
@@ -1821,6 +1823,7 @@ export default function ResourceBookingPage() {
</Modal.Root>
</Modal.Root>
<Modal.Root isOpen={isBatchEditOpen} onOpenChange={setIsBatchEditOpen}>
<Modal.Root isOpen={isBatchEditOpen} onOpenChange={setIsBatchEditOpen}>
<Modal.Trigger aria-hidden="true" className="sr-only" tabIndex={-1} />
<Modal.Backdrop>
<Modal.Backdrop>
<Modal.Container placement="center" scroll="inside" size="lg">
<Modal.Container placement="center" scroll="inside" size="lg">
<Modal.Dialog className={XINYUAN_4XL_DIALOG_CLASS}>
<Modal.Dialog className={XINYUAN_4XL_DIALOG_CLASS}>
...
@@ -2005,6 +2008,7 @@ export default function ResourceBookingPage() {
...
@@ -2005,6 +2008,7 @@ export default function ResourceBookingPage() {
</Modal.Root>
</Modal.Root>
<Modal.Root isOpen={isBatchDeleteOpen} onOpenChange={setIsBatchDeleteOpen}>
<Modal.Root isOpen={isBatchDeleteOpen} onOpenChange={setIsBatchDeleteOpen}>
<Modal.Trigger aria-hidden="true" className="sr-only" tabIndex={-1} />
<Modal.Backdrop>
<Modal.Backdrop>
<Modal.Container placement="center" size="md">
<Modal.Container placement="center" size="md">
<Modal.Dialog>
<Modal.Dialog>
...
@@ -2045,6 +2049,7 @@ export default function ResourceBookingPage() {
...
@@ -2045,6 +2049,7 @@ export default function ResourceBookingPage() {
</Modal.Root>
</Modal.Root>
<Modal.Root isOpen={isDeleteOpen} onOpenChange={setIsDeleteOpen}>
<Modal.Root isOpen={isDeleteOpen} onOpenChange={setIsDeleteOpen}>
<Modal.Trigger aria-hidden="true" className="sr-only" tabIndex={-1} />
<Modal.Backdrop>
<Modal.Backdrop>
<Modal.Container placement="center" size="md">
<Modal.Container placement="center" size="md">
<Modal.Dialog>
<Modal.Dialog>
...
@@ -2085,6 +2090,7 @@ export default function ResourceBookingPage() {
...
@@ -2085,6 +2090,7 @@ export default function ResourceBookingPage() {
</Modal.Root>
</Modal.Root>
<Modal.Root isOpen={isImportOpen} onOpenChange={setIsImportOpen}>
<Modal.Root isOpen={isImportOpen} onOpenChange={setIsImportOpen}>
<Modal.Trigger aria-hidden="true" className="sr-only" tabIndex={-1} />
<Modal.Backdrop>
<Modal.Backdrop>
<Modal.Container placement="center" scroll="inside" size="lg">
<Modal.Container placement="center" scroll="inside" size="lg">
<Modal.Dialog className={XINYUAN_4XL_DIALOG_CLASS}>
<Modal.Dialog className={XINYUAN_4XL_DIALOG_CLASS}>
...
...
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