Commit c31c9507 authored by Andy-bubu's avatar Andy-bubu

设计统一

parent 6dc24cea
...@@ -76,6 +76,9 @@ export default defineConfig({ ...@@ -76,6 +76,9 @@ export default defineConfig({
} }
}, },
esbuildMinifyIIFE: true, esbuildMinifyIIFE: true,
jsMinifierOptions: {
target: ['chrome80', 'es2020'],
},
define: { define: {
STREAMS_API_URL: '/api', STREAMS_API_URL: '/api',
STREAMS_PARSER_URL: '/parser', STREAMS_PARSER_URL: '/parser',
......
# OA 流程监控 UI/UX 全局审计
审计日期:2026-08-11
审计分支:`codex/xinyuan-ui-ux`
约束:只调整 UI/UX,不修改接口、路由、权限、数据结构、表单提交和业务状态机。
## 审计范围
- 登录页、鉴权加载态与验证码。
- 桌面/移动端 Shell、侧栏、导航、应用切换和用户信息。
- 流程监控工作台、分组切换、模板列表及管理弹窗。
- 模板配置、流程实例详情、记录抽屉和引用记录表格。
- 通用筛选、表格、空状态、反馈状态、分页和行操作。
## 迁移前主要问题
1. 品牌身份不统一:登录页为深色营销式布局,Shell 使用深灰侧栏,局部存在 teal、sky、cyan、rose 等页面私有品牌色。
2. Logo 与标题关系不统一:展开侧栏缺少完整鑫元 Logo,折叠态与应用切换按钮尺寸过大,品牌区间距未使用统一 Token。
3. 页面标题装饰过重:工作台使用大面积渐变 Banner,并展示面向开发者的说明文字,不符合企业业务应用的信息层级。
4. 页面切换样式不统一:分组切换使用大卡片,未采用统一的紧凑 Tabs/Segment 视觉。
5. 筛选模块分散:搜索和选择器直接放在标题区域或普通 Card 中,按钮、字段间距、展开区和响应式行为不一致。
6. 列表样式不统一:Catalyst Table 与页面私有表格并存,表头、固定列、行操作、空状态和选择状态缺乏统一语义。
7. 分页不统一:上一页/下一页与页码采用普通文本按钮,当前页、每页条数和总数摘要未使用鑫元分页视觉。
8. 提示信息过多直出:页面内存在开发背景、迁移说明和重复帮助文案,应收敛为标题旁 `info` 小提示,仅在需要时查看。
9. 表面层级不统一:页面存在 22/24/28/32px 多套圆角、彩色渐变、玻璃效果和页面私有阴影。
10. 暗色主题缺失:当前仅有单一视觉,Overlay、表面和文本未随根主题统一切换。
## 本轮迁移基线
- 主品牌色统一为 `#9E1B1B`,禁止将 sky/teal/cyan/rose 作为可见品牌色。
- 使用本地完整 HeroUI Pro 镜像及 HeroUI 样式层。
- 同步已验收鑫元 Token、Shell 和组件 CSS。
- 登录页使用鑫元红 Logo、紧凑品牌区、统一输入高度和不透明浅红 filled/autofill 状态。
- Shell 使用浅色同画布侧栏、紧凑品牌区、中性选中项、全局主题切换和无阴影导航表面。
- 页面说明收敛为标题旁 `info` 图标;业务状态和错误信息仍保留可见反馈。
- 分组切换改为统一页面 Tabs 视觉;筛选区按统一 Card、字段、按钮和响应式规则治理。
- 分页当前页使用鑫元红实心状态,其余操作保持中性。
- 页面级 Card 使用统一模块圆角、边框和 `--rc-shadow-card`,DataGrid/列表主体不叠加多余阴影。
## 后续验收清单
- 1440px 与 390px 下检查登录、Shell、列表和弹层无横向溢出。
- 检查 Logo 与标题间距、应用切换按钮尺寸、折叠侧栏几何。
- 检查 Tabs 的默认、Hover、选中和键盘 Focus 状态。
- 检查筛选字段、重置/查询/展开按钮和移动端堆叠。
- 检查分页总数、每页条数、当前页、禁用态和页码省略符。
- 检查提示字段仅以 `info` 图标存在,Tooltip 可访问且不遮挡内容。
- 检查浅色/深色主题下 Dropdown、Modal、Tooltip、表格和图表表面。
# 鑫元 OA 流程监控设计规范
本文档是本项目后续新增页面和功能的 UI 执行基线。新功能必须复用这里定义的 Token、组件和布局模式,不得新增页面私有品牌体系。
## 1. 基本原则
- 保持业务逻辑不变,UI 组件只承接展示与交互。
- 品牌主色固定为 `#9E1B1B`,颜色通过 `src/design-system/tokens.css` 的语义变量使用。
- 优先使用 HeroUI / HeroUI Pro;现有 Catalyst 组件在迁移期间必须通过统一 CSS 语义层呈现。
- 图标使用单一图标层,操作图标必须居中并提供 `aria-label` 或 Tooltip。
- 页面不得出现开发背景、迁移说明等冗余文案;补充说明放在标题旁 `info` 图标中。
## 2. 依赖与样式顺序
```css
@import 'tailwindcss';
@import '@heroui/styles';
@import '@heroui-pro/react/css';
@import './design-system/tokens.css';
@import './design-system/shell.css';
@import './design-system/components.css';
```
HeroUI Pro 必须使用本地完整镜像:
```json
"@heroui-pro/react": "file:../project_manager_new/node_modules/@heroui-pro/react"
```
## 3. 品牌与 Logo
- 浅色主题:`src/assets/xy-logo-red.png`。
- 深色主题:`src/assets/xy-logo-white.png`。
- Logo 使用 `object-fit: contain`,不得通过 CSS 反色或放置彩色底板模拟。
- 侧栏品牌区按“Logo → 8~10px 间距 → 系统标题 → 应用切换按钮”排列。
- 应用切换按钮统一为 36px 圆形按钮,不得比标题区域更抢眼。
- 登录 Card 内容内边距为 36px,品牌区与表单间距为 32px;登录字段标签到控件为 12px,账号/密码/验证码字段根节点之间必须有 24px 真实可见间距,不能只依赖 HeroUI 外层 `form gap`;验证码区域到登录按钮保留 24px 顶间距,禁止标签贴近上一输入框。
## 4. Shell
- 页面背景和侧栏默认使用 `--rc-bg-canvas`,主内容使用 `--rc-bg-surface`。
- Sidebar、Navbar 不使用阴影;选中导航使用中性表面,图标使用品牌红。
- 桌面页面标题左侧基准为 `--rc-page-title-inset: 68px`,移动端为 `72px`。
- 顶栏右侧提供 36px 主题切换按钮,主题写入 `xinyuan_color_theme`。
- 应用切换弹窗以当前已验收的 `src/components/ApplicationSwitcherDialog.jsx` 为唯一基线,后续必须原样复用 Headless Dialog DOM 和 class list,只允许适配应用数据、当前应用判断与跳转逻辑,禁止使用 Catalyst/HeroUI 通用 Modal 骨架做近似替代。
- 弹窗固定居中:遮罩 `rgba(15,23,42,0.42)` 并轻微模糊;面板宽 `min(46rem, 100vw - 2rem)`、最大高 `min(42rem, 100dvh - 2rem)`、16px 圆角、1px `--rc-border-default` 描边、`--rc-bg-surface` 背景和 `--rc-shadow-overlay` 阴影。
- Header 与 Body 均使用 `px-5 py-4`;标题固定“应用切换”,下方显示“选择你可访问的应用”。这里的副标题是应用切换器明确例外,不改成 info Tooltip。关闭按钮固定 24×24px 圆形,内部 16px Close icon。
- 应用列表固定使用 `grid gap-2 sm:grid-cols-2 lg:grid-cols-3`;卡片 12px 圆角、`px-3 py-3`、`--rc-bg-subtle` 表面,Logo/首字回退均为 36×36px。标题 14px/500/20px,描述 12px/400/16px并单行截断。
- 当前应用只允许一个 `当前` 标记,卡片使用 `data-current="true"`、鑫元 soft 背景和低透明度品牌描边。禁止分组标题、应用数量、访问级别/角色/分组标签、外链 icon、统计卡、装饰内容、营销文案和文字“关闭”按钮。
- 验收必须与已验收组件逐项比对面板位置/尺寸、Header 高度、关闭按钮、列数/间距、卡片高度/内边距、Logo、字级、当前态和内部滚动;只做到颜色或圆角接近不算完成。
## 5. 页面标题与提示
- 页面主标题建议 `24px / 600`,不得使用大面积营销 Banner。
- 标题后的补充说明使用 `info` 小图标和 Tooltip,不直接占用正文空间。
- 错误、警告、成功等业务反馈必须继续可见,不能隐藏在 Tooltip 中。
- 页面操作区的主按钮固定在最右侧,次按钮从右向左排列;常规文字按钮禁止添加装饰性加号、上传、下载或搜索图标,只有真正的 icon-only 操作保留图标并提供 Tooltip。
## 6. Tabs
- 页面级切换使用紧凑轨道:浅色中性背景、12~14px 圆角。
- 选中项使用白色/主题表面、品牌红文字和轻微交互阴影。
- 禁止用大卡片、底部粗红线或大面积品牌色块表示选中。
- 页面级 Tab 桌面端必须按选项内容收缩,只有外层横向滚动容器允许占满页面;禁止外层和 `Tabs` 根节点同时使用 `filter-tabs-wrap`,禁止最后一个选项后残留整行空轨道。
- Tab 标签默认只显示名称,不显示装饰性数量徽标;选中项使用鑫元红文字和白色表面。
- 页面级 Tab 与其作用域内的新增/管理操作放在同一工具行:Tab 左对齐,次按钮和主按钮在右侧,鑫元红主按钮固定最右;移动端允许整组操作换到 Tab 下方并自适应宽度。
## 7. 筛选模块
- 筛选区是独立 Card,主筛选字段优先单行排列,移动端按一列堆叠。
- 操作顺序固定为:重置、查询、展开/收起。
- 查询按钮使用品牌主色;重置使用 outline;展开使用 ghost。
- 字段标签、控件高度、间距和错误信息必须统一,禁止裸原生 Select。
- Catalyst/HeroUI 输入框必须通过 `rc-form-input` 单表面适配器呈现:默认态最外层必须显示 1px 中性描边,Hover 描边加深,Focus 切换为鑫元红描边和 soft ring;内部真实 `input` 必须透明、无描边、无阴影。禁止默认态无边框、双白框或聚焦时内外双红框。
## 8. 表格与分页
- 数据列表优先使用 HeroUI Pro DataGrid;迁移期 Catalyst Table 必须服从统一表头、边框和状态样式。
- 列表区域不使用 Card 阴影;固定列阴影只表达滚动层级。
- 行操作优先使用 32px 圆形图标按钮,危险操作使用 danger-soft。
- 分页显示总数、当前范围、每页条数和页码;当前页使用鑫元红实心状态。
- 流程监控模板列表必须使用 HeroUI Pro `DataGrid`,不再使用 Catalyst Table;DataGrid 自身拥有 20px 圆角、1px `--rc-border-default` 描边和不透明表面,列表标题/action 行保持透明无框。
- 表头使用 12px/500 弱化文字,普通单元格 14px/400,主标题 14px/550,辅助 ID 13px/400;状态使用共享 success Chip,操作列固定在右侧并使用 32px icon-only 操作。
- 列表中作为详情入口的主标题默认使用鑫元红,Hover/键盘聚焦时颜色加深并显示 1px 下划线;普通不可点击主文本仍使用 `--rc-text-primary`,不得把整列普通文字全部染红。
- 操作列必须复用 `TableActionGroup` 和 `TableActionButton`:双操作列宽度 112px,表头、单元格和按钮组全部右对齐,按钮组必须占满单元格宽度以避免被共享 `.icon-actions` 左对齐规则覆盖;按钮固定 32×32、圆形、间距 6px。编辑使用 `pm-table-action--default` 中性浅底,删除/取消使用 `pm-table-action--danger` 红色 soft 底,不得直接混用 HeroUI `ghost`/`danger-soft` 形成大小和底色不一致的按钮。
- 列表默认每页 10 条,并提供 10/20/50 页容量;分页显示总数和当前页,筛选、切换分组或页容量变化后回到第一页。
- 有数据的 DataGrid 必须按实际行数收缩高度,禁止因默认 `min-height` 在单行数据后留下大块空白。圆角只属于最外层 DataGrid,body 单元格和固定操作列不得各自出现底部圆角;固定操作列使用同一行背景和轻量左分隔,禁止形成独立弧形白色岛。
- 模板实例详情页使用同一列表合同:返回导航与页面操作同一工具行,主按钮最右;筛选 Card 只承载业务筛选字段和重置操作,页容量必须放在分页区域;动态字段列表使用 HeroUI Pro DataGrid,标题入口使用鑫元红可点击样式,空状态只保留一个来源。
## 9. Card、弹层与状态
- 页面模块圆角使用 `--rc-radius-module`,静态 Card 阴影使用 `--rc-shadow-card`。
- 数字/KPI Card 必须在右侧提供与指标含义对应的业务图标;密集卡片使用 48×48 图标底板、16px 圆角和 20×20 图标。
- 数字/KPI Card 必须直接复用 `rc-card-surface rc-dashboard-card`:Card 圆角固定 24px,1px 描边使用 `--rc-border-default`,不得硬编码深色描边、直角或页面私有圆角。
- 同一组数字卡片的 Card 本体必须统一使用不透明中性纯色表面 `--rc-bg-surface`,禁止渐变、半透明染色或每张卡片使用不同颜色。
- 视觉变化只允许放在克制的图标底板中;同一组指标必须使用不同的语义 tone 和不同业务图标,禁止重复颜色或相邻色调,禁止“彩虹卡片墙”式的卡片本体着色。
- Modal 使用 `--rc-shadow-overlay`,Dropdown/Tooltip 使用 raised/overlay 层级。
- EmptyState 包含标题、简短说明和最多一个主操作。
- 深色主题画布、Card、嵌套区域使用明确不透明表面,禁止叠加半透明浅色灰块。
## 10. 开发检查
新增或修改页面完成后至少执行:
```bash
npm run build
```
并在 1440px、390px 下检查浅色/深色、Hover、Focus、打开的下拉层、Modal、分页和空状态。
KPI 卡片属于首轮验收硬门槛,不能只看构建结果。必须在浏览器计算样式中逐项确认:Card 圆角为 24px、描边为 1px、描边色来自 `--rc-border-default`、背景来自 `--rc-bg-surface`,每张卡片右侧有对应业务图标,并且同组图标的图标、前景色和 soft 底色均不重复。任一项不符都不得标记迁移完成。
...@@ -6,8 +6,12 @@ ...@@ -6,8 +6,12 @@
"": { "": {
"hasInstallScript": true, "hasInstallScript": true,
"dependencies": { "dependencies": {
"@ant-design/icons": "^6.3.2",
"@headlessui/react": "^2.2.10", "@headlessui/react": "^2.2.10",
"@heroicons/react": "^2.2.0", "@heroicons/react": "^2.2.0",
"@heroui-pro/react": "file:../project_manager_new/node_modules/@heroui-pro/react",
"@heroui/react": "file:../project_manager_new/node_modules/@heroui/react",
"@heroui/styles": "file:../project_manager_new/node_modules/@heroui/styles",
"@tailwindcss/postcss": "^4.2.0", "@tailwindcss/postcss": "^4.2.0",
"@umijs/max": "^4.5.3", "@umijs/max": "^4.5.3",
"clsx": "^2.1.1", "clsx": "^2.1.1",
...@@ -15,19 +19,98 @@ ...@@ -15,19 +19,98 @@
"dayjs": "^1.11.20", "dayjs": "^1.11.20",
"echarts": "^6.0.0", "echarts": "^6.0.0",
"echarts-for-react": "^3.0.6", "echarts-for-react": "^3.0.6",
"react": "^18.3.1", "react": "^19.2.8",
"react-dom": "^18.3.1", "react-aria-components": "^1.20.0",
"react-dom": "^19.2.8",
"tailwind-merge": "^3.6.0",
"tailwind-variants": "^3.3.1",
"tailwindcss": "^4.2.0", "tailwindcss": "^4.2.0",
"umi-request": "^1.4.0", "umi-request": "^1.4.0",
"umi-request-progress": "^1.1.0", "umi-request-progress": "^1.1.0",
"xlsx": "^0.18.5" "xlsx": "^0.18.5"
}, },
"devDependencies": { "devDependencies": {
"@types/react": "^18.0.33", "@types/react": "^19.2.18",
"@types/react-dom": "^18.0.11", "@types/react-dom": "^19.2.4",
"typescript": "^5.0.3" "typescript": "^5.0.3"
} }
}, },
"../project_manager_new/node_modules/@heroui-pro/react": {
"version": "1.0.0-beta.7",
"license": "SEE LICENSE IN LICENSE",
"dependencies": {
"@internationalized/date": "3.12.2",
"@internationalized/number": "3.6.7",
"@react-aria/utils": "3.34.1",
"@react-stately/utils": "3.12.1"
},
"peerDependencies": {
"@heroui/react": ">=3.2.2",
"@heroui/styles": ">=3.2.2",
"@number-flow/react": ">=0.5.0",
"@tiptap/core": ">=3.23.6",
"@tiptap/extension-link": ">=3.23.6",
"@tiptap/extension-underline": ">=3.23.6",
"@tiptap/extensions": ">=3.23.6",
"@tiptap/pm": ">=3.23.6",
"@tiptap/react": ">=3.23.6",
"@tiptap/starter-kit": ">=3.23.6",
"@tiptap/suggestion": ">=3.23.6",
"embla-carousel": ">=8.6.0",
"embla-carousel-react": ">=8.6.0",
"maplibre-gl": ">=5.15.0",
"marked": ">=18.0.0",
"motion": ">=12.12.0",
"react": ">=19.0.0",
"react-aria-components": ">=1.19.0",
"react-dom": ">=19.0.0",
"react-markdown": ">=10.1.0",
"react-resizable-panels": ">=4.10.0",
"recharts": ">=2.0.0",
"remark-breaks": ">=4.0.0",
"remark-gfm": ">=4.0.0",
"shiki": ">=4.0.0",
"streamdown": ">=2.5.0",
"tailwind-merge": ">=3.4.0",
"tailwind-variants": ">=3.2.0",
"tailwindcss": ">=4.0.0"
}
},
"../project_manager_new/node_modules/@heroui/react": {
"version": "3.2.2",
"license": "MIT",
"dependencies": {
"@heroui/styles": "3.2.2",
"@radix-ui/react-avatar": "1.1.11",
"@react-aria/i18n": "3.13.1",
"@react-aria/ssr": "3.10.1",
"@react-aria/utils": "3.34.1",
"@react-stately/utils": "3.12.1",
"@react-types/color": "3.2.0",
"@react-types/shared": "3.36.0",
"input-otp": "1.4.2",
"react-aria": "^3.50.0",
"react-aria-components": "^1.19.0",
"tailwind-merge": "3.4.0",
"tailwind-variants": "3.2.2"
},
"peerDependencies": {
"react": ">=19.0.0",
"react-dom": ">=19.0.0",
"tailwindcss": ">=4.0.0"
}
},
"../project_manager_new/node_modules/@heroui/styles": {
"version": "3.2.2",
"license": "MIT",
"dependencies": {
"tailwind-variants": "3.2.2",
"tw-animate-css": "1.4.0"
},
"peerDependencies": {
"tailwindcss": ">=4.0.0"
}
},
"node_modules/@alloc/quick-lru": { "node_modules/@alloc/quick-lru": {
"version": "5.2.0", "version": "5.2.0",
"resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
...@@ -90,17 +173,15 @@ ...@@ -90,17 +173,15 @@
} }
}, },
"node_modules/@ant-design/icons": { "node_modules/@ant-design/icons": {
"version": "4.8.3", "version": "6.3.2",
"resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-4.8.3.tgz", "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-6.3.2.tgz",
"integrity": "sha512-HGlIQZzrEbAhpJR6+IGdzfbPym94Owr6JZkJ2QCCnOkPVIWMO2xgIVcOKnl8YcpijIo39V7l2qQL5fmtw56cMw==", "integrity": "sha512-B6O5a5XJ4wjtNOfZejXYwHW5zvKV5gYkjGf11dHGLEbKn0ABDGndo41+gfIiXyTFhvESj4XTotuud33mUFid0g==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@ant-design/colors": "^6.0.0", "@ant-design/colors": "^8.0.1",
"@ant-design/icons-svg": "^4.3.0", "@ant-design/icons-svg": "^4.5.0",
"@babel/runtime": "^7.11.2", "@rc-component/util": "^1.11.0",
"classnames": "^2.2.6", "clsx": "^2.1.1"
"lodash": "^4.17.15",
"rc-util": "^5.9.4"
}, },
"engines": { "engines": {
"node": ">=8" "node": ">=8"
...@@ -111,11 +192,29 @@ ...@@ -111,11 +192,29 @@
} }
}, },
"node_modules/@ant-design/icons-svg": { "node_modules/@ant-design/icons-svg": {
"version": "4.4.2", "version": "4.5.0",
"resolved": "https://registry.npmjs.org/@ant-design/icons-svg/-/icons-svg-4.4.2.tgz", "resolved": "https://registry.npmjs.org/@ant-design/icons-svg/-/icons-svg-4.5.0.tgz",
"integrity": "sha512-vHbT+zJEVzllwP+CM+ul7reTEfBR0vgxFe7+lREAsAA7YGsYpboiq2sQNeQeRvh09GfQgs/GyFEvZpJ9cLXpXA==", "integrity": "sha512-1BTUFyKPTBZ53MuTP8s0k5SFEXL7o3VHEOwLgzaoWKwnBeqIcqUtVshc4SKzhI6uACfqhJqBwBUE9FsWR3uULA==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@ant-design/icons/node_modules/@ant-design/colors": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-8.0.1.tgz",
"integrity": "sha512-foPVl0+SWIslGUtD/xBr1p9U4AKzPhNYEseXYRRo5QSzGACYZrQbe11AYJbYfAWnWSpGBx6JjBmSeugUsD9vqQ==",
"license": "MIT",
"dependencies": {
"@ant-design/fast-color": "^3.0.0"
}
},
"node_modules/@ant-design/icons/node_modules/@ant-design/fast-color": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@ant-design/fast-color/-/fast-color-3.0.1.tgz",
"integrity": "sha512-esKJegpW4nckh0o6kV3Tkb7NPIZYbPnnFxmQDUmL08ukXZAvV85TZBr70eGuke/CIArLaP6aw8lt9KILjnWuOw==",
"license": "MIT",
"engines": {
"node": ">=8.x"
}
},
"node_modules/@ant-design/moment-webpack-plugin": { "node_modules/@ant-design/moment-webpack-plugin": {
"version": "0.0.3", "version": "0.0.3",
"resolved": "https://registry.npmjs.org/@ant-design/moment-webpack-plugin/-/moment-webpack-plugin-0.0.3.tgz", "resolved": "https://registry.npmjs.org/@ant-design/moment-webpack-plugin/-/moment-webpack-plugin-0.0.3.tgz",
...@@ -641,7 +740,6 @@ ...@@ -641,7 +740,6 @@
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.6.tgz", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.6.tgz",
"integrity": "sha512-FxpRyGjrMJXh7X3wGLGhNDCRiwpWEF74sKjTLDJSG5Kyvow3QZaG0Adbqzi9ZrVjTWpsX+2cxWXD71NMg93kdw==", "integrity": "sha512-FxpRyGjrMJXh7X3wGLGhNDCRiwpWEF74sKjTLDJSG5Kyvow3QZaG0Adbqzi9ZrVjTWpsX+2cxWXD71NMg93kdw==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@ampproject/remapping": "^2.2.0", "@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.23.5", "@babel/code-frame": "^7.23.5",
...@@ -1490,7 +1588,6 @@ ...@@ -1490,7 +1588,6 @@
"resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.3.1.tgz", "resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.3.1.tgz",
"integrity": "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==", "integrity": "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@dnd-kit/accessibility": "^3.1.1", "@dnd-kit/accessibility": "^3.1.1",
"@dnd-kit/utilities": "^3.2.2", "@dnd-kit/utilities": "^3.2.2",
...@@ -2606,12 +2703,23 @@ ...@@ -2606,12 +2703,23 @@
"react": ">= 16 || ^19.0.0-rc" "react": ">= 16 || ^19.0.0-rc"
} }
}, },
"node_modules/@heroui-pro/react": {
"resolved": "../project_manager_new/node_modules/@heroui-pro/react",
"link": true
},
"node_modules/@heroui/react": {
"resolved": "../project_manager_new/node_modules/@heroui/react",
"link": true
},
"node_modules/@heroui/styles": {
"resolved": "../project_manager_new/node_modules/@heroui/styles",
"link": true
},
"node_modules/@hono/node-server": { "node_modules/@hono/node-server": {
"version": "1.19.14", "version": "1.19.14",
"resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.14.tgz", "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.14.tgz",
"integrity": "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==", "integrity": "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==",
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=18.14.1" "node": ">=18.14.1"
}, },
...@@ -2691,27 +2799,27 @@ ...@@ -2691,27 +2799,27 @@
} }
}, },
"node_modules/@internationalized/date": { "node_modules/@internationalized/date": {
"version": "3.12.1", "version": "3.12.3",
"resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.12.1.tgz", "resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.12.3.tgz",
"integrity": "sha512-6IedsVWXyq4P9Tj+TxuU8WGWM70hYLl12nbYU8jkikVpa6WXapFazPUcHUMDMoWftIDE2ILDkFFte6W2nFCkRQ==", "integrity": "sha512-fuLX+3ZKLsxI73y8b01EG/WjHb6gE6weCqlfawPO27kBWGMh9G1yH6Csv1uU7/cac9H2GHmOMt6CjmuQ1aia4Q==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@swc/helpers": "^0.5.0" "@swc/helpers": "^0.5.0"
} }
}, },
"node_modules/@internationalized/number": { "node_modules/@internationalized/number": {
"version": "3.6.6", "version": "3.6.7",
"resolved": "https://registry.npmjs.org/@internationalized/number/-/number-3.6.6.tgz", "resolved": "https://registry.npmjs.org/@internationalized/number/-/number-3.6.7.tgz",
"integrity": "sha512-iFgmQaXHE0vytNfpLZWOC2mEJCBRzcUxt53Xf/yCXG93lRvqas237i3r7X4RKMwO3txiyZD4mQjKAByFv6UGSQ==", "integrity": "sha512-3ji1fcrT+FPAK86UqEhB/psHixYo6niWPJtt7+qRaYFynt/BaJG8GhAPimtWUpEiVSTq8ZM8L5psMxGquiB/Vg==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@swc/helpers": "^0.5.0" "@swc/helpers": "^0.5.0"
} }
}, },
"node_modules/@internationalized/string": { "node_modules/@internationalized/string": {
"version": "3.2.8", "version": "3.2.10",
"resolved": "https://registry.npmjs.org/@internationalized/string/-/string-3.2.8.tgz", "resolved": "https://registry.npmjs.org/@internationalized/string/-/string-3.2.10.tgz",
"integrity": "sha512-NdbMQUSfXLYIQol5VyMtinm9pZDciiMfN7RtmSuSB78io1hqwJ0naYfxyW6vgxWBkzWymQa/3uLDlbfmshtCaA==", "integrity": "sha512-PDx6//vHSpRnHfxqMqto11zQvhsaU74O3mKv2F/0eicGZcl9NLjQmGlbHz/LsJh5tLKp4A4L7ZVTzN1/MmMTvA==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@swc/helpers": "^0.5.0" "@swc/helpers": "^0.5.0"
...@@ -3550,6 +3658,26 @@ ...@@ -3550,6 +3658,26 @@
"react-dom": ">=16.9.0" "react-dom": ">=16.9.0"
} }
}, },
"node_modules/@rc-component/util": {
"version": "1.12.0",
"resolved": "https://registry.npmjs.org/@rc-component/util/-/util-1.12.0.tgz",
"integrity": "sha512-AEjPL8JVdohIITaiXokyjL9WQ6tKWWjAYK9QU16tGNE9JaQABBQy+hA4H2Lup5MgXy9yY3iLrbZJheuU13hTdQ==",
"license": "MIT",
"dependencies": {
"is-mobile": "^5.0.0",
"react-is": "^19.2.7"
},
"peerDependencies": {
"react": ">=18.0.0",
"react-dom": ">=18.0.0"
}
},
"node_modules/@rc-component/util/node_modules/react-is": {
"version": "19.2.8",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.8.tgz",
"integrity": "sha512-s5un28nYxKJw5gvUHyW5PCC28CvBqLu9r3cWgzHT4Vo/5fqqkFcdRYsGcKf50WMPpjjFZS5d76fn3YCo2njKwQ==",
"license": "MIT"
},
"node_modules/@react-aria/focus": { "node_modules/@react-aria/focus": {
"version": "3.22.0", "version": "3.22.0",
"resolved": "https://registry.npmjs.org/@react-aria/focus/-/focus-3.22.0.tgz", "resolved": "https://registry.npmjs.org/@react-aria/focus/-/focus-3.22.0.tgz",
...@@ -3580,9 +3708,9 @@ ...@@ -3580,9 +3708,9 @@
} }
}, },
"node_modules/@react-types/shared": { "node_modules/@react-types/shared": {
"version": "3.34.0", "version": "3.36.1",
"resolved": "https://registry.npmjs.org/@react-types/shared/-/shared-3.34.0.tgz", "resolved": "https://registry.npmjs.org/@react-types/shared/-/shared-3.36.1.tgz",
"integrity": "sha512-gp6xo/s2lX54AlTjOiqwDnxA7UW79BNvI9dB9pr3LZTzRKCd1ZA+ZbgKw/ReIiWuvvVw/8QFJpnqeeFyLocMcQ==", "integrity": "sha512-AzsuD9OfxTOZMMvTRhlN3oHBwOmFN7tDh27LzqmHt4+uOgPhJT7ZM7/kVs/8/o0WxayMUIk3hBmCFRHv1FUoag==",
"license": "Apache-2.0", "license": "Apache-2.0",
"peerDependencies": { "peerDependencies": {
"react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1"
...@@ -3774,7 +3902,6 @@ ...@@ -3774,7 +3902,6 @@
"resolved": "https://registry.npmjs.org/@svgr/core/-/core-6.5.1.tgz", "resolved": "https://registry.npmjs.org/@svgr/core/-/core-6.5.1.tgz",
"integrity": "sha512-/xdLSWxK5QkqG524ONSjvg3V/FkNyCv538OIBdQqPNaAta3AsXj/Bd2FbvR87yMbXO2hFSWiAe/Q6IkVPDw+mw==", "integrity": "sha512-/xdLSWxK5QkqG524ONSjvg3V/FkNyCv538OIBdQqPNaAta3AsXj/Bd2FbvR87yMbXO2hFSWiAe/Q6IkVPDw+mw==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@babel/core": "^7.19.6", "@babel/core": "^7.19.6",
"@svgr/babel-preset": "^6.5.1", "@svgr/babel-preset": "^6.5.1",
...@@ -4221,32 +4348,6 @@ ...@@ -4221,32 +4348,6 @@
"@babel/types": "^7.28.2" "@babel/types": "^7.28.2"
} }
}, },
"node_modules/@types/eslint": {
"version": "9.6.1",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz",
"integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==",
"license": "MIT",
"dependencies": {
"@types/estree": "*",
"@types/json-schema": "*"
}
},
"node_modules/@types/eslint-scope": {
"version": "3.7.7",
"resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz",
"integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==",
"license": "MIT",
"dependencies": {
"@types/eslint": "*",
"@types/estree": "*"
}
},
"node_modules/@types/estree": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz",
"integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==",
"license": "MIT"
},
"node_modules/@types/graceful-fs": { "node_modules/@types/graceful-fs": {
"version": "4.1.9", "version": "4.1.9",
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz",
...@@ -4262,12 +4363,6 @@ ...@@ -4262,12 +4363,6 @@
"integrity": "sha512-oOMFT8vmCTFncsF1engrs04jatz8/Anwx3De9uxnOK4chgSEgWBvFtpSoJo8u3784JNO+ql5tzRR6phHoRnscQ==", "integrity": "sha512-oOMFT8vmCTFncsF1engrs04jatz8/Anwx3De9uxnOK4chgSEgWBvFtpSoJo8u3784JNO+ql5tzRR6phHoRnscQ==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/history": {
"version": "4.7.11",
"resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz",
"integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==",
"license": "MIT"
},
"node_modules/@types/hoist-non-react-statics": { "node_modules/@types/hoist-non-react-statics": {
"version": "3.3.7", "version": "3.3.7",
"resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.7.tgz", "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.7.tgz",
...@@ -4292,12 +4387,6 @@ ...@@ -4292,12 +4387,6 @@
"integrity": "sha512-IwpIMieE55oGWiXkQPSBY1nw1nFs6bsKXTFskNY8sdS17K24vyEBRQZEwlRS7ZmXCWnJcQtbxWzly+cODWGs2A==", "integrity": "sha512-IwpIMieE55oGWiXkQPSBY1nw1nFs6bsKXTFskNY8sdS17K24vyEBRQZEwlRS7ZmXCWnJcQtbxWzly+cODWGs2A==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/isomorphic-fetch": {
"version": "0.0.34",
"resolved": "https://registry.npmjs.org/@types/isomorphic-fetch/-/isomorphic-fetch-0.0.34.tgz",
"integrity": "sha512-BmJKuPCZCR6pbYYgi5nKFJrPC4pLoBgsi/B1nFN64Ba+hLLGUcKPIh7eVlR2xG763Ap08hgQafq/Wx4RFb0omQ==",
"license": "MIT"
},
"node_modules/@types/istanbul-lib-coverage": { "node_modules/@types/istanbul-lib-coverage": {
"version": "2.0.6", "version": "2.0.6",
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz",
...@@ -4339,7 +4428,6 @@ ...@@ -4339,7 +4428,6 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.2.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.2.tgz",
"integrity": "sha512-sokuT28dxf9JT5Kady1fsXOvI4HVpjZa95NKT5y9PNTIrs2AsobR4GFAA90ZG8M+nxVRLysCXsVj6eGC7Vbrlw==", "integrity": "sha512-sokuT28dxf9JT5Kady1fsXOvI4HVpjZa95NKT5y9PNTIrs2AsobR4GFAA90ZG8M+nxVRLysCXsVj6eGC7Vbrlw==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"undici-types": "~7.19.0" "undici-types": "~7.19.0"
} }
...@@ -4356,65 +4444,24 @@ ...@@ -4356,65 +4444,24 @@
"integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/prop-types": {
"version": "15.7.15",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz",
"integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==",
"license": "MIT"
},
"node_modules/@types/react": { "node_modules/@types/react": {
"version": "18.3.28", "version": "19.2.18",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.28.tgz", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.18.tgz",
"integrity": "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==", "integrity": "sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==",
"dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@types/prop-types": "*",
"csstype": "^3.2.2" "csstype": "^3.2.2"
} }
}, },
"node_modules/@types/react-dom": { "node_modules/@types/react-dom": {
"version": "18.3.7", "version": "19.2.4",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.4.tgz",
"integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", "integrity": "sha512-Bsc+QHgp+P/F02XDzNCY9jnZNCUuLki36KT7VKrTXXLdHf+vHMNZnW1rVu5DNW/rCK+fya3DATySbLM4yhtKUw==",
"devOptional": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"peerDependencies": { "peerDependencies": {
"@types/react": "^18.0.0" "@types/react": "^19.2.0"
}
},
"node_modules/@types/react-router": {
"version": "5.1.20",
"resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz",
"integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==",
"license": "MIT",
"dependencies": {
"@types/history": "^4.7.11",
"@types/react": "*"
}
},
"node_modules/@types/react-router-dom": {
"version": "4.3.5",
"resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-4.3.5.tgz",
"integrity": "sha512-eFajSUASYbPHg2BDM1G8Btx+YqGgvROPIg6sBhl3O4kbDdYXdFdfrgQFf/pcBuQVObjfT9AL/dd15jilR5DIEA==",
"license": "MIT",
"dependencies": {
"@types/history": "*",
"@types/react": "*",
"@types/react-router": "*"
}
},
"node_modules/@types/react-router-redux": {
"version": "5.0.27",
"resolved": "https://registry.npmjs.org/@types/react-router-redux/-/react-router-redux-5.0.27.tgz",
"integrity": "sha512-qC5lbuP2K/kMR/HE3e5ltCJptyiQhmfV0wbklqcqWDbNdpJBDwUsBGP4f/0RDYJf09+OTbz43u6iG+8E0Zcwqw==",
"license": "MIT",
"dependencies": {
"@types/history": "^4.7.11",
"@types/react": "*",
"@types/react-router": "^5.1.0",
"redux": ">= 3.7.2"
} }
}, },
"node_modules/@types/resolve": { "node_modules/@types/resolve": {
...@@ -4507,7 +4554,6 @@ ...@@ -4507,7 +4554,6 @@
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz",
"integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==",
"license": "BSD-2-Clause", "license": "BSD-2-Clause",
"peer": true,
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "5.62.0", "@typescript-eslint/scope-manager": "5.62.0",
"@typescript-eslint/types": "5.62.0", "@typescript-eslint/types": "5.62.0",
...@@ -5069,7 +5115,6 @@ ...@@ -5069,7 +5115,6 @@
} }
], ],
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"nanoid": "^3.3.6", "nanoid": "^3.3.6",
"picocolors": "^1.0.0", "picocolors": "^1.0.0",
...@@ -5830,7 +5875,6 @@ ...@@ -5830,7 +5875,6 @@
"resolved": "https://registry.npmjs.org/less/-/less-4.6.4.tgz", "resolved": "https://registry.npmjs.org/less/-/less-4.6.4.tgz",
"integrity": "sha512-OJmO5+HxZLLw0RLzkqaNHzcgEAQG7C0y3aMbwtCzIUFZsLMNNq/1IdAdHEycQ58CwUO3jPTHmoN+tE5I7FQxNg==", "integrity": "sha512-OJmO5+HxZLLw0RLzkqaNHzcgEAQG7C0y3aMbwtCzIUFZsLMNNq/1IdAdHEycQ58CwUO3jPTHmoN+tE5I7FQxNg==",
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true,
"dependencies": { "dependencies": {
"copy-anything": "^3.0.5", "copy-anything": "^3.0.5",
"parse-node-version": "^1.0.1" "parse-node-version": "^1.0.1"
...@@ -6100,6 +6144,36 @@ ...@@ -6100,6 +6144,36 @@
"react-dom": ">=16.0.0" "react-dom": ">=16.0.0"
} }
}, },
"node_modules/@umijs/plugins/node_modules/@ant-design/icons": {
"version": "4.8.3",
"resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-4.8.3.tgz",
"integrity": "sha512-HGlIQZzrEbAhpJR6+IGdzfbPym94Owr6JZkJ2QCCnOkPVIWMO2xgIVcOKnl8YcpijIo39V7l2qQL5fmtw56cMw==",
"license": "MIT",
"dependencies": {
"@ant-design/colors": "^6.0.0",
"@ant-design/icons-svg": "^4.3.0",
"@babel/runtime": "^7.11.2",
"classnames": "^2.2.6",
"lodash": "^4.17.15",
"rc-util": "^5.9.4"
},
"engines": {
"node": ">=8"
},
"peerDependencies": {
"react": ">=16.0.0",
"react-dom": ">=16.0.0"
}
},
"node_modules/@umijs/plugins/node_modules/@ant-design/icons/node_modules/@ant-design/colors": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-6.0.0.tgz",
"integrity": "sha512-qAZRvPzfdWHtfameEGP2Qvuf838NhergR35o+EuVyB5XvSA98xod5r4utvi4TJ3ywmevm290g9nsCG5MryrdWQ==",
"license": "MIT",
"dependencies": {
"@ctrl/tinycolor": "^3.4.0"
}
},
"node_modules/@umijs/plugins/node_modules/@ant-design/pro-components": { "node_modules/@umijs/plugins/node_modules/@ant-design/pro-components": {
"version": "2.8.10", "version": "2.8.10",
"resolved": "https://registry.npmjs.org/@ant-design/pro-components/-/pro-components-2.8.10.tgz", "resolved": "https://registry.npmjs.org/@ant-design/pro-components/-/pro-components-2.8.10.tgz",
...@@ -6347,7 +6421,6 @@ ...@@ -6347,7 +6421,6 @@
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-4.44.0.tgz", "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-4.44.0.tgz",
"integrity": "sha512-RuIqHYrS98LrK/8kJJOJMMSQ/BCpojwsXDh7p0fBmp38ZOz6dlk+uyFRRusH+V+t3POoCsDOQ2zhomEYOeReXw==", "integrity": "sha512-RuIqHYrS98LrK/8kJJOJMMSQ/BCpojwsXDh7p0fBmp38ZOz6dlk+uyFRRusH+V+t3POoCsDOQ2zhomEYOeReXw==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@tanstack/query-core": "4.44.0", "@tanstack/query-core": "4.44.0",
"use-sync-external-store": "^1.6.0" "use-sync-external-store": "^1.6.0"
...@@ -6406,31 +6479,6 @@ ...@@ -6406,31 +6479,6 @@
"styled-components": ">= 2" "styled-components": ">= 2"
} }
}, },
"node_modules/@umijs/plugins/node_modules/dva": {
"version": "2.5.0-beta.2",
"resolved": "https://registry.npmjs.org/dva/-/dva-2.5.0-beta.2.tgz",
"integrity": "sha512-kc2+CHhF1cNIU3Rg1miMhHgOKJ/VDrq9d6ynVBZf1EN2YKWU3MVFq/uTTBqMr2qkR0m9f8VKHOFmfKLtfMI93Q==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.0.0",
"@types/isomorphic-fetch": "^0.0.34",
"@types/react-router-dom": "^4.2.7",
"@types/react-router-redux": "^5.0.13",
"dva-core": "^1.5.0-beta.2",
"global": "^4.3.2",
"history": "^4.6.3",
"invariant": "^2.2.2",
"isomorphic-fetch": "^2.2.1",
"react-redux": "^5.0.5",
"react-router-dom": "^4.1.2",
"react-router-redux": "5.0.0-alpha.9",
"redux": "^3.7.2"
},
"peerDependencies": {
"react": "15.x || ^16.0.0-0",
"react-dom": "15.x || ^16.0.0-0"
}
},
"node_modules/@umijs/plugins/node_modules/dva-core": { "node_modules/@umijs/plugins/node_modules/dva-core": {
"version": "2.0.4", "version": "2.0.4",
"resolved": "https://registry.npmjs.org/dva-core/-/dva-core-2.0.4.tgz", "resolved": "https://registry.npmjs.org/dva-core/-/dva-core-2.0.4.tgz",
...@@ -6471,110 +6519,6 @@ ...@@ -6471,110 +6519,6 @@
"dva": "^2.5.0-0" "dva": "^2.5.0-0"
} }
}, },
"node_modules/@umijs/plugins/node_modules/dva/node_modules/dva-core": {
"version": "1.5.0-beta.2",
"resolved": "https://registry.npmjs.org/dva-core/-/dva-core-1.5.0-beta.2.tgz",
"integrity": "sha512-xmtr/J63EZXBdVXNBW+QCD7p9CaE8kAo2U1faRyv3PIGcy0G3Y6IBDNtoBB/Cj3nzk/jvX0dv96Hnh1kpSnI7Q==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.0.0",
"flatten": "^1.0.2",
"global": "^4.3.2",
"invariant": "^2.2.1",
"is-plain-object": "^2.0.3",
"redux": "^3.7.1",
"redux-saga": "^0.16.0",
"warning": "^3.0.0"
},
"peerDependencies": {
"redux": "3.x"
}
},
"node_modules/@umijs/plugins/node_modules/dva/node_modules/react-redux": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-5.1.2.tgz",
"integrity": "sha512-Ns1G0XXc8hDyH/OcBHOxNgQx9ayH3SPxBnFCOidGKSle8pKihysQw2rG/PmciUQRoclhVBO8HMhiRmGXnDja9Q==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.1.2",
"hoist-non-react-statics": "^3.3.0",
"invariant": "^2.2.4",
"loose-envify": "^1.1.0",
"prop-types": "^15.6.1",
"react-is": "^16.6.0",
"react-lifecycles-compat": "^3.0.0"
},
"peerDependencies": {
"react": "^0.14.0 || ^15.0.0-0 || ^16.0.0-0",
"redux": "^2.0.0 || ^3.0.0 || ^4.0.0-0"
}
},
"node_modules/@umijs/plugins/node_modules/dva/node_modules/redux": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/redux/-/redux-3.7.2.tgz",
"integrity": "sha512-pNqnf9q1hI5HHZRBkj3bAngGZW/JMCmexDlOxw4XagXY2o1327nHH54LoTjiPJ0gizoqPDRqWyX/00g0hD6w+A==",
"license": "MIT",
"peer": true,
"dependencies": {
"lodash": "^4.2.1",
"lodash-es": "^4.2.1",
"loose-envify": "^1.1.0",
"symbol-observable": "^1.0.3"
}
},
"node_modules/@umijs/plugins/node_modules/dva/node_modules/warning": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz",
"integrity": "sha512-jMBt6pUrKn5I+OGgtQ4YZLdhIeJmObddh6CsibPxyQ5yPZm1XExSyzC1LCNX7BzhxWgiHmizBWJTHJIjMjTQYQ==",
"license": "BSD-3-Clause",
"dependencies": {
"loose-envify": "^1.0.0"
}
},
"node_modules/@umijs/plugins/node_modules/history": {
"version": "4.10.1",
"resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz",
"integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.1.2",
"loose-envify": "^1.2.0",
"resolve-pathname": "^3.0.0",
"tiny-invariant": "^1.0.2",
"tiny-warning": "^1.0.0",
"value-equal": "^1.0.1"
}
},
"node_modules/@umijs/plugins/node_modules/react": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
"integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
"license": "MIT",
"peer": true,
"dependencies": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/@umijs/plugins/node_modules/react-dom": {
"version": "16.14.0",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.14.0.tgz",
"integrity": "sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==",
"license": "MIT",
"peer": true,
"dependencies": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1",
"prop-types": "^15.6.2",
"scheduler": "^0.19.1"
},
"peerDependencies": {
"react": "^16.14.0"
}
},
"node_modules/@umijs/plugins/node_modules/react-intl": { "node_modules/@umijs/plugins/node_modules/react-intl": {
"version": "3.12.1", "version": "3.12.1",
"resolved": "https://registry.npmjs.org/react-intl/-/react-intl-3.12.1.tgz", "resolved": "https://registry.npmjs.org/react-intl/-/react-intl-3.12.1.tgz",
...@@ -6643,63 +6587,11 @@ ...@@ -6643,63 +6587,11 @@
"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@umijs/plugins/node_modules/react-router": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-4.3.1.tgz",
"integrity": "sha512-yrvL8AogDh2X42Dt9iknk4wF4V8bWREPirFfS9gLU1huk6qK41sg7Z/1S81jjTrGHxa3B8R3J6xIkDAA6CVarg==",
"license": "MIT",
"dependencies": {
"history": "^4.7.2",
"hoist-non-react-statics": "^2.5.0",
"invariant": "^2.2.4",
"loose-envify": "^1.3.1",
"path-to-regexp": "^1.7.0",
"prop-types": "^15.6.1",
"warning": "^4.0.1"
},
"peerDependencies": {
"react": ">=15"
}
},
"node_modules/@umijs/plugins/node_modules/react-router-dom": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-4.3.1.tgz",
"integrity": "sha512-c/MlywfxDdCp7EnB7YfPMOfMD3tOtIjrQlj/CKfNMBxdmpJP8xcz5P/UAFn3JbnQCNUxsHyVVqllF9LhgVyFCA==",
"license": "MIT",
"dependencies": {
"history": "^4.7.2",
"invariant": "^2.2.4",
"loose-envify": "^1.3.1",
"prop-types": "^15.6.1",
"react-router": "^4.3.1",
"warning": "^4.0.1"
},
"peerDependencies": {
"react": ">=15"
}
},
"node_modules/@umijs/plugins/node_modules/react-router/node_modules/hoist-non-react-statics": {
"version": "2.5.5",
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz",
"integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw==",
"license": "BSD-3-Clause"
},
"node_modules/@umijs/plugins/node_modules/scheduler": {
"version": "0.19.1",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz",
"integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==",
"license": "MIT",
"dependencies": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1"
}
},
"node_modules/@umijs/plugins/node_modules/styled-components": { "node_modules/@umijs/plugins/node_modules/styled-components": {
"version": "6.1.1", "version": "6.1.1",
"resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.1.tgz", "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.1.tgz",
"integrity": "sha512-cpZZP5RrKRIClBW5Eby4JM1wElLVP4NQrJbJ0h10TidTyJf4SIIwa3zLXOoPb4gJi8MsJ8mjq5mu2IrEhZIAcQ==", "integrity": "sha512-cpZZP5RrKRIClBW5Eby4JM1wElLVP4NQrJbJ0h10TidTyJf4SIIwa3zLXOoPb4gJi8MsJ8mjq5mu2IrEhZIAcQ==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@emotion/is-prop-valid": "^1.2.1", "@emotion/is-prop-valid": "^1.2.1",
"@emotion/unitless": "^0.8.0", "@emotion/unitless": "^0.8.0",
...@@ -6814,12 +6706,46 @@ ...@@ -6814,12 +6706,46 @@
"node": ">=8.6.0" "node": ">=8.6.0"
} }
}, },
"node_modules/@umijs/preset-umi/node_modules/react": {
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
"license": "MIT",
"dependencies": {
"loose-envify": "^1.1.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/@umijs/preset-umi/node_modules/react-dom": {
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
"license": "MIT",
"dependencies": {
"loose-envify": "^1.1.0",
"scheduler": "^0.23.2"
},
"peerDependencies": {
"react": "^18.3.1"
}
},
"node_modules/@umijs/preset-umi/node_modules/regenerator-runtime": { "node_modules/@umijs/preset-umi/node_modules/regenerator-runtime": {
"version": "0.13.11", "version": "0.13.11",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@umijs/preset-umi/node_modules/scheduler": {
"version": "0.23.2",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
"integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
"license": "MIT",
"dependencies": {
"loose-envify": "^1.1.0"
}
},
"node_modules/@umijs/react-refresh-webpack-plugin": { "node_modules/@umijs/react-refresh-webpack-plugin": {
"version": "0.5.11", "version": "0.5.11",
"resolved": "https://registry.npmjs.org/@umijs/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.11.tgz", "resolved": "https://registry.npmjs.org/@umijs/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.11.tgz",
...@@ -6920,32 +6846,66 @@ ...@@ -6920,32 +6846,66 @@
"react-router-dom": "6.3.0" "react-router-dom": "6.3.0"
} }
}, },
"node_modules/@umijs/test": { "node_modules/@umijs/server/node_modules/react": {
"version": "4.6.51", "version": "18.3.1",
"resolved": "https://registry.npmjs.org/@umijs/test/-/test-4.6.51.tgz", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
"integrity": "sha512-BK1tbS6olKKGIoy3a7la7l09Jyt3+THvGEYy9oXc7/pyj7SJ6HSoIrE7L85AMWXM8EiOM9dAHSLiE6J22uxK4g==", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/plugin-transform-modules-commonjs": "7.23.3", "loose-envify": "^1.1.0"
"@jest/types": "27.5.1",
"@umijs/bundler-utils": "4.6.51",
"@umijs/utils": "4.6.51",
"babel-jest": "^29.7.0",
"esbuild": "0.21.4",
"identity-obj-proxy": "3.0.0",
"isomorphic-unfetch": "4.0.2"
}
}, },
"node_modules/@umijs/ui": { "engines": {
"version": "3.0.1", "node": ">=0.10.0"
"resolved": "https://registry.npmjs.org/@umijs/ui/-/ui-3.0.1.tgz", }
"integrity": "sha512-zcz37AJH0xt/6XVVbyO/hmsK9Hq4vH23HZ4KYVi5A8rbM9KeJkJigTS7ELOdArawZhVNGe+h3a5Oixs4a2QsWw==",
"license": "MIT"
}, },
"node_modules/@umijs/use-params": { "node_modules/@umijs/server/node_modules/react-dom": {
"version": "1.0.9", "version": "18.3.1",
"resolved": "https://registry.npmjs.org/@umijs/use-params/-/use-params-1.0.9.tgz", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
"integrity": "sha512-QlN0RJSBVQBwLRNxbxjQ5qzqYIGn+K7USppMoIOVlf7fxXHsnQZ2bEsa6Pm74bt6DVQxpUE8HqvdStn6Y9FV1w==", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
"license": "MIT",
"dependencies": {
"loose-envify": "^1.1.0",
"scheduler": "^0.23.2"
},
"peerDependencies": {
"react": "^18.3.1"
}
},
"node_modules/@umijs/server/node_modules/scheduler": {
"version": "0.23.2",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
"integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
"license": "MIT",
"dependencies": {
"loose-envify": "^1.1.0"
}
},
"node_modules/@umijs/test": {
"version": "4.6.51",
"resolved": "https://registry.npmjs.org/@umijs/test/-/test-4.6.51.tgz",
"integrity": "sha512-BK1tbS6olKKGIoy3a7la7l09Jyt3+THvGEYy9oXc7/pyj7SJ6HSoIrE7L85AMWXM8EiOM9dAHSLiE6J22uxK4g==",
"license": "MIT",
"dependencies": {
"@babel/plugin-transform-modules-commonjs": "7.23.3",
"@jest/types": "27.5.1",
"@umijs/bundler-utils": "4.6.51",
"@umijs/utils": "4.6.51",
"babel-jest": "^29.7.0",
"esbuild": "0.21.4",
"identity-obj-proxy": "3.0.0",
"isomorphic-unfetch": "4.0.2"
}
},
"node_modules/@umijs/ui": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@umijs/ui/-/ui-3.0.1.tgz",
"integrity": "sha512-zcz37AJH0xt/6XVVbyO/hmsK9Hq4vH23HZ4KYVi5A8rbM9KeJkJigTS7ELOdArawZhVNGe+h3a5Oixs4a2QsWw==",
"license": "MIT"
},
"node_modules/@umijs/use-params": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/@umijs/use-params/-/use-params-1.0.9.tgz",
"integrity": "sha512-QlN0RJSBVQBwLRNxbxjQ5qzqYIGn+K7USppMoIOVlf7fxXHsnQZ2bEsa6Pm74bt6DVQxpUE8HqvdStn6Y9FV1w==",
"license": "MIT", "license": "MIT",
"peerDependencies": { "peerDependencies": {
"react": "*" "react": "*"
...@@ -7131,164 +7091,6 @@ ...@@ -7131,164 +7091,6 @@
"vite": "^4.2.0" "vite": "^4.2.0"
} }
}, },
"node_modules/@webassemblyjs/ast": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz",
"integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==",
"license": "MIT",
"dependencies": {
"@webassemblyjs/helper-numbers": "1.13.2",
"@webassemblyjs/helper-wasm-bytecode": "1.13.2"
}
},
"node_modules/@webassemblyjs/floating-point-hex-parser": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz",
"integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==",
"license": "MIT"
},
"node_modules/@webassemblyjs/helper-api-error": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz",
"integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==",
"license": "MIT"
},
"node_modules/@webassemblyjs/helper-buffer": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz",
"integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==",
"license": "MIT"
},
"node_modules/@webassemblyjs/helper-numbers": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz",
"integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==",
"license": "MIT",
"dependencies": {
"@webassemblyjs/floating-point-hex-parser": "1.13.2",
"@webassemblyjs/helper-api-error": "1.13.2",
"@xtuc/long": "4.2.2"
}
},
"node_modules/@webassemblyjs/helper-wasm-bytecode": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz",
"integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==",
"license": "MIT"
},
"node_modules/@webassemblyjs/helper-wasm-section": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz",
"integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==",
"license": "MIT",
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
"@webassemblyjs/helper-buffer": "1.14.1",
"@webassemblyjs/helper-wasm-bytecode": "1.13.2",
"@webassemblyjs/wasm-gen": "1.14.1"
}
},
"node_modules/@webassemblyjs/ieee754": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz",
"integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==",
"license": "MIT",
"dependencies": {
"@xtuc/ieee754": "^1.2.0"
}
},
"node_modules/@webassemblyjs/leb128": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz",
"integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==",
"license": "Apache-2.0",
"dependencies": {
"@xtuc/long": "4.2.2"
}
},
"node_modules/@webassemblyjs/utf8": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz",
"integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==",
"license": "MIT"
},
"node_modules/@webassemblyjs/wasm-edit": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz",
"integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==",
"license": "MIT",
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
"@webassemblyjs/helper-buffer": "1.14.1",
"@webassemblyjs/helper-wasm-bytecode": "1.13.2",
"@webassemblyjs/helper-wasm-section": "1.14.1",
"@webassemblyjs/wasm-gen": "1.14.1",
"@webassemblyjs/wasm-opt": "1.14.1",
"@webassemblyjs/wasm-parser": "1.14.1",
"@webassemblyjs/wast-printer": "1.14.1"
}
},
"node_modules/@webassemblyjs/wasm-gen": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz",
"integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==",
"license": "MIT",
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
"@webassemblyjs/helper-wasm-bytecode": "1.13.2",
"@webassemblyjs/ieee754": "1.13.2",
"@webassemblyjs/leb128": "1.13.2",
"@webassemblyjs/utf8": "1.13.2"
}
},
"node_modules/@webassemblyjs/wasm-opt": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz",
"integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==",
"license": "MIT",
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
"@webassemblyjs/helper-buffer": "1.14.1",
"@webassemblyjs/wasm-gen": "1.14.1",
"@webassemblyjs/wasm-parser": "1.14.1"
}
},
"node_modules/@webassemblyjs/wasm-parser": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz",
"integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==",
"license": "MIT",
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
"@webassemblyjs/helper-api-error": "1.13.2",
"@webassemblyjs/helper-wasm-bytecode": "1.13.2",
"@webassemblyjs/ieee754": "1.13.2",
"@webassemblyjs/leb128": "1.13.2",
"@webassemblyjs/utf8": "1.13.2"
}
},
"node_modules/@webassemblyjs/wast-printer": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz",
"integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==",
"license": "MIT",
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
"@xtuc/long": "4.2.2"
}
},
"node_modules/@xtuc/ieee754": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
"integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==",
"license": "BSD-3-Clause"
},
"node_modules/@xtuc/long": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
"integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
"license": "Apache-2.0"
},
"node_modules/accepts": { "node_modules/accepts": {
"version": "1.3.8", "version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
...@@ -7316,7 +7118,6 @@ ...@@ -7316,7 +7118,6 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"acorn": "bin/acorn" "acorn": "bin/acorn"
}, },
...@@ -7324,18 +7125,6 @@ ...@@ -7324,18 +7125,6 @@
"node": ">=0.4.0" "node": ">=0.4.0"
} }
}, },
"node_modules/acorn-import-phases": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz",
"integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==",
"license": "MIT",
"engines": {
"node": ">=10.13.0"
},
"peerDependencies": {
"acorn": "^8.14.0"
}
},
"node_modules/acorn-jsx": { "node_modules/acorn-jsx": {
"version": "5.3.2", "version": "5.3.2",
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
...@@ -7395,7 +7184,6 @@ ...@@ -7395,7 +7184,6 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz",
"integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"fast-deep-equal": "^3.1.1", "fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0", "fast-json-stable-stringify": "^2.0.0",
...@@ -7407,45 +7195,6 @@ ...@@ -7407,45 +7195,6 @@
"url": "https://github.com/sponsors/epoberezkin" "url": "https://github.com/sponsors/epoberezkin"
} }
}, },
"node_modules/ajv-formats": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
"integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
"license": "MIT",
"dependencies": {
"ajv": "^8.0.0"
},
"peerDependencies": {
"ajv": "^8.0.0"
},
"peerDependenciesMeta": {
"ajv": {
"optional": true
}
}
},
"node_modules/ajv-formats/node_modules/ajv": {
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz",
"integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==",
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/ajv-formats/node_modules/json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"license": "MIT"
},
"node_modules/ajv-keywords": { "node_modules/ajv-keywords": {
"version": "3.5.2", "version": "3.5.2",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
...@@ -7496,7 +7245,6 @@ ...@@ -7496,7 +7245,6 @@
"resolved": "https://registry.npmjs.org/antd/-/antd-4.24.16.tgz", "resolved": "https://registry.npmjs.org/antd/-/antd-4.24.16.tgz",
"integrity": "sha512-zZrK4UYxHtU6tGOOf0uG/kBRx1kTvypfuSB3GqE/SBQxFhZ/TZ+yj7Z1qwI8vGfMtUUJdLeuoCAqGDa1zPsXnQ==", "integrity": "sha512-zZrK4UYxHtU6tGOOf0uG/kBRx1kTvypfuSB3GqE/SBQxFhZ/TZ+yj7Z1qwI8vGfMtUUJdLeuoCAqGDa1zPsXnQ==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@ant-design/colors": "^6.0.0", "@ant-design/colors": "^6.0.0",
"@ant-design/icons": "^4.8.2", "@ant-design/icons": "^4.8.2",
...@@ -7560,6 +7308,27 @@ ...@@ -7560,6 +7308,27 @@
"dayjs": "*" "dayjs": "*"
} }
}, },
"node_modules/antd/node_modules/@ant-design/icons": {
"version": "4.8.3",
"resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-4.8.3.tgz",
"integrity": "sha512-HGlIQZzrEbAhpJR6+IGdzfbPym94Owr6JZkJ2QCCnOkPVIWMO2xgIVcOKnl8YcpijIo39V7l2qQL5fmtw56cMw==",
"license": "MIT",
"dependencies": {
"@ant-design/colors": "^6.0.0",
"@ant-design/icons-svg": "^4.3.0",
"@babel/runtime": "^7.11.2",
"classnames": "^2.2.6",
"lodash": "^4.17.15",
"rc-util": "^5.9.4"
},
"engines": {
"node": ">=8"
},
"peerDependencies": {
"react": ">=16.0.0",
"react-dom": ">=16.0.0"
}
},
"node_modules/anymatch": { "node_modules/anymatch": {
"version": "3.1.3", "version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
...@@ -8375,7 +8144,6 @@ ...@@ -8375,7 +8144,6 @@
} }
], ],
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"baseline-browser-mapping": "^2.10.12", "baseline-browser-mapping": "^2.10.12",
"caniuse-lite": "^1.0.30001782", "caniuse-lite": "^1.0.30001782",
...@@ -8652,15 +8420,6 @@ ...@@ -8652,15 +8420,6 @@
"fsevents": "~2.3.2" "fsevents": "~2.3.2"
} }
}, },
"node_modules/chrome-trace-event": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz",
"integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==",
"license": "MIT",
"engines": {
"node": ">=6.0"
}
},
"node_modules/ci-info": { "node_modules/ci-info": {
"version": "3.9.0", "version": "3.9.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz",
...@@ -9441,8 +9200,7 @@ ...@@ -9441,8 +9200,7 @@
"version": "1.11.20", "version": "1.11.20",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.20.tgz", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.20.tgz",
"integrity": "sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==", "integrity": "sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==",
"license": "MIT", "license": "MIT"
"peer": true
}, },
"node_modules/debug": { "node_modules/debug": {
"version": "4.4.3", "version": "4.4.3",
...@@ -10113,33 +9871,6 @@ ...@@ -10113,33 +9871,6 @@
"stream-shift": "^1.0.2" "stream-shift": "^1.0.2"
} }
}, },
"node_modules/dva-core": {
"version": "1.6.0-beta.7",
"resolved": "https://registry.npmjs.org/dva-core/-/dva-core-1.6.0-beta.7.tgz",
"integrity": "sha512-e+0yOEWUK+XbnqflX+KXoLZDGxn+kLKgcT6XYT8GyRe0xcbmLEbwDZO0DXUkdsbxfqSOlLkIprMUoYJ3D5B4Gg==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.0.0",
"flatten": "^1.0.2",
"global": "^4.3.2",
"invariant": "^2.2.1",
"is-plain-object": "^2.0.3",
"redux-saga": "^0.16.0",
"warning": "^3.0.0"
},
"peerDependencies": {
"redux": "4.x"
}
},
"node_modules/dva-core/node_modules/warning": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz",
"integrity": "sha512-jMBt6pUrKn5I+OGgtQ4YZLdhIeJmObddh6CsibPxyQ5yPZm1XExSyzC1LCNX7BzhxWgiHmizBWJTHJIjMjTQYQ==",
"license": "BSD-3-Clause",
"dependencies": {
"loose-envify": "^1.0.0"
}
},
"node_modules/dva-loading": { "node_modules/dva-loading": {
"version": "3.0.25", "version": "3.0.25",
"resolved": "https://registry.npmjs.org/dva-loading/-/dva-loading-3.0.25.tgz", "resolved": "https://registry.npmjs.org/dva-loading/-/dva-loading-3.0.25.tgz",
...@@ -10473,12 +10204,6 @@ ...@@ -10473,12 +10204,6 @@
"node": ">= 0.4" "node": ">= 0.4"
} }
}, },
"node_modules/es-module-lexer": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz",
"integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==",
"license": "MIT"
},
"node_modules/es-object-atoms": { "node_modules/es-object-atoms": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
...@@ -10658,7 +10383,6 @@ ...@@ -10658,7 +10383,6 @@
"integrity": "sha512-BxAf1fVL7w+JLRQhWl2pzGeSiGqbWumV4WNvc9Rhp6tiCtm4oHnyPBSEtMGZwrQgudFQ+otqzWoPB7x+hxoWsw==", "integrity": "sha512-BxAf1fVL7w+JLRQhWl2pzGeSiGqbWumV4WNvc9Rhp6tiCtm4oHnyPBSEtMGZwrQgudFQ+otqzWoPB7x+hxoWsw==",
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@eslint/eslintrc": "^2.0.0", "@eslint/eslintrc": "^2.0.0",
"@eslint/js": "8.35.0", "@eslint/js": "8.35.0",
...@@ -11806,12 +11530,6 @@ ...@@ -11806,12 +11530,6 @@
"node": ">= 6" "node": ">= 6"
} }
}, },
"node_modules/glob-to-regexp": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
"integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
"license": "BSD-2-Clause"
},
"node_modules/global": { "node_modules/global": {
"version": "4.4.0", "version": "4.4.0",
"resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz",
...@@ -12121,7 +11839,6 @@ ...@@ -12121,7 +11839,6 @@
"resolved": "https://registry.npmjs.org/hono/-/hono-4.12.18.tgz", "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.18.tgz",
"integrity": "sha512-RWzP96k/yv0PQfyXnWjs6zot20TqfpfsNXhOnev8d1InAxubW93L11/oNUc3tQqn2G0bSdAOBpX+2uDFHV7kdQ==", "integrity": "sha512-RWzP96k/yv0PQfyXnWjs6zot20TqfpfsNXhOnev8d1InAxubW93L11/oNUc3tQqn2G0bSdAOBpX+2uDFHV7kdQ==",
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=16.9.0" "node": ">=16.9.0"
} }
...@@ -12917,6 +12634,12 @@ ...@@ -12917,6 +12634,12 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/is-mobile": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/is-mobile/-/is-mobile-5.0.0.tgz",
"integrity": "sha512-Tz/yndySvLAEXh+Uk8liFCxOwVH6YutuR74utvOcu7I9Di+DwM0mtdPVZNaVvvBUM2OXxne/NhOs1zAO7riusQ==",
"license": "MIT"
},
"node_modules/is-negative-zero": { "node_modules/is-negative-zero": {
"version": "2.0.3", "version": "2.0.3",
"resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz",
...@@ -13619,7 +13342,6 @@ ...@@ -13619,7 +13342,6 @@
"resolved": "https://registry.npmjs.org/less/-/less-4.1.3.tgz", "resolved": "https://registry.npmjs.org/less/-/less-4.1.3.tgz",
"integrity": "sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA==", "integrity": "sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA==",
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true,
"dependencies": { "dependencies": {
"copy-anything": "^2.0.1", "copy-anything": "^2.0.1",
"parse-node-version": "^1.0.1", "parse-node-version": "^1.0.1",
...@@ -13646,7 +13368,6 @@ ...@@ -13646,7 +13368,6 @@
"resolved": "https://registry.npmjs.org/less-loader/-/less-loader-11.1.0.tgz", "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-11.1.0.tgz",
"integrity": "sha512-C+uDBV7kS7W5fJlUjq5mPBeBVhYpTIm5gB09APT9o3n/ILeaXVsiSFTbZpTJCJwQ/Crczfn3DmfQFwxYusWFug==", "integrity": "sha512-C+uDBV7kS7W5fJlUjq5mPBeBVhYpTIm5gB09APT9o3n/ILeaXVsiSFTbZpTJCJwQ/Crczfn3DmfQFwxYusWFug==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"klona": "^2.0.4" "klona": "^2.0.4"
}, },
...@@ -15371,7 +15092,6 @@ ...@@ -15371,7 +15092,6 @@
} }
], ],
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"nanoid": "^3.3.11", "nanoid": "^3.3.11",
"picocolors": "^1.1.1", "picocolors": "^1.1.1",
...@@ -16107,7 +15827,6 @@ ...@@ -16107,7 +15827,6 @@
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
"integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"cssesc": "^3.0.0", "cssesc": "^3.0.0",
"util-deprecate": "^1.0.2" "util-deprecate": "^1.0.2"
...@@ -16121,7 +15840,6 @@ ...@@ -16121,7 +15840,6 @@
"resolved": "https://registry.npmjs.org/postcss-syntax/-/postcss-syntax-0.36.2.tgz", "resolved": "https://registry.npmjs.org/postcss-syntax/-/postcss-syntax-0.36.2.tgz",
"integrity": "sha512-nBRg/i7E3SOHWxF3PpF5WnJM/jQ1YpY9000OaVXlAQj6Zp/kIqJxEDWIZ67tAd7NLuk7zqN4yqe9nc0oNAOs1w==", "integrity": "sha512-nBRg/i7E3SOHWxF3PpF5WnJM/jQ1YpY9000OaVXlAQj6Zp/kIqJxEDWIZ67tAd7NLuk7zqN4yqe9nc0oNAOs1w==",
"license": "MIT", "license": "MIT",
"peer": true,
"peerDependencies": { "peerDependencies": {
"postcss": ">=5.0.0" "postcss": ">=5.0.0"
} }
...@@ -16141,22 +15859,6 @@ ...@@ -16141,22 +15859,6 @@
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/prettier": {
"version": "3.8.3",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz",
"integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==",
"license": "MIT",
"peer": true,
"bin": {
"prettier": "bin/prettier.cjs"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/prettier-plugin-organize-imports": { "node_modules/prettier-plugin-organize-imports": {
"version": "3.2.4", "version": "3.2.4",
"resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-3.2.4.tgz", "resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-3.2.4.tgz",
...@@ -16641,7 +16343,6 @@ ...@@ -16641,7 +16343,6 @@
"resolved": "https://registry.npmjs.org/rc-field-form/-/rc-field-form-1.38.2.tgz", "resolved": "https://registry.npmjs.org/rc-field-form/-/rc-field-form-1.38.2.tgz",
"integrity": "sha512-O83Oi1qPyEv31Sg+Jwvsj6pXc8uQI2BtIAkURr5lvEYHVggXJhdU/nynK8wY1gbw0qR48k731sN5ON4egRCROA==", "integrity": "sha512-O83Oi1qPyEv31Sg+Jwvsj6pXc8uQI2BtIAkURr5lvEYHVggXJhdU/nynK8wY1gbw0qR48k731sN5ON4egRCROA==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@babel/runtime": "^7.18.0", "@babel/runtime": "^7.18.0",
"async-validator": "^4.1.0", "async-validator": "^4.1.0",
...@@ -17151,14 +16852,10 @@ ...@@ -17151,14 +16852,10 @@
} }
}, },
"node_modules/react": { "node_modules/react": {
"version": "18.3.1", "version": "19.2.8",
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz",
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": {
"loose-envify": "^1.1.0"
},
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
} }
...@@ -17184,6 +16881,72 @@ ...@@ -17184,6 +16881,72 @@
"react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1"
} }
}, },
"node_modules/react-aria-components": {
"version": "1.20.0",
"resolved": "https://registry.npmjs.org/react-aria-components/-/react-aria-components-1.20.0.tgz",
"integrity": "sha512-BMbpIgoV9aELeBrB0Y120NgoigHb5OdcJwc+4e7uSnbTbamea6lo+gqcc4LAxzMaK3Jf+7LI1oCDE6yANsmxIQ==",
"license": "Apache-2.0",
"dependencies": {
"@internationalized/date": "^3.12.3",
"@internationalized/string": "^3.2.10",
"@react-types/shared": "^3.36.1",
"@swc/helpers": "^0.5.0",
"client-only": "^0.0.1",
"react-aria": "3.51.0",
"react-stately": "3.49.0"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1",
"react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1"
}
},
"node_modules/react-aria-components/node_modules/react-aria": {
"version": "3.51.0",
"resolved": "https://registry.npmjs.org/react-aria/-/react-aria-3.51.0.tgz",
"integrity": "sha512-AyWLw0XR38cFPwBu/ErgGaVrc5dupLEKmRlMXTGvFKOtbaGRQ2+yQJkjVhpdHhoRhU4+G+tJDFeHDTS8tK3bfQ==",
"license": "Apache-2.0",
"dependencies": {
"@internationalized/date": "^3.12.3",
"@internationalized/number": "^3.6.7",
"@internationalized/string": "^3.2.10",
"@react-types/shared": "^3.36.1",
"@swc/helpers": "^0.5.0",
"aria-hidden": "^1.2.3",
"clsx": "^2.0.0",
"react-stately": "3.49.0",
"use-sync-external-store": "^1.6.0"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1",
"react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1"
}
},
"node_modules/react-aria-components/node_modules/react-stately": {
"version": "3.49.0",
"resolved": "https://registry.npmjs.org/react-stately/-/react-stately-3.49.0.tgz",
"integrity": "sha512-13iNq2KzBrRAzxRc+n53hgROfIistiYY/sPtIhCw1qUB7/kmo+X1xEU2uiS5zcCIrc55AUPwoHqOIIpKWSwB9A==",
"license": "Apache-2.0",
"dependencies": {
"@internationalized/date": "^3.12.3",
"@internationalized/number": "^3.6.7",
"@internationalized/string": "^3.2.10",
"@react-types/shared": "^3.36.1",
"@swc/helpers": "^0.5.0",
"use-sync-external-store": "^1.6.0"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1"
}
},
"node_modules/react-aria-components/node_modules/use-sync-external-store": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
"integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==",
"license": "MIT",
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
},
"node_modules/react-aria/node_modules/use-sync-external-store": { "node_modules/react-aria/node_modules/use-sync-external-store": {
"version": "1.6.0", "version": "1.6.0",
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
...@@ -17194,17 +16957,15 @@ ...@@ -17194,17 +16957,15 @@
} }
}, },
"node_modules/react-dom": { "node_modules/react-dom": {
"version": "18.3.1", "version": "19.2.8",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.8.tgz",
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"loose-envify": "^1.1.0", "scheduler": "^0.27.0"
"scheduler": "^0.23.2"
}, },
"peerDependencies": { "peerDependencies": {
"react": "^18.3.1" "react": "^19.2.8"
} }
}, },
"node_modules/react-error-overlay": { "node_modules/react-error-overlay": {
...@@ -17263,7 +17024,6 @@ ...@@ -17263,7 +17024,6 @@
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz",
"integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==", "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==",
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
} }
...@@ -17294,59 +17054,6 @@ ...@@ -17294,59 +17054,6 @@
"react-dom": ">=16.8" "react-dom": ">=16.8"
} }
}, },
"node_modules/react-router-redux": {
"version": "5.0.0-alpha.9",
"resolved": "https://registry.npmjs.org/react-router-redux/-/react-router-redux-5.0.0-alpha.9.tgz",
"integrity": "sha512-euSgNIANnRXr4GydIuwA7RZCefrLQzIw5WdXspS8NPYbV+FxrKSS9MKG7U9vb6vsKHONnA4VxrVNWfnMUnUQAw==",
"deprecated": "This project is no longer maintained.",
"license": "MIT",
"dependencies": {
"history": "^4.7.2",
"prop-types": "^15.6.0",
"react-router": "^4.2.0"
},
"peerDependencies": {
"react": ">=15"
}
},
"node_modules/react-router-redux/node_modules/history": {
"version": "4.10.1",
"resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz",
"integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.1.2",
"loose-envify": "^1.2.0",
"resolve-pathname": "^3.0.0",
"tiny-invariant": "^1.0.2",
"tiny-warning": "^1.0.0",
"value-equal": "^1.0.1"
}
},
"node_modules/react-router-redux/node_modules/hoist-non-react-statics": {
"version": "2.5.5",
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz",
"integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw==",
"license": "BSD-3-Clause"
},
"node_modules/react-router-redux/node_modules/react-router": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-4.3.1.tgz",
"integrity": "sha512-yrvL8AogDh2X42Dt9iknk4wF4V8bWREPirFfS9gLU1huk6qK41sg7Z/1S81jjTrGHxa3B8R3J6xIkDAA6CVarg==",
"license": "MIT",
"dependencies": {
"history": "^4.7.2",
"hoist-non-react-statics": "^2.5.0",
"invariant": "^2.2.4",
"loose-envify": "^1.3.1",
"path-to-regexp": "^1.7.0",
"prop-types": "^15.6.1",
"warning": "^4.0.1"
},
"peerDependencies": {
"react": ">=15"
}
},
"node_modules/react-stately": { "node_modules/react-stately": {
"version": "3.46.0", "version": "3.46.0",
"resolved": "https://registry.npmjs.org/react-stately/-/react-stately-3.46.0.tgz", "resolved": "https://registry.npmjs.org/react-stately/-/react-stately-3.46.0.tgz",
...@@ -17585,7 +17292,6 @@ ...@@ -17585,7 +17292,6 @@
"resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz",
"integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@babel/runtime": "^7.9.2" "@babel/runtime": "^7.9.2"
} }
...@@ -17764,12 +17470,6 @@ ...@@ -17764,12 +17470,6 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/resolve-pathname": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz",
"integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==",
"license": "MIT"
},
"node_modules/resolve-pkg-maps": { "node_modules/resolve-pkg-maps": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
...@@ -17784,7 +17484,6 @@ ...@@ -17784,7 +17484,6 @@
"resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz", "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz",
"integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==", "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"adjust-sourcemap-loader": "^4.0.0", "adjust-sourcemap-loader": "^4.0.0",
"convert-source-map": "^1.7.0", "convert-source-map": "^1.7.0",
...@@ -17926,7 +17625,6 @@ ...@@ -17926,7 +17625,6 @@
"resolved": "https://registry.npmjs.org/rollup/-/rollup-3.30.0.tgz", "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.30.0.tgz",
"integrity": "sha512-kQvGasUgN+AlWGliFn2POSajRQEsULVYFGTvOZmK06d7vCD+YhZztt70kGk3qaeAXeWYL5eO7zx+rAubBc55eA==", "integrity": "sha512-kQvGasUgN+AlWGliFn2POSajRQEsULVYFGTvOZmK06d7vCD+YhZztt70kGk3qaeAXeWYL5eO7zx+rAubBc55eA==",
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"rollup": "dist/bin/rollup" "rollup": "dist/bin/rollup"
}, },
...@@ -18094,7 +17792,6 @@ ...@@ -18094,7 +17792,6 @@
"resolved": "https://registry.npmjs.org/sass/-/sass-1.54.0.tgz", "resolved": "https://registry.npmjs.org/sass/-/sass-1.54.0.tgz",
"integrity": "sha512-C4zp79GCXZfK0yoHZg+GxF818/aclhp9F48XBu/+bm9vXEVAYov9iU3FBVRMq3Hx3OA4jfKL+p2K9180mEh0xQ==", "integrity": "sha512-C4zp79GCXZfK0yoHZg+GxF818/aclhp9F48XBu/+bm9vXEVAYov9iU3FBVRMq3Hx3OA4jfKL+p2K9180mEh0xQ==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"chokidar": ">=3.0.0 <4.0.0", "chokidar": ">=3.0.0 <4.0.0",
"immutable": "^4.0.0", "immutable": "^4.0.0",
...@@ -18112,7 +17809,6 @@ ...@@ -18112,7 +17809,6 @@
"resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.2.0.tgz", "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.2.0.tgz",
"integrity": "sha512-JWEp48djQA4nbZxmgC02/Wh0eroSUutulROUusYJO9P9zltRbNN80JCBHqRGzjd4cmZCa/r88xgfkjGD0TXsHg==", "integrity": "sha512-JWEp48djQA4nbZxmgC02/Wh0eroSUutulROUusYJO9P9zltRbNN80JCBHqRGzjd4cmZCa/r88xgfkjGD0TXsHg==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"klona": "^2.0.4", "klona": "^2.0.4",
"neo-async": "^2.6.2" "neo-async": "^2.6.2"
...@@ -18156,13 +17852,10 @@ ...@@ -18156,13 +17852,10 @@
} }
}, },
"node_modules/scheduler": { "node_modules/scheduler": {
"version": "0.23.2", "version": "0.27.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
"integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
"license": "MIT", "license": "MIT"
"dependencies": {
"loose-envify": "^1.1.0"
}
}, },
"node_modules/schema-utils": { "node_modules/schema-utils": {
"version": "3.3.0", "version": "3.3.0",
...@@ -19051,30 +18744,6 @@ ...@@ -19051,30 +18744,6 @@
"integrity": "sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==", "integrity": "sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==",
"license": "ISC" "license": "ISC"
}, },
"node_modules/styled-jsx": {
"version": "5.1.7",
"resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.7.tgz",
"integrity": "sha512-HPLmEIYprxCeWDMLYiaaAhsV3yGfIlCqzuVOybE6fjF3SUJmH67nCoMDO+nAvHNHo46OfvpCNu4Rcue82dMNFg==",
"license": "MIT",
"peer": true,
"dependencies": {
"client-only": "0.0.1"
},
"engines": {
"node": ">= 12.0.0"
},
"peerDependencies": {
"react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0"
},
"peerDependenciesMeta": {
"@babel/core": {
"optional": true
},
"babel-plugin-macros": {
"optional": true
}
}
},
"node_modules/stylelint": { "node_modules/stylelint": {
"version": "14.8.2", "version": "14.8.2",
"resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.8.2.tgz", "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.8.2.tgz",
...@@ -19324,15 +18993,6 @@ ...@@ -19324,15 +18993,6 @@
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
} }
}, },
"node_modules/symbol-observable": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
"integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/synckit": { "node_modules/synckit": {
"version": "0.8.5", "version": "0.8.5",
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz", "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz",
...@@ -19399,6 +19059,38 @@ ...@@ -19399,6 +19059,38 @@
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/tailwind-merge": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.6.0.tgz",
"integrity": "sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/dcastil"
}
},
"node_modules/tailwind-variants": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/tailwind-variants/-/tailwind-variants-3.3.1.tgz",
"integrity": "sha512-4pAvwUtM4HKBiRZftncAbpn6V9Hhwoa5Fl7O2u5zbp7Z5Cvu+/o/6+176WY3WCEES209543quG8zFIcXCsc5Jw==",
"license": "MIT",
"engines": {
"node": ">=16.9.x",
"pnpm": ">=7.x"
},
"peerDependencies": {
"tailwind-merge": ">=3.0.0",
"tailwindcss": "*"
},
"peerDependenciesMeta": {
"tailwind-merge": {
"optional": true
},
"tailwindcss": {
"optional": true
}
}
},
"node_modules/tailwindcss": { "node_modules/tailwindcss": {
"version": "4.2.4", "version": "4.2.4",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.4.tgz", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.4.tgz",
...@@ -19423,7 +19115,6 @@ ...@@ -19423,7 +19115,6 @@
"resolved": "https://registry.npmjs.org/terser/-/terser-5.47.1.tgz", "resolved": "https://registry.npmjs.org/terser/-/terser-5.47.1.tgz",
"integrity": "sha512-tPbLXTI6ohPASb/1YViL428oEHu6/qv1OxqYnfaonVCFHqx4+wCd95pHrQWsL5X4pl90CTyW9piSAsS2L0VoMw==", "integrity": "sha512-tPbLXTI6ohPASb/1YViL428oEHu6/qv1OxqYnfaonVCFHqx4+wCd95pHrQWsL5X4pl90CTyW9piSAsS2L0VoMw==",
"license": "BSD-2-Clause", "license": "BSD-2-Clause",
"peer": true,
"dependencies": { "dependencies": {
"@jridgewell/source-map": "^0.3.3", "@jridgewell/source-map": "^0.3.3",
"acorn": "^8.15.0", "acorn": "^8.15.0",
...@@ -19437,122 +19128,6 @@ ...@@ -19437,122 +19128,6 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/terser-webpack-plugin": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.5.0.tgz",
"integrity": "sha512-UYhptBwhWvfIjKd/UuFo6D8uq9xpGLDK+z8EDsj/zWhrTaH34cKEbrkMKfV5YWqGBvAYA3tlzZbs2R+qYrbQJA==",
"license": "MIT",
"dependencies": {
"@jridgewell/trace-mapping": "^0.3.25",
"jest-worker": "^27.4.5",
"schema-utils": "^4.3.0",
"terser": "^5.31.1"
},
"engines": {
"node": ">= 10.13.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
},
"peerDependencies": {
"webpack": "^5.1.0"
},
"peerDependenciesMeta": {
"@swc/core": {
"optional": true
},
"esbuild": {
"optional": true
},
"uglify-js": {
"optional": true
}
}
},
"node_modules/terser-webpack-plugin/node_modules/ajv": {
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz",
"integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==",
"license": "MIT",
"peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/terser-webpack-plugin/node_modules/ajv-keywords": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
"integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.3"
},
"peerDependencies": {
"ajv": "^8.8.2"
}
},
"node_modules/terser-webpack-plugin/node_modules/jest-worker": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
"integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
"license": "MIT",
"dependencies": {
"@types/node": "*",
"merge-stream": "^2.0.0",
"supports-color": "^8.0.0"
},
"engines": {
"node": ">= 10.13.0"
}
},
"node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"license": "MIT"
},
"node_modules/terser-webpack-plugin/node_modules/schema-utils": {
"version": "4.3.3",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz",
"integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==",
"license": "MIT",
"dependencies": {
"@types/json-schema": "^7.0.9",
"ajv": "^8.9.0",
"ajv-formats": "^2.1.1",
"ajv-keywords": "^5.1.0"
},
"engines": {
"node": ">= 10.13.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
}
},
"node_modules/terser-webpack-plugin/node_modules/supports-color": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
"license": "MIT",
"dependencies": {
"has-flag": "^4.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
"node_modules/terser/node_modules/commander": { "node_modules/terser/node_modules/commander": {
"version": "2.20.3", "version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
...@@ -19609,18 +19184,6 @@ ...@@ -19609,18 +19184,6 @@
"node": ">=0.6.0" "node": ">=0.6.0"
} }
}, },
"node_modules/tiny-invariant": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz",
"integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==",
"license": "MIT"
},
"node_modules/tiny-warning": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
"integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==",
"license": "MIT"
},
"node_modules/tinycolor2": { "node_modules/tinycolor2": {
"version": "1.6.0", "version": "1.6.0",
"resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz",
...@@ -19881,8 +19444,8 @@ ...@@ -19881,8 +19444,8 @@
"version": "5.9.3", "version": "5.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true,
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
"tsserver": "bin/tsserver" "tsserver": "bin/tsserver"
...@@ -19922,7 +19485,6 @@ ...@@ -19922,7 +19485,6 @@
"resolved": "https://registry.npmjs.org/umi-request/-/umi-request-1.4.0.tgz", "resolved": "https://registry.npmjs.org/umi-request/-/umi-request-1.4.0.tgz",
"integrity": "sha512-OknwtQZddZHi0Ggi+Vr/olJ7HNMx4AzlywyK0W3NZBT7B0stjeZ9lcztA85dBgdAj3KVk8uPJPZSnGaDjELhrA==", "integrity": "sha512-OknwtQZddZHi0Ggi+Vr/olJ7HNMx4AzlywyK0W3NZBT7B0stjeZ9lcztA85dBgdAj3KVk8uPJPZSnGaDjELhrA==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"isomorphic-fetch": "^2.2.1", "isomorphic-fetch": "^2.2.1",
"qs": "^6.9.1" "qs": "^6.9.1"
...@@ -20183,12 +19745,6 @@ ...@@ -20183,12 +19745,6 @@
} }
} }
}, },
"node_modules/value-equal": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz",
"integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==",
"license": "MIT"
},
"node_modules/vary": { "node_modules/vary": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
...@@ -20203,7 +19759,6 @@ ...@@ -20203,7 +19759,6 @@
"resolved": "https://registry.npmjs.org/vite/-/vite-4.5.2.tgz", "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.2.tgz",
"integrity": "sha512-tBCZBNSBbHQkaGyhGCDUGqeo2ph8Fstyp6FMSvTtsXeZSPpSMGlviAOav2hxVTqFcx8Hj/twtWKsMJXNY0xI8w==", "integrity": "sha512-tBCZBNSBbHQkaGyhGCDUGqeo2ph8Fstyp6FMSvTtsXeZSPpSMGlviAOav2hxVTqFcx8Hj/twtWKsMJXNY0xI8w==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"esbuild": "^0.18.10", "esbuild": "^0.18.10",
"postcss": "^8.4.27", "postcss": "^8.4.27",
...@@ -20667,19 +20222,6 @@ ...@@ -20667,19 +20222,6 @@
"loose-envify": "^1.0.0" "loose-envify": "^1.0.0"
} }
}, },
"node_modules/watchpack": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz",
"integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==",
"license": "MIT",
"dependencies": {
"glob-to-regexp": "^0.4.1",
"graceful-fs": "^4.1.2"
},
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/wbuf": { "node_modules/wbuf": {
"version": "1.7.3", "version": "1.7.3",
"resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz",
...@@ -20698,54 +20240,6 @@ ...@@ -20698,54 +20240,6 @@
"node": ">= 8" "node": ">= 8"
} }
}, },
"node_modules/webpack": {
"version": "5.106.2",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.106.2.tgz",
"integrity": "sha512-wGN3qcrBQIFmQ/c0AiOAQBvrZ5lmY8vbbMv4Mxfgzqd/B6+9pXtLo73WuS1dSGXM5QYY3hZnIbvx+K1xxe6FyA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@types/eslint-scope": "^3.7.7",
"@types/estree": "^1.0.8",
"@types/json-schema": "^7.0.15",
"@webassemblyjs/ast": "^1.14.1",
"@webassemblyjs/wasm-edit": "^1.14.1",
"@webassemblyjs/wasm-parser": "^1.14.1",
"acorn": "^8.16.0",
"acorn-import-phases": "^1.0.3",
"browserslist": "^4.28.1",
"chrome-trace-event": "^1.0.2",
"enhanced-resolve": "^5.20.0",
"es-module-lexer": "^2.0.0",
"eslint-scope": "5.1.1",
"events": "^3.2.0",
"glob-to-regexp": "^0.4.1",
"graceful-fs": "^4.2.11",
"loader-runner": "^4.3.1",
"mime-db": "^1.54.0",
"neo-async": "^2.6.2",
"schema-utils": "^4.3.3",
"tapable": "^2.3.0",
"terser-webpack-plugin": "^5.3.17",
"watchpack": "^2.5.1",
"webpack-sources": "^3.3.4"
},
"bin": {
"webpack": "bin/webpack.js"
},
"engines": {
"node": ">=10.13.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
},
"peerDependenciesMeta": {
"webpack-cli": {
"optional": true
}
}
},
"node_modules/webpack-5-chain": { "node_modules/webpack-5-chain": {
"version": "8.0.1", "version": "8.0.1",
"resolved": "https://registry.npmjs.org/webpack-5-chain/-/webpack-5-chain-8.0.1.tgz", "resolved": "https://registry.npmjs.org/webpack-5-chain/-/webpack-5-chain-8.0.1.tgz",
...@@ -20768,78 +20262,6 @@ ...@@ -20768,78 +20262,6 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/webpack-sources": {
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.4.1.tgz",
"integrity": "sha512-eACpxRN02yaawnt+uUNIF7Qje6A9zArxBbcAJjK1PK3S9Ycg5jIuJ8pW4q8EMnwNZCEGltcjkRx1QzOxOkKD8A==",
"license": "MIT",
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/webpack/node_modules/ajv": {
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz",
"integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==",
"license": "MIT",
"peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/webpack/node_modules/ajv-keywords": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
"integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.3"
},
"peerDependencies": {
"ajv": "^8.8.2"
}
},
"node_modules/webpack/node_modules/json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"license": "MIT"
},
"node_modules/webpack/node_modules/mime-db": {
"version": "1.54.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
"integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/webpack/node_modules/schema-utils": {
"version": "4.3.3",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz",
"integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==",
"license": "MIT",
"dependencies": {
"@types/json-schema": "^7.0.9",
"ajv": "^8.9.0",
"ajv-formats": "^2.1.1",
"ajv-keywords": "^5.1.0"
},
"engines": {
"node": ">= 10.13.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
}
},
"node_modules/whatwg-fetch": { "node_modules/whatwg-fetch": {
"version": "3.6.20", "version": "3.6.20",
"resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz",
...@@ -21155,7 +20577,6 @@ ...@@ -21155,7 +20577,6 @@
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
"license": "MIT", "license": "MIT",
"peer": true,
"funding": { "funding": {
"url": "https://github.com/sponsors/colinhacks" "url": "https://github.com/sponsors/colinhacks"
} }
......
...@@ -8,8 +8,12 @@ ...@@ -8,8 +8,12 @@
"start": "npm run dev" "start": "npm run dev"
}, },
"dependencies": { "dependencies": {
"@ant-design/icons": "^6.3.2",
"@headlessui/react": "^2.2.10", "@headlessui/react": "^2.2.10",
"@heroicons/react": "^2.2.0", "@heroicons/react": "^2.2.0",
"@heroui-pro/react": "file:../project_manager_new/node_modules/@heroui-pro/react",
"@heroui/react": "file:../project_manager_new/node_modules/@heroui/react",
"@heroui/styles": "file:../project_manager_new/node_modules/@heroui/styles",
"@tailwindcss/postcss": "^4.2.0", "@tailwindcss/postcss": "^4.2.0",
"@umijs/max": "^4.5.3", "@umijs/max": "^4.5.3",
"clsx": "^2.1.1", "clsx": "^2.1.1",
...@@ -17,16 +21,19 @@ ...@@ -17,16 +21,19 @@
"dayjs": "^1.11.20", "dayjs": "^1.11.20",
"echarts": "^6.0.0", "echarts": "^6.0.0",
"echarts-for-react": "^3.0.6", "echarts-for-react": "^3.0.6",
"react": "^18.3.1", "react": "^19.2.8",
"react-dom": "^18.3.1", "react-aria-components": "^1.20.0",
"react-dom": "^19.2.8",
"tailwind-merge": "^3.6.0",
"tailwind-variants": "^3.3.1",
"tailwindcss": "^4.2.0", "tailwindcss": "^4.2.0",
"umi-request": "^1.4.0", "umi-request": "^1.4.0",
"umi-request-progress": "^1.1.0", "umi-request-progress": "^1.1.0",
"xlsx": "^0.18.5" "xlsx": "^0.18.5"
}, },
"devDependencies": { "devDependencies": {
"@types/react": "^18.0.33", "@types/react": "^19.2.18",
"@types/react-dom": "^18.0.11", "@types/react-dom": "^19.2.4",
"typescript": "^5.0.3" "typescript": "^5.0.3"
} }
} }
import '@/global.less'; import '@/global.less';
import '@/tailwind.css'; import '@/tailwind.css';
import { I18nProvider } from '@heroui/react';
import { createElement } from 'react';
import { defineApp } from 'umi'; import { defineApp } from 'umi';
export async function getInitialState() { export async function getInitialState() {
...@@ -8,4 +10,8 @@ export async function getInitialState() { ...@@ -8,4 +10,8 @@ export async function getInitialState() {
}; };
} }
export default defineApp({}); export default defineApp({
rootContainer(container) {
return createElement(I18nProvider, { locale: 'zh-CN' }, container);
},
});
import AppstoreOutlined from '@ant-design/icons/AppstoreOutlined';
import ArrowLeftOutlined from '@ant-design/icons/ArrowLeftOutlined';
import DatabaseOutlined from '@ant-design/icons/DatabaseOutlined';
import DeleteOutlined from '@ant-design/icons/DeleteOutlined';
import EditOutlined from '@ant-design/icons/EditOutlined';
import ExportOutlined from '@ant-design/icons/ExportOutlined';
import FieldTimeOutlined from '@ant-design/icons/FieldTimeOutlined';
import FileTextOutlined from '@ant-design/icons/FileTextOutlined';
import FilterOutlined from '@ant-design/icons/FilterOutlined';
import FolderOpenOutlined from '@ant-design/icons/FolderOpenOutlined';
import InfoCircleOutlined from '@ant-design/icons/InfoCircleOutlined';
import LogoutOutlined from '@ant-design/icons/LogoutOutlined';
import MoonOutlined from '@ant-design/icons/MoonOutlined';
import OrderedListOutlined from '@ant-design/icons/OrderedListOutlined';
import ReloadOutlined from '@ant-design/icons/ReloadOutlined';
import RightOutlined from '@ant-design/icons/RightOutlined';
import SunOutlined from '@ant-design/icons/SunOutlined';
import TeamOutlined from '@ant-design/icons/TeamOutlined';
import CloseOutlined from '@ant-design/icons/CloseOutlined';
function withSize(Icon) {
return function AppIcon({ size, style, ...props }) {
return <Icon aria-hidden="true" {...props} style={size ? { fontSize: size, ...style } : style} />;
};
}
export const AppGrid = withSize(AppstoreOutlined);
export const ArrowLeft = withSize(ArrowLeftOutlined);
export const DataStore = withSize(DatabaseOutlined);
export const Delete = withSize(DeleteOutlined);
export const Edit = withSize(EditOutlined);
export const External = withSize(ExportOutlined);
export const FieldTime = withSize(FieldTimeOutlined);
export const FileText = withSize(FileTextOutlined);
export const Filter = withSize(FilterOutlined);
export const FolderOpen = withSize(FolderOpenOutlined);
export const Info = withSize(InfoCircleOutlined);
export const LogOut = withSize(LogoutOutlined);
export function SidebarPanel({ size = 16, style, className, ...props }) {
return (
<span
aria-hidden="true"
role="img"
{...props}
className={['anticon', className].filter(Boolean).join(' ')}
style={size ? { fontSize: size, ...style } : style}
>
<svg
aria-hidden="true"
fill="none"
focusable="false"
height="1em"
viewBox="0 0 16 16"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
clipRule="evenodd"
d="M6 3.5h6A1.5 1.5 0 0 1 13.5 5v6a1.5 1.5 0 0 1-1.5 1.5H6zm-1.5 0H4A1.5 1.5 0 0 0 2.5 5v6A1.5 1.5 0 0 0 4 12.5h.5zM1 5a3 3 0 0 1 3-3h8a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H4a3 3 0 0 1-3-3z"
fill="currentColor"
fillRule="evenodd"
/>
</svg>
</span>
);
}
export const Moon = withSize(MoonOutlined);
export const ProcessList = withSize(OrderedListOutlined);
export const Reload = withSize(ReloadOutlined);
export const ChevronRight = withSize(RightOutlined);
export const Sun = withSize(SunOutlined);
export const Team = withSize(TeamOutlined);
export const Close = withSize(CloseOutlined);
import { Sidebar } from '@heroui-pro/react/sidebar';
export default function AppShell({ theme, open, onOpenChange, navigate, sidebar, navbar, children, overlays }) {
return (
<Sidebar.Provider
className={`rc-app-shell ${theme}`}
collapsible="offcanvas"
navigate={navigate}
open={open}
onOpenChange={onOpenChange}
>
{sidebar}
<Sidebar.Main className="rc-app-main">
{navbar}
<div className="app-shell-content-scroll min-h-0 flex-1 overflow-y-auto">
<main className="rc-app-page">{children}</main>
</div>
</Sidebar.Main>
{overlays}
</Sidebar.Provider>
);
}
import { Close } from '@/components/AppIcons';
import { getApplications } from '@/services/DataService'; import { getApplications } from '@/services/DataService';
import * as Headless from '@headlessui/react'; import * as Headless from '@headlessui/react';
import {
ArrowTopRightOnSquareIcon,
ExclamationCircleIcon,
SparklesIcon,
} from '@heroicons/react/24/outline';
import clsx from 'clsx'; import clsx from 'clsx';
import { useEffect, useMemo, useState } from 'react'; import { useEffect, useMemo, useState } from 'react';
function normalizeLabelList(items) { const CURRENT_APP_NAME = 'oa_process_monitor_new';
if (!Array.isArray(items)) { const CURRENT_APP_TITLE = 'OA流程监控';
return [];
}
function normalizeLabelList(items) {
if (!Array.isArray(items)) return [];
return items return items
.map((item) => { .map((item) => (typeof item === 'string' ? item : item?.display_name || item?.title || item?.name || ''))
if (typeof item === 'string') {
return item;
}
return item?.display_name || item?.title || item?.name || '';
})
.filter(Boolean); .filter(Boolean);
} }
function resolveApplicationUrl(application) { function resolveApplicationUrl(application) {
if (application?.name) { return application?.name ? `/${application.name}` : '#';
return `/${application.name}`;
}
return '#';
} }
function normalizeApplication(application, fallback = {}) { function normalizeApplication(application, fallback = {}) {
const name = application?.name || fallback?.name || ''; const name = application?.name || fallback?.name || '';
const sourceTitle = application?.title || fallback?.title || name || '未命名应用';
return { return {
name, name,
title: application?.title || fallback?.title || application?.name || fallback?.name || '未命名应用', title: name === CURRENT_APP_NAME ? CURRENT_APP_TITLE : sourceTitle,
description: description:
application?.description || name === CURRENT_APP_NAME
fallback?.description || ? CURRENT_APP_TITLE
fallback?.title || : application?.description || fallback?.description || fallback?.title || sourceTitle,
application?.title ||
'进入对应应用继续处理业务',
logo: application?.logo || fallback?.logo || null, logo: application?.logo || fallback?.logo || null,
url: resolveApplicationUrl({ name }), url: resolveApplicationUrl({ name }),
access: application?.access || fallback?.access || '', access: application?.access || fallback?.access || '',
status: application?.status || fallback?.status || '',
type: application?.type || fallback?.type || '',
order: application?.order ?? fallback?.order ?? 0, order: application?.order ?? fallback?.order ?? 0,
roles: normalizeLabelList(application?.roles?.length ? application.roles : fallback?.roles), roles: normalizeLabelList(application?.roles?.length ? application.roles : fallback?.roles),
groups: normalizeLabelList(application?.groups?.length ? application.groups : fallback?.groups), groups: normalizeLabelList(application?.groups?.length ? application.groups : fallback?.groups),
}; };
} }
function formatAccessLabel(access) {
if (access === 'public') return '公开';
if (access === 'protected') return '受限';
if (access === 'private') return '私有';
if (access === 'internal') return '内部';
return '';
}
function mergeApplications(fetchedApplications, fallbackApplications) { function mergeApplications(fetchedApplications, fallbackApplications) {
const fallbackMap = new Map( const fallbackMap = new Map(fallbackApplications.map((application) => [application.name, application]));
fallbackApplications.map((application) => [application.name, application]),
);
const normalizedFetched = fetchedApplications
.map((application) =>
normalizeApplication(application, fallbackMap.get(application?.name)),
)
.filter((application) => application.name);
const mergedMap = new Map( const mergedMap = new Map(
normalizedFetched.map((application) => [application.name, application]), fetchedApplications
.map((application) => normalizeApplication(application, fallbackMap.get(application?.name)))
.filter((application) => application.name)
.map((application) => [application.name, application]),
); );
fallbackApplications.forEach((application) => { fallbackApplications.forEach((application) => {
if (!application?.name || mergedMap.has(application.name)) { if (application?.name && !mergedMap.has(application.name)) {
return;
}
mergedMap.set(application.name, normalizeApplication(application, application)); mergedMap.set(application.name, normalizeApplication(application, application));
});
return Array.from(mergedMap.values()).sort((left, right) => {
const orderDifference = Number(left.order || 0) - Number(right.order || 0);
if (orderDifference !== 0) {
return orderDifference;
} }
return left.title.localeCompare(right.title, 'zh-CN');
}); });
}
function buildApplicationSections(applications, applicationGroups) {
if (!Array.isArray(applicationGroups) || applicationGroups.length === 0) {
return [
{
key: 'all',
label: '全部应用',
applications,
},
];
}
const applicationMap = new Map( return [...mergedMap.values()].sort((left, right) => {
applications.map((application) => [application.name, application]), const orderDifference = Number(left.order || 0) - Number(right.order || 0);
); return orderDifference || left.title.localeCompare(right.title, 'zh-CN');
const groupedApplicationNames = new Set();
const sections = applicationGroups
.map((group, index) => {
const groupApplications = Array.isArray(group?.applications)
? group.applications
.map((name) => {
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;
}
const currentPath = window.location.pathname; const currentPath = window.location.pathname;
const applicationRoot = application?.name ? `/${application.name}` : ''; const applicationRoot = application?.name ? `/${application.name}` : '';
return currentPath === applicationRoot || currentPath.startsWith(`${applicationRoot}/`);
}
if (application?.url?.startsWith('http')) { function markCurrentApplication(applications) {
try { if (!Array.isArray(applications) || applications.length === 0) return [];
const url = new URL(application.url); const currentApplication = applications.find(isCurrentApplication);
return url.pathname === currentPath; return applications.map((application) => ({
} catch (error) { ...application,
return false; current: currentApplication?.name === application.name,
} }));
}
return (
application?.url === currentPath ||
(!!applicationRoot &&
(currentPath === applicationRoot || currentPath.startsWith(`${applicationRoot}/`)))
);
} }
function ApplicationCard({ application }) { function ApplicationCard({ application }) {
const current = isCurrentApplication(application); const current = application.current === true;
const target = application?.url?.startsWith('http') ? '_blank' : undefined; const target = application.url.startsWith('http') ? '_blank' : undefined;
const accessLabel = formatAccessLabel(application.access);
const firstRole = application.roles?.[0];
const firstGroup = application.groups?.[0];
return ( return (
<a <a
href={application.url}
target={target}
rel={target ? 'noreferrer' : undefined}
className={clsx( className={clsx(
'group relative min-h-[84px] overflow-hidden rounded-2xl border border-zinc-200/80 bg-[linear-gradient(180deg,rgba(255,255,255,0.98),rgba(248,250,252,0.94))] p-2.5 shadow-[0_10px_24px_rgba(15,23,42,0.06)] transition duration-200 ease-out hover:-translate-y-0.5 hover:border-sky-200 hover:shadow-[0_16px_32px_rgba(14,165,233,0.12)] focus:outline-none focus-visible:ring-2 focus-visible:ring-sky-400/60', 'app-switcher-card group flex min-w-0 items-center gap-3 rounded-xl border border-[var(--rc-border-default)] bg-[var(--rc-bg-subtle)] px-3 py-3 text-left transition hover:bg-[var(--accent-soft)] focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--focus)]',
current && 'border-sky-300 bg-[linear-gradient(180deg,rgba(240,249,255,0.96),rgba(255,255,255,0.98))]',
)} )}
data-current={current ? 'true' : undefined}
href={application.url}
rel={target ? 'noreferrer' : undefined}
target={target}
> >
<div className="absolute inset-x-0 top-0 h-14 bg-[radial-gradient(circle_at_top_right,rgba(14,165,233,0.14),transparent_50%)] opacity-0 transition duration-200 group-hover:opacity-100" />
<div className="relative flex items-start justify-between gap-3">
<div className="flex min-w-0 items-center gap-2.5">
{application.logo ? ( {application.logo ? (
<img <img alt={application.title} className="app-switcher-card__logo" src={application.logo} />
src={application.logo}
alt={application.title}
className="size-9 rounded-xl border border-white/80 bg-white object-cover shadow-sm"
/>
) : ( ) : (
<div className="flex size-9 shrink-0 items-center justify-center rounded-xl bg-[linear-gradient(135deg,#0f766e,#0ea5e9)] text-sm font-semibold text-white shadow-[0_8px_18px_rgba(14,116,144,0.22)]"> <span className="app-switcher-card__initial">{application.title.slice(0, 1)}</span>
{application.title.slice(0, 1)}
</div>
)} )}
<div className="min-w-0"> <span className="min-w-0 flex-1">
<div className="truncate text-sm font-semibold text-slate-950"> <span className="block truncate text-sm font-medium leading-5 text-[var(--rc-text-primary)]">{application.title}</span>
{application.title} <span className="mt-0.5 block truncate text-xs leading-4 text-[var(--rc-text-muted)]">{application.description || application.name || '应用'}</span>
</div>
<div className="mt-0.5 truncate text-[11px] leading-4 text-slate-500">
{application.description}
</div>
</div>
</div>
<div className="flex shrink-0 items-center gap-2">
{current ? (
<span className="rounded-full bg-sky-100 px-2 py-0.5 text-[11px] font-medium text-sky-700">
当前
</span>
) : null}
<span className="rounded-full bg-slate-100 p-1.5 text-slate-500 transition group-hover:bg-sky-50 group-hover:text-sky-600">
<ArrowTopRightOnSquareIcon className="size-3.5" />
</span>
</div>
</div>
{accessLabel || firstRole || firstGroup ? (
<div className="relative mt-2 flex flex-wrap gap-1.5">
{accessLabel ? (
<span className="rounded-full bg-zinc-100 px-2 py-0.5 text-[11px] font-medium text-zinc-700">
{accessLabel}
</span> </span>
) : null} {current ? (
{firstRole ? ( <span className="shrink-0 rounded-full bg-[var(--rc-brand-primary-soft)] px-2 py-0.5 text-xs font-medium text-[var(--rc-brand-primary)]">当前</span>
<span className="rounded-full bg-slate-100 px-2 py-0.5 text-[11px] font-medium text-slate-700">
{firstRole}
</span>
) : null}
{firstGroup ? (
<span className="rounded-full bg-sky-50 px-2 py-0.5 text-[11px] font-medium text-sky-700">
{firstGroup}
</span>
) : null}
</div>
) : null} ) : null}
</a> </a>
); );
...@@ -250,24 +107,17 @@ function ApplicationCard({ application }) { ...@@ -250,24 +107,17 @@ function ApplicationCard({ application }) {
function LoadingSkeleton() { function LoadingSkeleton() {
return ( return (
<div className="grid gap-2.5 sm:grid-cols-2 xl:grid-cols-4 2xl:grid-cols-6"> <div className="grid gap-2 sm:grid-cols-2 lg:grid-cols-3">
{Array.from({ length: 6 }).map((_, index) => ( {Array.from({ length: 6 }).map((_, index) => (
<div <div className="rounded-xl border border-[var(--rc-border-default)] bg-[var(--rc-bg-subtle)] px-3 py-3" key={index}>
key={index}
className="min-h-[84px] rounded-2xl border border-zinc-200 bg-white/90 p-2.5 shadow-[0_10px_24px_rgba(15,23,42,0.05)]"
>
<div className="animate-pulse"> <div className="animate-pulse">
<div className="flex items-start gap-3"> <div className="flex items-center gap-3">
<div className="size-9 rounded-xl bg-zinc-200" /> <div className="size-9 rounded-lg bg-[var(--default-hover)]" />
<div className="min-w-0 flex-1 space-y-2"> <div className="min-w-0 flex-1 space-y-2">
<div className="h-4 w-2/5 rounded-full bg-zinc-200" /> <div className="h-4 w-2/5 rounded-full bg-[var(--default-hover)]" />
<div className="h-3 w-full rounded-full bg-zinc-100" /> <div className="h-3 w-full rounded-full bg-[var(--default-hover)]" />
</div> </div>
</div> </div>
<div className="mt-2 flex gap-1.5">
<div className="h-5 w-12 rounded-full bg-zinc-100" />
<div className="h-5 w-14 rounded-full bg-zinc-100" />
</div>
</div> </div>
</div> </div>
))} ))}
...@@ -275,157 +125,85 @@ function LoadingSkeleton() { ...@@ -275,157 +125,85 @@ function LoadingSkeleton() {
); );
} }
export default function ApplicationSwitcherDialog({ export default function ApplicationSwitcherDialog({ open, onClose, userInfo }) {
open,
onClose,
userInfo,
siteInfo,
}) {
const fallbackApplications = useMemo(() => { const fallbackApplications = useMemo(() => {
if (!Array.isArray(userInfo?.applications)) { const candidates = [
return []; ...(Array.isArray(userInfo?.applications) ? userInfo.applications : []),
} ...(Array.isArray(userInfo?.roles) ? userInfo.roles.flatMap((role) => role?.applications || []) : []),
];
return userInfo.applications return mergeApplications([], candidates.map((application) => normalizeApplication(application)));
.map((application) =>
normalizeApplication(application, {
...application,
description: application?.title,
}),
)
.filter((application) => application.name);
}, [userInfo]); }, [userInfo]);
const [applications, setApplications] = useState(fallbackApplications); const [applications, setApplications] = useState(() => markCurrentApplication(fallbackApplications));
const [status, setStatus] = useState( const [status, setStatus] = useState(fallbackApplications.length ? 'success' : 'idle');
fallbackApplications.length > 0 ? 'success' : 'idle',
);
const [errorMessage, setErrorMessage] = useState(''); const [errorMessage, setErrorMessage] = useState('');
useEffect(() => { useEffect(() => {
if (!open) { if (!open) return undefined;
return;
}
let cancelled = false; let cancelled = false;
setStatus('loading');
(async () => {
setStatus(fallbackApplications.length > 0 ? 'loading' : 'loading');
setErrorMessage(''); setErrorMessage('');
try { getApplications()
const fetchedApplications = await getApplications(); .then((result) => {
if (cancelled) return;
if (cancelled) { setApplications(markCurrentApplication(mergeApplications(Array.isArray(result) ? result : [], fallbackApplications)));
return;
}
const mergedApplications = mergeApplications(
Array.isArray(fetchedApplications) ? fetchedApplications : [],
fallbackApplications,
);
setApplications(mergedApplications);
setStatus('success'); setStatus('success');
} catch (error) { })
if (cancelled) { .catch((error) => {
return; if (cancelled) return;
} setApplications(markCurrentApplication(fallbackApplications));
setStatus(fallbackApplications.length ? 'success' : 'error');
setApplications(fallbackApplications);
setStatus(fallbackApplications.length > 0 ? 'success' : 'error');
setErrorMessage(error?.message || '加载应用列表失败'); setErrorMessage(error?.message || '加载应用列表失败');
} });
})();
return () => { return () => { cancelled = true; };
cancelled = true;
};
}, [open, fallbackApplications]); }, [open, fallbackApplications]);
const sections = useMemo(() => {
return buildApplicationSections(applications, siteInfo?.application_groups || []);
}, [applications, siteInfo]);
return ( return (
<Headless.Dialog open={open} onClose={onClose} className="relative z-[200]"> <Headless.Dialog open={open} onClose={onClose} className="relative z-[180]">
<div className="fixed inset-0 bg-slate-950/35 backdrop-blur-sm" aria-hidden="true" /> <Headless.DialogBackdrop
transition
<div className="fixed inset-0 overflow-y-auto px-3 py-6 sm:px-6 sm:py-10"> className="fixed inset-0 bg-[rgba(15,23,42,0.42)] backdrop-blur-sm transition duration-200 ease-out data-closed:opacity-0"
<div className="mx-auto flex min-h-full w-full max-w-6xl items-center justify-center"> />
<Headless.DialogPanel className="w-full overflow-hidden rounded-[30px] border border-white/70 bg-[linear-gradient(180deg,rgba(255,255,255,0.96),rgba(248,250,252,0.94))] shadow-[0_28px_80px_rgba(15,23,42,0.18)] ring-1 ring-slate-950/5"> <div className="fixed inset-0 overflow-y-auto p-4">
<div className="border-b border-zinc-200/80 bg-[linear-gradient(135deg,rgba(14,165,233,0.08),rgba(255,255,255,0.6))] px-5 py-4 sm:px-7 sm:py-5"> <div className="flex min-h-full items-center justify-center">
<div className="flex flex-wrap items-start justify-between gap-4"> <Headless.DialogPanel
transition
className="app-switcher-dialog flex max-h-[min(42rem,calc(100dvh-2rem))] w-full max-w-[46rem] flex-col overflow-hidden rounded-2xl border border-[var(--rc-border-default)] bg-[var(--rc-bg-surface)] shadow-[var(--rc-shadow-overlay)] transition duration-200 ease-out data-closed:translate-y-2 data-closed:scale-[0.98] data-closed:opacity-0"
>
<div className="flex shrink-0 items-start justify-between gap-4 border-b border-[var(--rc-border-default)] px-5 py-4">
<div className="min-w-0"> <div className="min-w-0">
<div className="inline-flex items-center gap-2 rounded-full bg-sky-50 px-3 py-1 text-xs font-medium text-sky-700"> <Headless.DialogTitle className="text-base font-semibold leading-6 text-[var(--rc-text-primary)]">应用切换</Headless.DialogTitle>
<SparklesIcon className="size-4" /> <p className="mt-1 text-sm leading-5 text-[var(--rc-text-muted)]">选择你可访问的应用</p>
应用切换
</div>
<Headless.DialogTitle className="mt-3 text-xl font-semibold tracking-tight text-slate-950 sm:text-2xl">
继续前往其他工作区
</Headless.DialogTitle>
<p className="mt-2 max-w-2xl text-sm leading-6 text-slate-500">
当前账号可访问的应用都整理在这里,支持从流程监控快速跳转,不需要返回门户重新进入。
</p>
</div> </div>
<button <button
type="button" type="button"
onClick={onClose} onClick={onClose}
className="rounded-full border border-zinc-200 bg-white px-4 py-2 text-sm font-medium text-slate-600 transition hover:border-sky-200 hover:text-sky-700" aria-label="关闭应用切换"
className="inline-grid size-6 shrink-0 place-items-center rounded-full bg-[var(--default)] p-1 text-[var(--rc-text-secondary)] transition hover:bg-[var(--default-hover)] hover:text-[var(--rc-text-primary)] focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--focus)] [&_.anticon]:grid [&_.anticon]:size-4 [&_.anticon]:place-items-center [&_.anticon]:leading-none [&_.anticon>svg]:block [&_.anticon>svg]:size-4 [&_svg]:m-0"
> >
关闭 <Close size={16} />
</button> </button>
</div> </div>
</div> <div className="min-h-0 flex-1 overflow-y-auto px-5 py-4 [scrollbar-gutter:stable]">
{status === 'error' && errorMessage ? (
<div className="max-h-[75vh] overflow-y-auto px-5 py-5 sm:px-7 sm:py-6"> <div className="mb-4 rounded-xl border border-[var(--rc-color-warning-border)] bg-[var(--rc-color-warning-soft)] px-3 py-2 text-sm text-[var(--rc-text-secondary)]">{errorMessage}</div>
{status === 'loading' ? <LoadingSkeleton /> : null}
{status === 'error' ? (
<div className="rounded-2xl border border-amber-200 bg-amber-50/80 p-4 text-sm text-amber-800">
<div className="flex items-start gap-3">
<ExclamationCircleIcon className="mt-0.5 size-5 shrink-0" />
<div>
<div className="font-medium">应用列表暂时加载失败</div>
<div className="mt-1">{errorMessage || '请稍后再试'}</div>
</div>
</div>
</div>
) : null}
{status !== 'loading' && sections.every((section) => section.applications.length === 0) ? (
<div className="rounded-3xl border border-dashed border-zinc-300 bg-white/90 px-6 py-14 text-center">
<div className="mx-auto flex size-14 items-center justify-center rounded-2xl bg-slate-100 text-slate-500">
<SparklesIcon className="size-7" />
</div>
<div className="mt-4 text-lg font-semibold text-slate-900">
暂无可切换的应用
</div>
<div className="mt-2 text-sm text-slate-500">
当前账号还没有配置其它工作区入口。
</div>
</div>
) : null} ) : null}
{status === 'loading' && applications.length === 0 ? (
<div className="space-y-6"> <LoadingSkeleton />
{sections.map((section) => ( ) : applications.length > 0 ? (
<section key={section.key}> <div className="grid gap-2 sm:grid-cols-2 lg:grid-cols-3">
<div className="mb-3 flex items-center justify-between gap-3"> {applications.map((application) => (
<h3 className="text-sm font-semibold tracking-wide text-slate-900"> <ApplicationCard application={application} key={application.name} />
{section.label}
</h3>
<div className="text-xs text-slate-400">
{section.applications.length} 个应用
</div>
</div>
<div className="grid gap-2.5 sm:grid-cols-2 xl:grid-cols-4 2xl:grid-cols-6">
{section.applications.map((application) => (
<ApplicationCard key={application.name} application={application} />
))} ))}
</div> </div>
</section> ) : (
))} <div className="flex min-h-48 flex-col items-center justify-center rounded-xl border border-dashed border-[var(--rc-border-default)] bg-[var(--rc-bg-subtle)] px-6 text-center">
<div className="text-base font-semibold text-[var(--rc-text-primary)]">暂无可切换应用</div>
<p className="mt-2 max-w-md text-sm leading-6 text-[var(--rc-text-muted)]">当前账号还没有分配其它应用权限,后续分配后这里会自动展示。</p>
</div> </div>
)}
</div> </div>
</Headless.DialogPanel> </Headless.DialogPanel>
</div> </div>
......
import { Moon, SidebarPanel, Sun } from '@/components/AppIcons';
import { Navbar } from '@heroui-pro/react/navbar';
import { Sidebar, useSidebar } from '@heroui-pro/react/sidebar';
import { Button, Tooltip } from '@heroui/react';
export default function DashboardNavbar({ theme, title, onThemeChange }) {
const { isMobile, isOpen } = useSidebar();
const isDark = theme === 'dark';
const themeLabel = isDark ? '切换至浅色模式' : '切换至深色模式';
return (
<Navbar className="rc-navbar" maxWidth="full">
<Navbar.Header>
<Sidebar.Trigger aria-label={isMobile ? '打开导航' : isOpen ? '收起侧栏' : '展开侧栏'}>
<SidebarPanel size={16} />
</Sidebar.Trigger>
<h1 className="rc-navbar-title">{title}</h1>
<Navbar.Spacer />
<Tooltip delay={0}>
<Button
isIconOnly
aria-label={themeLabel}
aria-pressed={isDark}
className="rc-navbar-icon-button"
size="sm"
variant="ghost"
onPress={() => onThemeChange(isDark ? 'light' : 'dark')}
>
{isDark ? <Sun size={16} /> : <Moon size={16} />}
</Button>
<Tooltip.Content>{themeLabel}</Tooltip.Content>
</Tooltip>
</Navbar.Header>
</Navbar>
);
}
import xyLogoRed from '@/assets/xy-logo-red.png';
import xyLogoWhite from '@/assets/xy-logo-white.png';
import { AppGrid, LogOut } from '@/components/AppIcons';
import { Sidebar } from '@heroui-pro/react/sidebar';
import { Avatar, Button, Dropdown, Label, Tooltip } from '@heroui/react';
function SidebarUserMenu({ userInfo }) {
const displayName = userInfo?.display_name || userInfo?.name || userInfo?.username || '当前用户';
const username = userInfo?.username || userInfo?.email || '已登录';
return (
<Dropdown>
<Button fullWidth className="rc-sidebar-user-trigger" size="sm" variant="ghost">
<Avatar className="rc-sidebar-avatar">
{userInfo?.avatar ? <Avatar.Image alt={displayName} src={userInfo.avatar} /> : null}
<Avatar.Fallback>{String(displayName).trim().slice(0, 1).toUpperCase() || 'U'}</Avatar.Fallback>
</Avatar>
<span className="rc-sidebar-user-copy" data-sidebar="label">
<strong>{displayName}</strong>
<small>{username}</small>
</span>
</Button>
<Dropdown.Popover placement="top start">
<Dropdown.Menu aria-label="用户菜单" onAction={(key) => key === 'logout' && userInfo?.logout?.()}>
<Dropdown.Item id="logout" textValue="退出登录" variant="danger">
<div className="flex w-full items-center justify-between gap-3">
<Label>退出登录</Label>
<LogOut size={14} />
</div>
</Dropdown.Item>
</Dropdown.Menu>
</Dropdown.Popover>
</Dropdown>
);
}
function SidebarContents({ appName, menuGroups, pathname, userInfo, onOpenApplications }) {
return (
<>
<Sidebar.Header>
<div className="rc-sidebar-brand">
<div className="rc-sidebar-brand-mark">
<img src={xyLogoRed} alt="鑫元" className="rc-sidebar-logo rc-sidebar-logo-light" />
<img src={xyLogoWhite} alt="鑫元" className="rc-sidebar-logo rc-sidebar-logo-dark" />
</div>
<div className="rc-sidebar-brand-main" data-sidebar="label"><span className="rc-sidebar-title">{appName}</span></div>
<div className="rc-sidebar-app-switcher" data-sidebar="label">
<Tooltip delay={0}>
<Button isIconOnly aria-label="切换应用" className="rc-sidebar-app-trigger" size="sm" variant="ghost" onPress={onOpenApplications}>
<AppGrid size={16} />
</Button>
<Tooltip.Content>切换应用</Tooltip.Content>
</Tooltip>
</div>
</div>
</Sidebar.Header>
<Sidebar.Content>
{menuGroups.map((group) => (
<Sidebar.Group key={group.title}>
<Sidebar.GroupLabel>{group.title}</Sidebar.GroupLabel>
<Sidebar.Menu aria-label={group.title}>
{group.items.map((item) => (
<Sidebar.MenuItem href={item.path} isCurrent={pathname.startsWith(item.path)} key={item.path} textValue={item.name} tooltip={item.name}>
<Sidebar.MenuIcon><item.icon size={16} /></Sidebar.MenuIcon>
<Sidebar.MenuLabel>{item.name}</Sidebar.MenuLabel>
</Sidebar.MenuItem>
))}
</Sidebar.Menu>
</Sidebar.Group>
))}
</Sidebar.Content>
<Sidebar.Footer><SidebarUserMenu userInfo={userInfo} /></Sidebar.Footer>
</>
);
}
export default function DashboardSidebar(props) {
return (
<>
<Sidebar className="rc-sidebar"><SidebarContents {...props} /></Sidebar>
<Sidebar.Mobile className="rc-mobile-sidebar" aria-label={`${props.appName}导航`}><SidebarContents {...props} /></Sidebar.Mobile>
</>
);
}
import { ArrowLeft } from '@/components/AppIcons';
import { Breadcrumbs, Button, Tooltip } from '@heroui/react';
import { useNavigate } from 'umi';
export default function DetailNavigation({ backHref, backLabel, items, currentLabel }) {
const navigate = useNavigate();
return (
<nav className="rc-detail-navigation" aria-label="详情页导航">
<Tooltip delay={400}>
<Tooltip.Trigger>
<Button
isIconOnly
aria-label={backLabel}
className="rc-detail-navigation__back"
size="sm"
variant="outline"
onPress={() => navigate(backHref)}
>
<ArrowLeft size={16} />
</Button>
</Tooltip.Trigger>
<Tooltip.Content placement="bottom">{backLabel}</Tooltip.Content>
</Tooltip>
<Breadcrumbs className="rc-detail-navigation__breadcrumbs" separator={<span aria-hidden="true">/</span>}>
{items.map((item) => (
<Breadcrumbs.Item href={item.href} key={`${item.href}-${item.label}`}>
{item.label}
</Breadcrumbs.Item>
))}
<Breadcrumbs.Item>{currentLabel}</Breadcrumbs.Item>
</Breadcrumbs>
</nav>
);
}
import { ChevronDownIcon as ChevronDown } from '@heroicons/react/20/solid';
import { Label, ListBox, Select } from '@heroui/react';
import clsx from 'clsx';
import { useMemo } from 'react';
const EMPTY_OPTION_KEY = '__rc_filter_empty__';
export default function FilterSelect({ 'aria-label': ariaLabel, className, onChange, options = [], placeholder = '请选择', value = '' }) {
const normalizedOptions = useMemo(() => options.map((option) => typeof option === 'object' ? { label: String(option.label ?? option.value ?? ''), value: String(option.value ?? '') } : { label: String(option), value: String(option) }), [options]);
const selectedValue = String(value ?? '');
const selectedOption = normalizedOptions.find((option) => option.value === selectedValue);
return (
<Select aria-label={ariaLabel || placeholder} className={clsx('rc-filter-select', className)} fullWidth selectedKey={selectedValue || EMPTY_OPTION_KEY} variant="secondary" onSelectionChange={(key) => onChange?.(key === EMPTY_OPTION_KEY ? '' : String(key ?? ''))}>
<Select.Trigger className="rc-filter-select__trigger">
<Select.Value className="rc-filter-select__value"><span className={clsx('block min-w-0 truncate', !selectedOption && 'rc-filter-select__placeholder')}>{selectedOption?.label || placeholder}</span></Select.Value>
<ChevronDown className="rc-filter-select__indicator" />
</Select.Trigger>
<Select.Popover className="rc-filter-select__popover" placement="bottom start">
<ListBox aria-label={ariaLabel || placeholder} className="rc-filter-select__listbox">
{normalizedOptions.map((option) => (
<ListBox.Item key={option.value || EMPTY_OPTION_KEY} id={option.value || EMPTY_OPTION_KEY} className="rc-filter-select__option" textValue={option.label}>
<Label className="rc-filter-select__option-label">{option.label}</Label>
<ListBox.ItemIndicator className="rc-filter-select__option-indicator" />
</ListBox.Item>
))}
</ListBox>
</Select.Popover>
</Select>
);
}
import { Button, Tooltip } from '@heroui/react';
import clsx from 'clsx';
export function TableActionGroup({ children, className }) {
return (
<div className={clsx('icon-actions flex flex-nowrap items-center justify-end gap-1.5 whitespace-nowrap', className)}>
{children}
</div>
);
}
export function TableActionButton({ icon: Icon, label, onPress, tone = 'default' }) {
return (
<Tooltip delay={0}>
<Button
isIconOnly
aria-label={label}
className={clsx('pm-table-action', `pm-table-action--${tone}`)}
size="sm"
title={label}
variant="ghost"
onPress={onPress}
>
<Icon size={16} />
</Button>
<Tooltip.Content>{label}</Tooltip.Content>
</Tooltip>
);
}
import { Info } from '@/components/AppIcons';
import { Button, Tooltip } from '@heroui/react';
export function TitleInfo({ label, content }) {
if (!content) return null;
return (
<Tooltip delay={0}>
<Button isIconOnly aria-label={`${label}说明`} className="rc-title-info-trigger" size="sm" variant="ghost">
<Info size={15} />
</Button>
<Tooltip.Content>{content}</Tooltip.Content>
</Tooltip>
);
}
...@@ -377,7 +377,7 @@ function WorkbenchPagination({ pagination }) { ...@@ -377,7 +377,7 @@ function WorkbenchPagination({ pagination }) {
const pageItems = buildPaginationPageItems(currentPage, totalPages); const pageItems = buildPaginationPageItems(currentPage, totalPages);
return ( return (
<div className="flex flex-col gap-3 border-t border-zinc-100 bg-zinc-50/70 px-4 py-3 sm:flex-row sm:items-center sm:justify-between"> <div className="rc-list-pagination flex flex-col gap-3 border-t border-zinc-100 px-4 py-3 sm:flex-row sm:items-center sm:justify-between">
<div className="flex flex-wrap items-center gap-3 text-sm text-slate-500"> <div className="flex flex-wrap items-center gap-3 text-sm text-slate-500">
<span> <span>
共 {totalRecords} 条,显示 {startRecord}-{endRecord} 共 {totalRecords} 条,显示 {startRecord}-{endRecord}
...@@ -398,7 +398,7 @@ function WorkbenchPagination({ pagination }) { ...@@ -398,7 +398,7 @@ function WorkbenchPagination({ pagination }) {
</label> </label>
</div> </div>
<div className="flex flex-wrap items-center gap-1.5"> <div className="rc-pagination-pages flex flex-wrap items-center gap-1.5">
<Button <Button
plain plain
disabled={currentPage <= 0} disabled={currentPage <= 0}
......
This source diff could not be displayed because it is too large. You can view the blob instead.
.rc-app-shell {
position: fixed;
inset: 0;
display: flex;
overflow: hidden;
color: var(--rc-text-primary);
background: var(--rc-bg-canvas);
}
.rc-sidebar,
.rc-mobile-sidebar {
display: flex;
flex-direction: column;
color: var(--foreground);
background: var(--rc-bg-canvas);
}
.rc-sidebar {
position: relative;
z-index: 30;
width: 15rem;
height: 100%;
flex: none;
padding: var(--rc-space-4) var(--rc-space-3) var(--rc-space-3);
transition: width var(--rc-motion-normal) var(--rc-ease-standard);
}
.rc-sidebar.is-collapsed {
width: 4rem;
}
.rc-sidebar-brand {
width: 100%;
min-width: 0;
display: flex;
min-height: 3.25rem;
align-items: center;
gap: 0.625rem;
padding: 0.5rem 0.25rem;
color: var(--foreground);
font-size: var(--rc-text-sm);
font-weight: var(--rc-font-semibold);
}
.rc-sidebar-brand.is-collapsed {
justify-content: center;
padding-inline: 0;
}
.rc-sidebar-brand-mark {
display: flex;
width: 1.75rem;
height: 1.75rem;
flex: none;
align-items: center;
justify-content: center;
overflow: hidden;
}
.rc-sidebar-logo {
display: block;
width: 100%;
height: 100%;
object-fit: contain;
}
.rc-sidebar-logo-dark {
display: none;
}
.dark .rc-sidebar-logo-light {
display: none;
}
.dark .rc-sidebar-logo-dark {
display: block;
}
.rc-sidebar-brand-main {
display: flex;
min-width: 0;
flex: 1;
align-items: center;
gap: var(--rc-space-2);
}
.rc-sidebar-app-icon {
display: inline-flex;
width: 1.75rem;
height: 1.75rem;
flex: none;
align-items: center;
justify-content: center;
border-radius: var(--rc-radius-control);
color: var(--rc-brand-light);
background: rgb(255 255 255 / 8%);
}
.rc-sidebar-title {
min-width: 0;
overflow: hidden;
color: var(--foreground);
font-size: 0.95rem;
font-weight: 650;
line-height: 1.2rem;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
text-overflow: ellipsis;
white-space: nowrap;
}
.rc-sidebar-app-switcher {
flex: none;
}
.rc-sidebar-content {
min-height: 0;
flex: 1;
overflow-y: auto;
padding-top: var(--rc-space-4);
scrollbar-width: thin;
}
.rc-sidebar-group + .rc-sidebar-group {
margin-top: var(--rc-space-5);
}
.rc-sidebar-group-label {
margin: 0 0 var(--rc-space-2);
padding: 0 var(--rc-space-3);
color: var(--muted);
font-size: var(--rc-text-xs);
font-weight: var(--rc-font-medium);
line-height: var(--rc-line-normal);
}
.rc-sidebar-menu {
display: grid;
gap: var(--rc-space-1);
}
.rc-sidebar-item {
position: relative;
display: flex;
min-width: 0;
height: 2.5rem;
align-items: center;
gap: var(--rc-space-3);
padding: 0 var(--rc-space-3);
border-radius: var(--rc-radius-control);
color: var(--muted);
font-size: var(--rc-text-sm);
font-weight: var(--rc-font-medium);
text-decoration: none;
transition: color var(--rc-motion-fast) var(--rc-ease-standard),
background var(--rc-motion-fast) var(--rc-ease-standard);
}
.rc-sidebar-item:hover {
color: var(--foreground);
background: var(--default);
}
.rc-sidebar-item.is-active {
color: var(--foreground);
background: var(--default);
}
.rc-sidebar-item.is-active::before {
position: absolute;
inset-block: 0.5rem;
left: 0;
width: 0.1875rem;
border-radius: 0 999px 999px 0;
background: var(--rc-brand-primary);
content: '';
}
.rc-sidebar-item.is-collapsed {
justify-content: center;
padding-inline: 0;
}
.rc-sidebar-item-icon {
flex: none;
font-size: 1rem;
}
.rc-sidebar-item.is-active .rc-sidebar-item-icon {
color: var(--rc-brand-light);
}
.rc-sidebar-item-label {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.rc-sidebar-state {
margin: var(--rc-space-2);
padding: var(--rc-space-3);
border-radius: var(--rc-radius-control);
color: var(--muted);
background: var(--default);
font-size: var(--rc-text-xs);
}
.rc-sidebar-state.is-error {
color: rgb(254 202 202);
background: rgb(201 54 54 / 14%);
}
.rc-sidebar.is-collapsed .rc-sidebar-state {
display: none;
}
.rc-sidebar-user {
display: flex;
width: 100%;
min-height: 3rem;
align-items: center;
gap: var(--rc-space-3);
padding: 0.375rem var(--rc-space-2);
border: 0;
border-radius: var(--rc-radius-container);
color: var(--foreground);
background: transparent;
cursor: pointer;
text-align: left;
}
.rc-sidebar-user:hover,
.rc-sidebar-user:focus-visible {
background: rgb(255 255 255 / 7%);
}
.rc-sidebar-user:focus-visible,
.rc-sidebar-item:focus-visible {
outline: 2px solid var(--rc-brand-light);
outline-offset: 2px;
}
.rc-sidebar-user.is-collapsed {
justify-content: center;
padding-inline: 0;
}
.rc-sidebar-avatar {
flex: none;
background: var(--rc-brand-primary);
}
.rc-sidebar-user-copy {
display: flex;
min-width: 0;
flex: 1;
flex-direction: column;
}
.rc-sidebar-user-copy strong,
.rc-sidebar-user-copy small {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.rc-sidebar-user-copy strong {
font-size: var(--rc-text-sm);
font-weight: var(--rc-font-medium);
}
.rc-sidebar-user-copy small {
margin-top: 0.125rem;
color: var(--muted);
font-size: var(--rc-text-xs);
}
.rc-sidebar-logout {
flex: none;
color: var(--muted);
font-size: 0.875rem;
}
.rc-app-main {
--rc-page-title-inset: calc(
var(--rc-space-6) + var(--rc-navbar-trigger-size) + var(--rc-space-3)
);
display: flex;
min-width: 0;
min-height: 0;
flex: 1;
flex-direction: column;
overflow: hidden;
}
.rc-navbar {
flex: none;
height: 4rem;
min-height: 4rem;
max-height: 4rem;
border: 0;
background: transparent;
box-shadow: none;
backdrop-filter: none;
}
.rc-navbar .navbar__header {
width: 100%;
height: 4rem;
min-height: 4rem;
max-height: 4rem;
gap: var(--rc-space-3);
padding: 0 var(--rc-space-6);
}
.rc-navbar [data-slot='sidebar-trigger'] {
width: var(--rc-navbar-trigger-size);
min-width: var(--rc-navbar-trigger-size);
max-width: var(--rc-navbar-trigger-size);
height: var(--rc-navbar-trigger-size);
flex: 0 0 var(--rc-navbar-trigger-size);
}
.rc-navbar-icon-button.button,
.rc-navbar-icon-button.toggle-button {
width: var(--rc-navbar-icon-button-size);
min-width: var(--rc-navbar-icon-button-size);
max-width: var(--rc-navbar-icon-button-size);
height: var(--rc-navbar-icon-button-size);
flex: 0 0 var(--rc-navbar-icon-button-size);
align-items: center;
justify-content: center;
padding: 0;
border: 0;
border-radius: 50%;
color: var(--foreground);
box-shadow: none;
line-height: 1;
}
.rc-navbar [data-slot='sidebar-trigger'] {
background: transparent !important;
}
.rc-navbar-icon-button.button,
.rc-navbar-icon-button.toggle-button {
background: var(--default) !important;
}
.rc-navbar [data-slot='sidebar-trigger']:hover,
.rc-navbar [data-slot='sidebar-trigger'][data-hovered='true'],
.rc-navbar [data-slot='sidebar-trigger']:focus-visible {
color: var(--foreground);
background: var(--default) !important;
}
.rc-navbar [data-slot='sidebar-trigger']:active,
.rc-navbar [data-slot='sidebar-trigger'][data-pressed='true'] {
background: var(--default-hover) !important;
}
.rc-navbar-icon-button.button:hover,
.rc-navbar-icon-button.button[data-hovered='true'],
.rc-navbar-icon-button.toggle-button:hover,
.rc-navbar-icon-button.toggle-button[data-hovered='true'] {
color: var(--foreground);
background: var(--default-hover) !important;
}
.rc-navbar [data-slot='sidebar-trigger'] > span,
.rc-navbar-icon-button > span,
.rc-navbar-icon-button .anticon {
display: grid;
width: 1rem;
height: 1rem;
place-items: center;
line-height: 1;
}
.rc-navbar [data-slot='sidebar-trigger'] > svg,
.rc-navbar [data-slot='sidebar-trigger'] > span > svg,
.rc-navbar-icon-button > svg,
.rc-navbar-icon-button .anticon > svg {
display: block;
width: 1rem;
height: 1rem;
margin: 0;
}
.rc-navbar-actions {
display: flex;
align-items: center;
gap: var(--rc-space-2);
}
.rc-navbar-title {
min-width: 0;
margin: 0;
overflow: hidden;
color: var(--foreground);
font-size: var(--rc-navbar-title-size);
font-weight: var(--rc-navbar-title-weight);
line-height: var(--rc-navbar-title-line-height);
letter-spacing: 0 !important;
text-overflow: ellipsis;
white-space: nowrap;
}
.rc-navbar-spacer {
flex: 1;
}
.app-shell-content-scroll {
min-width: 0;
background: var(--rc-bg-canvas);
overscroll-behavior: contain;
}
.rc-app-page {
width: 100%;
max-width: none;
min-width: 0;
min-height: 100%;
margin: 0;
padding: var(--rc-space-4) var(--rc-page-title-inset) var(--rc-space-5);
overflow-x: clip;
}
.rc-mobile-sidebar-backdrop {
position: fixed;
inset: 0;
z-index: 200;
background: rgb(15 23 42 / 32%);
transition: opacity var(--rc-motion-normal) var(--rc-ease-standard);
}
.rc-mobile-sidebar-panel {
position: fixed;
inset-block: 0;
left: 0;
z-index: 210;
width: min(19rem, calc(100vw - 3rem));
transition: transform var(--rc-motion-normal) var(--rc-ease-standard);
}
.rc-mobile-sidebar {
position: relative;
width: 100%;
height: 100%;
padding: var(--rc-space-4) var(--rc-space-3) var(--rc-space-3);
box-shadow: var(--rc-shadow-overlay);
}
.rc-mobile-sidebar-close.button {
position: absolute;
top: var(--rc-space-3);
right: var(--rc-space-3);
z-index: 1;
width: 2rem;
min-width: 2rem;
height: 2rem;
border-radius: 999px;
color: rgb(212 212 216);
}
@media (max-width: 1023px) {
.rc-sidebar {
display: none;
}
.rc-navbar {
min-height: 4rem;
}
}
@media (max-width: 640px) {
.rc-app-main {
--rc-page-title-inset: calc(
var(--rc-space-6) + var(--rc-navbar-icon-button-size) + var(--rc-space-3)
);
}
.rc-app-page {
padding: var(--rc-space-4) var(--rc-page-title-inset) var(--rc-space-5);
}
.rc-navbar [data-slot='sidebar-trigger'] {
width: var(--rc-navbar-icon-button-size);
min-width: var(--rc-navbar-icon-button-size);
max-width: var(--rc-navbar-icon-button-size);
height: var(--rc-navbar-icon-button-size);
flex-basis: var(--rc-navbar-icon-button-size);
}
}
/* HeroUI Pro offcanvas shell contract */
.rc-app-shell.sidebar__provider {
position: fixed;
inset: 0;
width: 100%;
height: 100dvh;
min-width: 0;
min-height: 0;
overflow: hidden;
background: var(--rc-bg-canvas);
}
.rc-app-shell .sidebar__offcanvas-wrapper {
--sidebar-width: 15rem;
}
.rc-app-shell .rc-sidebar.sidebar,
.rc-mobile-sidebar {
width: 15rem;
height: 100%;
max-height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
border: 0;
border-right: 1px solid var(--rc-border-default);
border-radius: 0;
background: var(--rc-bg-canvas);
box-shadow: none;
}
.rc-app-shell .sidebar__header,
.rc-mobile-sidebar .sidebar__header {
padding: 0.375rem var(--rc-space-4) 0.5rem;
}
.rc-sidebar-brand {
min-height: 3.25rem;
gap: 0.625rem;
padding: 0.5rem 0.25rem;
}
.rc-sidebar-title {
min-width: 0;
color: var(--foreground);
font-size: 0.95rem;
font-weight: 650;
line-height: 1.2rem;
}
.rc-sidebar-app-trigger.button {
display: grid;
width: var(--rc-sidebar-app-trigger-size);
height: var(--rc-sidebar-app-trigger-size);
min-width: var(--rc-sidebar-app-trigger-size);
max-width: var(--rc-sidebar-app-trigger-size);
flex: 0 0 var(--rc-sidebar-app-trigger-size);
place-items: center;
padding: 0;
border-radius: 50%;
color: var(--foreground);
background: transparent;
line-height: 1;
--button-bg-hover: var(--accent-soft);
--button-bg-pressed: var(--accent-soft);
}
@media (hover: hover) {
.rc-sidebar-app-trigger.button:hover,
.rc-sidebar-app-trigger.button[data-hovered='true'] {
color: var(--foreground);
background: var(--accent-soft);
}
}
.rc-sidebar-app-trigger.button[data-pressed='true'],
.rc-sidebar-app-trigger.button[aria-expanded='true'] {
color: var(--foreground);
background: var(--accent-soft);
}
.rc-sidebar-app-popover {
width: min(45rem, calc(100vw - 2rem));
padding: 0;
}
.rc-sidebar-app-dialog {
max-height: min(32rem, calc(100dvh - 7rem));
padding: 1.5rem;
overflow-y: auto;
outline: none;
}
.rc-sidebar-app-card {
min-width: 0;
cursor: pointer;
}
.rc-sidebar-app-card[aria-disabled='true'] {
cursor: default;
opacity: 0.6;
}
.rc-sidebar-app-logo,
.rc-sidebar-app-initial {
width: 2rem;
height: 2rem;
border-radius: var(--rc-radius-container);
object-fit: contain;
}
.rc-sidebar-app-initial {
display: grid;
place-items: center;
color: var(--foreground);
background: var(--default);
font-size: var(--rc-text-sm);
font-weight: var(--rc-font-semibold);
}
.rc-app-shell .sidebar__content,
.rc-mobile-sidebar .sidebar__content {
min-height: 0;
padding: 0 var(--rc-space-3);
}
.rc-app-shell .sidebar__group,
.rc-mobile-sidebar .sidebar__group {
padding: 0;
}
.rc-app-shell .sidebar__group + .sidebar__group,
.rc-mobile-sidebar .sidebar__group + .sidebar__group {
margin-top: var(--rc-space-2);
}
.rc-app-shell .sidebar__group-label,
.rc-mobile-sidebar .sidebar__group-label {
padding: 0.375rem var(--rc-space-2);
color: var(--rc-text-muted);
}
.rc-app-shell .sidebar__menu-item-content,
.rc-mobile-sidebar .sidebar__menu-item-content {
min-height: 2.25rem;
border-radius: calc(var(--radius) * 2);
color: var(--foreground);
}
.rc-app-shell .sidebar__menu-icon,
.rc-app-shell .sidebar__menu-label,
.rc-mobile-sidebar .sidebar__menu-icon,
.rc-mobile-sidebar .sidebar__menu-label {
color: inherit;
}
.rc-app-shell
.sidebar__menu-item[data-current='true']
.sidebar__menu-item-content,
.rc-mobile-sidebar
.sidebar__menu-item[data-current='true']
.sidebar__menu-item-content {
color: var(--foreground);
background: var(--default);
}
.rc-app-shell .sidebar__menu-item:hover .sidebar__menu-item-content,
.rc-app-shell
.sidebar__menu-item[data-hovered='true']
.sidebar__menu-item-content,
.rc-mobile-sidebar .sidebar__menu-item:hover .sidebar__menu-item-content,
.rc-mobile-sidebar
.sidebar__menu-item[data-hovered='true']
.sidebar__menu-item-content {
color: var(--foreground);
background: var(--default);
}
.rc-app-shell .sidebar__footer,
.rc-mobile-sidebar .sidebar__footer {
padding: var(--rc-space-2) var(--rc-space-3) var(--rc-space-4);
}
.rc-sidebar-user-trigger.button {
display: flex;
width: 100%;
min-width: 0;
min-height: 3rem;
align-items: center;
justify-content: center;
gap: 0.625rem;
padding: 0.375rem 0.5rem;
border-radius: calc(var(--radius) * 2);
color: var(--foreground);
background: transparent;
text-align: left;
}
.rc-sidebar-user-trigger.button:hover,
.rc-sidebar-user-trigger.button[data-hovered='true'],
.rc-sidebar-user-trigger.button[aria-expanded='true'] {
background: var(--default);
}
.rc-sidebar-avatar {
width: 2rem;
height: 2rem;
min-width: 2rem;
flex: 0 0 2rem;
background: var(--default);
}
.rc-sidebar-user-copy {
gap: 0.125rem;
line-height: 1;
}
.rc-sidebar-user-menu-item {
display: flex;
width: 100%;
align-items: center;
justify-content: space-between;
gap: var(--rc-space-2);
}
.rc-app-main.sidebar__main {
height: 100dvh;
min-height: 0;
max-height: 100dvh;
margin: 0;
overflow: hidden;
border: 0;
border-radius: 0;
background: var(--rc-bg-canvas);
}
.rc-navbar {
flex: none;
height: 4rem;
min-height: 4rem;
max-height: 4rem;
border: 0;
background: transparent;
}
.rc-navbar [data-slot='sidebar-trigger'] {
width: var(--rc-navbar-trigger-size);
min-width: var(--rc-navbar-trigger-size);
max-width: var(--rc-navbar-trigger-size);
height: var(--rc-navbar-trigger-size);
flex: 0 0 var(--rc-navbar-trigger-size);
padding: 0;
}
.rc-navbar-icon-button.button,
.rc-navbar-icon-button.toggle-button {
width: var(--rc-navbar-icon-button-size);
min-width: var(--rc-navbar-icon-button-size);
max-width: var(--rc-navbar-icon-button-size);
height: var(--rc-navbar-icon-button-size);
flex: 0 0 var(--rc-navbar-icon-button-size);
padding: 0;
}
@media (max-width: 768px) {
.rc-navbar [data-slot='sidebar-trigger'] {
width: var(--rc-navbar-icon-button-size);
min-width: var(--rc-navbar-icon-button-size);
max-width: var(--rc-navbar-icon-button-size);
height: var(--rc-navbar-icon-button-size);
flex-basis: var(--rc-navbar-icon-button-size);
}
.rc-app-shell > .sidebar__offcanvas-wrapper {
display: none;
}
.rc-mobile-sidebar {
width: 100%;
border-right: 0;
}
}
@media (min-width: 769px) {
.rc-app-shell .rc-sidebar.sidebar {
display: flex;
}
}
.rc-login-page {
display: grid;
min-height: 100dvh;
place-items: center;
padding: var(--rc-space-6);
background: var(--app-background-gradient);
}
.rc-login-shell {
display: grid;
width: min(100%, var(--rc-login-panel-width));
gap: var(--rc-login-brand-gap);
}
.rc-login-brand {
display: flex;
align-items: center;
justify-content: center;
gap: var(--rc-space-3);
color: var(--rc-text-primary);
}
.rc-login-brand img {
width: auto;
max-width: 8rem;
height: 1.5rem;
filter: brightness(0) saturate(100%) invert(13%) sepia(17%) saturate(1318%)
hue-rotate(181deg) brightness(91%) contrast(92%);
object-fit: contain;
}
.rc-login-brand strong {
font-size: var(--rc-login-brand-size);
font-weight: var(--rc-font-semibold);
}
.rc-login-card.card {
border-radius: var(--rc-radius-overlay);
background: var(--rc-bg-surface);
box-shadow: var(--rc-shadow-raised);
}
.rc-login-form {
display: grid;
gap: var(--rc-space-5);
}
@media (max-width: 480px) {
.rc-login-page {
align-items: start;
padding: 12vh var(--rc-space-4) var(--rc-space-4);
}
.rc-login-brand {
align-items: flex-start;
flex-direction: column;
}
}
/* approved Xinyuan baseline Sidebar geometry and typography contract. */
.template-dashboard-shell .app-sidebar-glass,
.rc-mobile-sidebar.app-sidebar-glass {
width: 15rem;
height: 100%;
max-height: 100%;
margin: 0;
overflow: hidden;
border: 0;
border-right: 1px solid var(--rc-border-default);
border-radius: 0;
color: var(--foreground);
background: var(--rc-bg-canvas);
box-shadow: none;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
}
.template-dashboard-shell .sidebar__header,
.rc-mobile-sidebar .sidebar__header {
padding: 6px 1rem 0.5rem;
}
.app-sidebar-brand {
display: flex;
width: 100%;
min-width: 0;
min-height: 3rem;
align-items: center;
gap: 0.75rem;
padding: 0.5rem 0.25rem;
}
.app-sidebar-brand-main {
display: flex;
min-width: 0;
flex: 1;
align-items: center;
gap: 0.5rem;
}
.app-sidebar-brand-mark {
display: flex;
width: 2.75rem;
height: 1.5rem;
flex: none;
align-items: center;
justify-content: center;
overflow: hidden;
}
.app-sidebar-brand-mark img {
display: block;
width: 100%;
height: 100%;
object-fit: contain;
}
.app-sidebar-title {
min-width: 0;
overflow: hidden;
color: var(--foreground);
font-size: 0.95rem;
font-weight: 650;
line-height: 1.2rem;
letter-spacing: 0;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
text-overflow: ellipsis;
white-space: nowrap;
}
.app-sidebar-app-switcher {
flex: none;
}
.app-sidebar-app-trigger.button {
display: grid;
width: var(--rc-sidebar-app-trigger-size);
height: var(--rc-sidebar-app-trigger-size);
min-width: var(--rc-sidebar-app-trigger-size);
max-width: var(--rc-sidebar-app-trigger-size);
flex: none;
place-items: center;
padding: 0;
border-radius: 50%;
color: var(--foreground);
background-color: transparent;
line-height: 1;
--button-bg-hover: var(--accent-soft);
--button-bg-pressed: var(--accent-soft);
--button-fg: var(--foreground);
}
.app-sidebar-app-trigger .anticon {
display: grid;
width: var(--rc-sidebar-app-trigger-icon-size);
height: var(--rc-sidebar-app-trigger-icon-size);
place-items: center;
line-height: 1;
}
.app-sidebar-app-trigger .anticon > svg {
display: block;
width: 100%;
height: 100%;
}
@media (hover: hover) {
.app-sidebar-app-trigger.button:hover,
.app-sidebar-app-trigger.button[data-hovered='true'] {
color: var(--foreground);
background-color: var(--accent-soft);
}
}
.app-sidebar-app-trigger.button:active,
.app-sidebar-app-trigger.button[data-pressed='true'],
.app-sidebar-app-trigger.button[aria-expanded='true'] {
color: var(--foreground);
background-color: var(--accent-soft);
}
.app-sidebar-app-dialog {
overflow: hidden;
outline: none;
}
.app-sidebar-app-scroll {
max-height: min(32rem, calc(100dvh - 7rem));
padding: 1.5rem;
overflow-y: auto;
}
.template-dashboard-shell .sidebar__content,
.rc-mobile-sidebar .sidebar__content {
min-height: 0;
padding-inline: 0.75rem;
}
.template-dashboard-shell .sidebar__group,
.rc-mobile-sidebar .sidebar__group {
padding: 0;
}
.template-dashboard-shell .sidebar__group + .sidebar__group,
.rc-mobile-sidebar .sidebar__group + .sidebar__group {
margin-top: 0.5rem;
}
.template-dashboard-shell .sidebar__group-label,
.rc-mobile-sidebar .sidebar__group-label {
padding: 0.375rem 0.5rem;
color: var(--rc-text-muted);
font-size: 0.75rem;
font-weight: 500;
line-height: 1rem;
letter-spacing: 0;
}
.template-dashboard-shell .sidebar__menu-item-content,
.rc-mobile-sidebar .sidebar__menu-item-content {
min-height: 2.25rem;
gap: 0.75rem;
padding: 0.375rem 0.5rem;
border-radius: calc(var(--radius) * 2);
color: var(--foreground);
font-weight: 400;
}
.template-dashboard-shell .sidebar__menu-icon,
.rc-mobile-sidebar .sidebar__menu-icon {
width: 1.25rem;
height: 1.25rem;
color: var(--muted);
}
.template-dashboard-shell .sidebar__menu-icon svg,
.rc-mobile-sidebar .sidebar__menu-icon svg {
width: 1rem;
height: 1rem;
}
.template-dashboard-shell .sidebar__menu-label,
.rc-mobile-sidebar .sidebar__menu-label {
color: var(--foreground);
font-size: 0.875rem;
font-weight: inherit;
line-height: 1.25rem;
}
.template-dashboard-shell
.sidebar__menu-item[data-current='true']
.sidebar__menu-item-content,
.template-dashboard-shell .sidebar__menu-item:hover .sidebar__menu-item-content,
.template-dashboard-shell
.sidebar__menu-item[data-hovered='true']
.sidebar__menu-item-content,
.rc-mobile-sidebar
.sidebar__menu-item[data-current='true']
.sidebar__menu-item-content,
.rc-mobile-sidebar .sidebar__menu-item:hover .sidebar__menu-item-content,
.rc-mobile-sidebar
.sidebar__menu-item[data-hovered='true']
.sidebar__menu-item-content {
color: var(--foreground);
background: var(--default);
}
.template-dashboard-shell
.sidebar__menu-item[data-current='true']
.sidebar__menu-item-content,
.rc-mobile-sidebar
.sidebar__menu-item[data-current='true']
.sidebar__menu-item-content {
font-weight: 500;
}
.template-dashboard-shell
.sidebar__menu-item[data-current='true']
:is(.sidebar__menu-icon, .sidebar__menu-label),
.rc-mobile-sidebar
.sidebar__menu-item[data-current='true']
:is(.sidebar__menu-icon, .sidebar__menu-label) {
color: var(--foreground);
}
.template-dashboard-shell .sidebar__footer,
.rc-mobile-sidebar .sidebar__footer {
padding: 0.5rem 0.75rem 1rem;
}
.app-sidebar-user-trigger.button {
display: flex;
width: 100%;
min-width: 0;
min-height: 3rem;
align-items: center;
justify-content: center;
gap: 0.625rem;
padding: 0.375rem 0.5rem !important;
border-radius: calc(var(--radius) * 2) !important;
color: var(--foreground);
background: transparent;
text-align: left;
}
@media (hover: hover) {
.app-sidebar-user-trigger.button:hover,
.app-sidebar-user-trigger.button[data-hovered='true'] {
background: var(--default);
}
}
.app-sidebar-user-trigger.button[aria-expanded='true'] {
background: var(--default);
}
.app-sidebar-user-avatar {
width: 2rem;
height: 2rem;
min-width: 2rem;
flex: 0 0 2rem;
background: var(--default);
}
.app-sidebar-user-copy {
display: flex;
min-width: 0;
flex: 1;
flex-direction: column;
gap: 0.125rem;
line-height: 1;
}
.app-sidebar-user-name,
.app-sidebar-user-description {
display: block;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.app-sidebar-user-name {
color: var(--foreground);
font-size: 0.875rem;
font-weight: 500;
line-height: 1.125rem;
}
.app-sidebar-user-description {
color: var(--muted);
font-size: 0.75rem;
font-weight: 500;
line-height: 1rem;
}
@media (max-width: 768px) {
.rc-mobile-sidebar.app-sidebar-glass {
width: 100%;
border-right: 0;
}
}
:root,
.light,
.default,
[data-theme='light'],
[data-theme='default'] {
/* Xinyuan brand and semantic colors */
--rc-brand-primary: #9e1b1b;
--rc-brand-light: #b83a3a;
--rc-brand-dark: #7e1515;
--rc-brand-primary-hover: var(--rc-brand-light);
--rc-brand-primary-pressed: var(--rc-brand-dark);
--rc-brand-primary-soft: rgb(158 27 27 / 8%);
--rc-brand-primary-soft-hover: rgb(158 27 27 / 12%);
--rc-brand-glass: rgb(158 27 27 / 4%);
--rc-brand-on-primary: #ffffff;
--rc-color-success: #16845b;
--rc-color-warning: #b46a00;
--rc-color-danger: #c93636;
--rc-color-info: var(--rc-brand-primary);
--rc-color-teal: #0f766e;
--rc-color-favorite: #d68a00;
--rc-color-favorite-soft: rgb(214 138 0 / 10%);
--rc-color-success-soft: rgb(22 132 91 / 9%);
--rc-color-success-border: rgb(22 132 91 / 24%);
--rc-color-warning-soft: rgb(180 106 0 / 10%);
--rc-color-warning-border: rgb(180 106 0 / 25%);
--rc-color-danger-soft: rgb(201 54 54 / 9%);
--rc-color-danger-border: rgb(201 54 54 / 22%);
--rc-color-info-soft: var(--rc-brand-primary-soft);
--rc-color-info-border: color-mix(in srgb, var(--rc-brand-primary) 24%, transparent);
--rc-color-teal-soft: rgb(15 118 110 / 9%);
--rc-color-teal-border: rgb(15 118 110 / 24%);
--rc-color-neutral-soft: #f4f4f5;
--rc-color-neutral-border: #e4e4e7;
/* Surfaces, borders and text */
--rc-bg-canvas: #f5f5f5;
--rc-bg-surface: #ffffff;
--rc-bg-subtle: #f8fafc;
--rc-layout-background: #f4f6f9;
--rc-sidebar-glass: rgb(255 255 255 / 42%);
--rc-main-glass: rgb(255 255 255 / 82%);
--rc-shell-glass: rgb(255 255 255 / 78%);
--rc-glass-border: rgb(255 255 255 / 60%);
--rc-sidebar-border: rgb(226 232 240 / 55%);
--rc-border-default: #e3e8ef;
--rc-border-strong: #cbd3de;
--rc-field-background: #ffffff;
--rc-field-border: #d9e1eb;
--rc-field-border-hover: #b8c4d2;
--rc-field-border-focus: var(--rc-brand-primary);
--rc-button-secondary-border: rgb(9 9 11 / 12%);
--rc-button-secondary-border-hover: rgb(9 9 11 / 20%);
--rc-button-secondary-background-hover: rgb(9 9 11 / 4%);
--rc-text-primary: #172033;
--rc-text-secondary: #4e5d73;
--rc-text-muted: #718096;
/* Typography */
--rc-font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC',
'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;
--rc-font-mono: 'SFMono-Regular', Consolas, 'Liberation Mono', monospace;
--rc-text-xs: 0.75rem;
--rc-text-sm: 0.875rem;
--rc-text-md: 1rem;
--rc-text-lg: 1.25rem;
--rc-text-xl: 1.5rem;
--rc-font-regular: 400;
--rc-font-medium: 500;
--rc-font-semibold: 600;
--rc-line-compact: 1.25;
--rc-line-normal: 1.5;
/* Spacing, radius and motion */
--rc-space-1: 0.25rem;
--rc-space-2: 0.5rem;
--rc-space-3: 0.75rem;
--rc-space-4: 1rem;
--rc-space-5: 1.25rem;
--rc-space-6: 1.5rem;
--rc-space-8: 2rem;
--rc-space-10: 2.5rem;
--rc-radius-control: 0.375rem;
--rc-radius-container: 0.5rem;
--rc-radius-overlay: 0.75rem;
--rc-motion-fast: 120ms;
--rc-motion-normal: 180ms;
--rc-ease-standard: cubic-bezier(0.2, 0, 0, 1);
/* Component contracts */
--rc-filter-radius: 0.75rem;
--rc-button-radius: 1.5rem;
--rc-button-sm-height: 2rem;
--rc-button-md-height: 2.25rem;
--rc-button-lg-height: 2.5rem;
--rc-table-action-width: 9rem;
--rc-table-action-gap: 0.5rem;
--rc-table-action-padding-inline: 0.75rem;
--rc-table-action-idle-opacity: 0.55;
--rc-navbar-trigger-size: 2rem;
--rc-navbar-icon-button-size: 2.25rem;
--rc-segment-track-padding: 0.125rem;
--rc-segment-track-radius: 0.75rem;
--rc-segment-item-height: 1.75rem;
--rc-segment-item-radius: 0.625rem;
--rc-segment-item-padding-inline: 0.75rem;
--rc-segment-item-gap: 0.5rem;
--rc-segment-font-size: var(--rc-text-sm);
--rc-segment-font-weight: var(--rc-font-medium);
--rc-segment-line-height: 1.25rem;
--rc-sidebar-app-trigger-size: 2.25rem;
--rc-sidebar-app-trigger-icon-size: 1rem;
--rc-navbar-border-width: 0px;
--rc-navbar-title-size: 1.25rem;
--rc-navbar-page-title-size: var(--rc-navbar-title-size);
--rc-navbar-title-weight: 600;
--rc-navbar-title-line-height: 1.75rem;
--rc-login-panel-width: 28rem;
--rc-login-brand-size: 1.5rem;
--rc-login-brand-weight: var(--rc-font-semibold);
--rc-login-brand-gap: 1.5rem;
--rc-toolbar-filter-background: var(--default);
--rc-toolbar-filter-background-hover: var(--default-hover);
--rc-toolbar-filter-foreground: var(--foreground);
--rc-toolbar-filter-icon: var(--muted);
--rc-toolbar-filter-radius: 999px;
--rc-toolbar-filter-content-gap: 0.5rem;
--rc-data-grid-radius: calc(var(--radius) * 2.5);
--rc-data-grid-header-background: var(--surface-secondary);
--rc-data-grid-header-height: 2.25rem;
--rc-data-grid-header-font-size: var(--rc-text-xs);
--rc-data-grid-header-font-weight: var(--rc-font-medium);
--rc-data-grid-header-line-height: var(--rc-line-compact);
--rc-data-grid-header-color: var(--rc-text-muted);
--rc-data-grid-body-font-size: var(--rc-text-sm);
--rc-data-grid-body-font-weight: var(--rc-font-regular);
--rc-data-grid-body-line-height: var(--rc-line-normal);
--rc-data-grid-body-color: var(--rc-text-secondary);
--rc-data-grid-primary-font-size: var(--rc-text-sm);
--rc-data-grid-primary-font-weight: 550;
--rc-data-grid-primary-line-height: var(--rc-line-normal);
--rc-data-grid-primary-color: var(--rc-text-primary);
--rc-data-grid-secondary-font-size: 0.8125rem;
--rc-data-grid-secondary-font-weight: var(--rc-font-regular);
--rc-data-grid-secondary-line-height: var(--rc-line-compact);
--rc-data-grid-secondary-color: #7a8596;
--rc-data-grid-text-pair-gap: 0.25rem;
--rc-data-grid-chip-font-size: var(--rc-text-xs);
--rc-data-grid-chip-font-weight: var(--rc-font-medium);
--rc-data-grid-chip-line-height: var(--rc-line-compact);
--rc-data-grid-row-hover-background: color-mix(
in oklab,
var(--default) 35%,
var(--surface)
);
--rc-modal-radius: 1.5rem;
--rc-modal-padding: 1.75rem;
--rc-modal-title-size: var(--rc-text-md);
--rc-modal-title-weight: var(--rc-font-medium);
--rc-modal-title-line-height: 1.5rem;
--rc-modal-section-gap: 0.75rem;
--rc-modal-footer-gap: 0.5rem;
--rc-modal-footer-margin: 1.5rem;
--rc-modal-backdrop-blur: 0.75rem;
--rc-modal-close-size: 1.5rem;
--rc-modal-close-inset: var(--rc-modal-padding);
--rc-modal-close-icon-size: 1rem;
--rc-modal-width-xs: 20rem;
--rc-modal-width-sm: 24rem;
--rc-modal-width-md: 30rem;
--rc-modal-width-lg: 40rem;
--rc-modal-width-xl: 46rem;
--rc-modal-width-2xl: 52.5rem;
--rc-modal-width-3xl: 60rem;
--rc-modal-width-4xl: 68rem;
--rc-modal-width-5xl: 76rem;
--rc-data-grid-action-size: 2rem;
--rc-data-grid-action-radius: 999px;
--rc-list-pagination-gap: 0.5rem;
--rc-checkbox-size: 1rem;
--rc-checkbox-radius: 0.25rem;
--rc-checkbox-background: var(--rc-field-background);
--rc-checkbox-border: var(--rc-field-border);
--rc-checkbox-border-hover: var(--rc-field-border-hover);
--rc-checkbox-disabled-background: #f3f5f8;
--rc-checkbox-disabled-border: #d8dee7;
--rc-checkbox-disabled-opacity: 0.56;
--rc-checkbox-checked-background: var(--rc-brand-primary);
--rc-checkbox-checked-border: var(--rc-brand-dark);
--rc-checkbox-check-color: var(--rc-brand-on-primary);
--rc-kbd-background: #f4f6f9;
--rc-content-max-width: 80rem;
--rc-page-gutter: 1.25rem;
/* Elevation */
--rc-shadow-card: 0 1px 2px rgb(15 23 42 / 2%), 0 4px 12px rgb(15 23 42 / 2%);
--rc-shadow-raised: 0 1px 2px rgb(15 23 42 / 6%),
0 8px 24px rgb(15 23 42 / 8%);
--rc-shadow-overlay: 0 16px 40px rgb(15 23 42 / 14%);
--rc-shadow-brand-glow: 0 4px 14px rgb(158 27 27 / 15%);
--rc-shadow-main-glass: 0 8px 28px rgb(148 163 184 / 14%),
inset 0 0 0 1px rgb(255 255 255 / 30%);
/* HeroUI semantic bridge */
--accent: var(--rc-brand-primary);
--accent-foreground: var(--rc-brand-on-primary);
--accent-hover: var(--rc-brand-primary-hover);
--accent-soft: var(--rc-brand-primary-soft);
--accent-soft-hover: var(--rc-brand-primary-soft-hover);
--accent-soft-foreground: color-mix(
in oklab,
var(--rc-brand-primary) 82%,
var(--rc-text-primary) 18%
);
--background: var(--rc-bg-canvas);
--surface: var(--rc-bg-surface);
--surface-shadow: var(--rc-shadow-card);
--foreground: var(--rc-text-primary);
--muted: var(--rc-text-muted);
--muted-foreground: var(--rc-text-secondary);
--separator: var(--rc-border-default);
--focus: var(--rc-brand-primary);
--app-background-gradient: radial-gradient(
circle at 0% 0%,
rgb(158 27 27 / 5%) 0%,
rgb(244 246 249 / 0%) 50%
),
var(--rc-layout-background);
}
.dark,
[data-theme='dark'] {
color-scheme: dark;
--rc-brand-primary-soft: rgb(158 27 27 / 16%);
--rc-brand-primary-soft-hover: rgb(158 27 27 / 22%);
--rc-brand-glass: rgb(158 27 27 / 10%);
--rc-color-success: #4fca92;
--rc-color-warning: #f0ad4e;
--rc-color-danger: #ff7272;
--rc-color-info: #f0a3a3;
--rc-color-teal: #5eead4;
--rc-color-favorite: #f2b84b;
--rc-color-favorite-soft: rgb(242 184 75 / 14%);
--rc-color-success-soft: rgb(79 202 146 / 14%);
--rc-color-success-border: rgb(79 202 146 / 30%);
--rc-color-warning-soft: rgb(240 173 78 / 15%);
--rc-color-warning-border: rgb(240 173 78 / 32%);
--rc-color-danger-soft: rgb(255 114 114 / 14%);
--rc-color-danger-border: rgb(255 114 114 / 30%);
--rc-color-info-soft: rgb(158 27 27 / 18%);
--rc-color-info-border: rgb(184 58 58 / 42%);
--rc-color-teal-soft: rgb(94 234 212 / 14%);
--rc-color-teal-border: rgb(94 234 212 / 30%);
--rc-color-neutral-soft: #27272a;
--rc-color-neutral-border: #3f3f46;
--rc-bg-canvas: #0f0f11;
--rc-bg-surface: #18181b;
--rc-bg-subtle: #202024;
--rc-layout-background: #0f0f11;
--rc-sidebar-glass: #0f0f11;
--rc-main-glass: #0f0f11;
--rc-shell-glass: #0f0f11;
--rc-glass-border: #303036;
--rc-sidebar-border: #303036;
--rc-border-default: #303036;
--rc-border-strong: #45454d;
--rc-field-background: #202024;
--rc-field-border: #3b3b42;
--rc-field-border-hover: #56565f;
--rc-button-secondary-border: rgb(255 255 255 / 18%);
--rc-button-secondary-border-hover: rgb(255 255 255 / 28%);
--rc-button-secondary-background-hover: rgb(255 255 255 / 7%);
--rc-text-primary: #f4f4f5;
--rc-text-secondary: #d4d4d8;
--rc-text-muted: #a1a1aa;
--rc-data-grid-secondary-color: #8b8b95;
--rc-checkbox-background: #202024;
--rc-checkbox-border: #56565f;
--rc-checkbox-border-hover: #6f6f7a;
--rc-checkbox-disabled-background: #1b1b1f;
--rc-checkbox-disabled-border: #36363d;
--rc-checkbox-disabled-opacity: 0.58;
--rc-kbd-background: #202024;
--rc-shadow-card: 0 1px 2px rgb(0 0 0 / 18%), 0 4px 12px rgb(0 0 0 / 12%);
--rc-shadow-raised: 0 1px 2px rgb(0 0 0 / 24%), 0 8px 24px rgb(0 0 0 / 24%);
--rc-shadow-overlay: 0 16px 40px rgb(0 0 0 / 38%);
--rc-shadow-main-glass: none;
--accent: var(--rc-brand-primary);
--accent-foreground: var(--rc-brand-on-primary);
--accent-hover: var(--rc-brand-light);
--accent-soft: var(--rc-brand-primary-soft);
--accent-soft-hover: var(--rc-brand-primary-soft-hover);
--accent-soft-foreground: #f0a3a3;
--background: var(--rc-bg-canvas);
--surface: var(--rc-bg-surface);
--surface-secondary: var(--rc-bg-subtle);
--surface-shadow: var(--rc-shadow-card);
--overlay: var(--rc-bg-surface);
--overlay-foreground: var(--rc-text-primary);
--foreground: var(--rc-text-primary);
--muted: var(--rc-text-muted);
--muted-foreground: var(--rc-text-secondary);
--default: #27272a;
--default-hover: #3f3f46;
--border: var(--rc-border-default);
--separator: var(--rc-border-default);
--field: var(--rc-field-background);
--field-foreground: var(--rc-text-primary);
--focus: var(--rc-brand-primary);
--backdrop: rgb(0 0 0 / 50%);
--app-background-gradient: var(--rc-bg-canvas);
}
import xyLogoRed from '@/assets/xy-logo-red.png';
import authService from '@/services/authService'; import authService from '@/services/authService';
import { getCaptcha, userLogin } from '@/services/DataService'; import { getCaptcha, userLogin } from '@/services/DataService';
import { SiteContext } from '@/wrapper/Site'; import { SiteContext } from '@/wrapper/Site';
import { Alert } from '@heroui/react/alert';
import { Button } from '@heroui/react/button';
import { Card } from '@heroui/react/card';
import { Input } from '@heroui/react/input';
import { Label } from '@heroui/react/label';
import { TextField } from '@heroui/react/textfield';
import CryptoJS from 'crypto-js'; import CryptoJS from 'crypto-js';
import { useContext, useEffect, useMemo, useState } from 'react'; import { useContext, useEffect, useState } from 'react';
import { history, useSearchParams } from 'umi'; import { history, useSearchParams } from 'umi';
function buildPassword(password, siteKey) { const APP_NAME = 'OA流程监控';
if (!password) {
return password;
}
function buildPassword(password, siteKey) {
if (!password) return password;
return siteKey ? CryptoJS.AES.encrypt(password, siteKey).toString() : password; return siteKey ? CryptoJS.AES.encrypt(password, siteKey).toString() : password;
} }
...@@ -23,36 +29,12 @@ export default function LoginPage() { ...@@ -23,36 +29,12 @@ export default function LoginPage() {
const [captchaLoading, setCaptchaLoading] = useState(false); const [captchaLoading, setCaptchaLoading] = useState(false);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [error, setError] = useState(''); const [error, setError] = useState('');
const redirect = searchParams.get('redirect') || '/'; const redirect = searchParams.get('redirect') || '/';
const siteTitle = site?.title || site?.name || '问题整改系统';
const siteSubtitle =
site?.subtitle || '整改填报、复核流转、归档追溯与驾驶舱统计统一协同';
const backgroundStyle = useMemo(() => {
const overlay =
'linear-gradient(135deg, rgba(64, 8, 18, 0.95) 0%, rgba(113, 18, 41, 0.92) 52%, rgba(190, 24, 93, 0.82) 100%)';
if (!site?.background) {
return {
backgroundImage: `${overlay}, radial-gradient(circle at top, #7f1d1d 0%, #450a0a 45%, #1f0a0f 100%)`,
};
}
return {
backgroundImage: `${overlay}, url(${site.background})`,
backgroundSize: 'cover',
backgroundPosition: 'center',
};
}, [site?.background]);
const refreshCaptcha = async () => { const refreshCaptcha = async () => {
setCaptchaLoading(true); setCaptchaLoading(true);
try { try {
const nextCaptcha = await getCaptcha(); setCaptchaData((await getCaptcha()) || null);
setCaptchaData(nextCaptcha || null);
} catch (requestError) { } catch (requestError) {
setCaptchaData(null); setCaptchaData(null);
setError(requestError?.message || '验证码加载失败,请稍后重试'); setError(requestError?.message || '验证码加载失败,请稍后重试');
...@@ -62,6 +44,7 @@ export default function LoginPage() { ...@@ -62,6 +44,7 @@ export default function LoginPage() {
}; };
useEffect(() => { useEffect(() => {
document.title = APP_NAME;
refreshCaptcha(); refreshCaptcha();
}, []); }, []);
...@@ -78,12 +61,8 @@ export default function LoginPage() { ...@@ -78,12 +61,8 @@ export default function LoginPage() {
token: captchaData?.token, token: captchaData?.token,
type: 'password', type: 'password',
}); });
authService.setCurrentUser(loginInfo); authService.setCurrentUser(loginInfo);
if (loginInfo?.token) { if (loginInfo?.token) authService.setToken(loginInfo.token);
authService.setToken(loginInfo.token);
}
history.push(redirect); history.push(redirect);
} catch (requestError) { } catch (requestError) {
setError(requestError?.message || '登录失败,请重试'); setError(requestError?.message || '登录失败,请重试');
...@@ -95,140 +74,95 @@ export default function LoginPage() { ...@@ -95,140 +74,95 @@ export default function LoginPage() {
}; };
return ( return (
<div <main className="login-page rc-login-page overflow-y-auto">
className="min-h-screen bg-[#061321] px-4 py-6 text-white md:px-8" <section className="login-shell rc-login-shell">
style={backgroundStyle} <Card className="login-card rc-login-card">
> <Card.Content>
<div className="mx-auto flex min-h-[calc(100vh-3rem)] w-full max-w-7xl overflow-hidden rounded-[32px] border border-white/10 bg-white/6 shadow-[0_28px_120px_rgba(0,0,0,0.38)] backdrop-blur-sm"> <div className="login-brand login-card-brand">
<section className="relative hidden w-[52%] flex-col justify-between overflow-hidden px-10 py-12 lg:flex"> <img alt="鑫元" src={xyLogoRed} />
<div className="absolute inset-0 bg-[radial-gradient(circle_at_top_left,rgba(255,255,255,0.2),transparent_36%),radial-gradient(circle_at_bottom_right,rgba(49,196,255,0.3),transparent_32%)]" /> <strong>{APP_NAME}</strong>
<div className="relative z-10 max-w-xl">
<p className="text-xs font-medium uppercase tracking-[0.45em] text-white/60">
Problem Rectification Access
</p>
<h1 className="mt-6 text-4xl font-semibold leading-tight text-white">
{siteTitle}
</h1>
<p className="mt-5 max-w-lg text-base leading-7 text-white/72">
{siteSubtitle}
</p>
</div> </div>
<div className="relative z-10 grid gap-4 xl:grid-cols-2"> <form className="login-form" onSubmit={handleSubmit}>
<div className="rounded-3xl border border-white/10 bg-white/8 p-6"> <TextField className="login-field" data-has-value={identity ? 'true' : undefined} fullWidth isDisabled={loading} isRequired value={identity} onChange={setIdentity}>
<div className="text-sm text-white/65">流转闭环</div> <Label>账号</Label>
<div className="mt-3 text-2xl font-semibold text-white"> <Input
填报 + 复核 + 归档 autoComplete="username"
</div> autoFocus
<p className="mt-3 text-sm leading-6 text-white/68"> className="login-input"
从问题录入到整改填报、复核、最终审核与归档追溯,流程在一个模块内连续完成。 data-filled={identity ? 'true' : undefined}
</p>
</div>
<div className="rounded-3xl border border-white/10 bg-black/18 p-6">
<div className="text-sm text-white/65">风险看板</div>
<div className="mt-3 text-2xl font-semibold text-white">临近与逾期整改</div>
<p className="mt-3 text-sm leading-6 text-white/68">
驾驶舱会统一展示整改进度、问题分布、临近整改与逾期清单,方便管理层快速判断风险。
</p>
</div>
</div>
</section>
<section className="flex flex-1 items-center justify-center bg-white/92 px-6 py-10 text-slate-900 sm:px-10">
<div className="w-full max-w-md">
<div className="mb-8">
<p className="text-sm font-medium uppercase tracking-[0.35em] text-sky-600/80">
Sign In
</p>
<h2 className="mt-3 text-3xl font-semibold text-slate-900">
登录问题整改系统
</h2>
<p className="mt-3 text-sm leading-6 text-slate-500">
当前登录入口已切换到问题整改重构版,继续沿用验证码校验流程。
</p>
</div>
<form onSubmit={handleSubmit} className="space-y-5">
<div>
<label className="mb-2 block text-sm font-medium text-slate-700">
账号
</label>
<input
className="w-full rounded-2xl border border-slate-200 bg-slate-50 px-4 py-3 text-sm text-slate-900 outline-none transition focus:border-sky-500 focus:bg-white"
value={identity}
onChange={(event) => setIdentity(event.target.value)}
disabled={loading}
placeholder="请输入账号" placeholder="请输入账号"
required variant="secondary"
/> />
</div> </TextField>
<div> <TextField className="login-field" data-has-value={password ? 'true' : undefined} fullWidth isDisabled={loading} isRequired type="password" value={password} onChange={setPassword}>
<label className="mb-2 block text-sm font-medium text-slate-700"> <Label>密码</Label>
密码 <Input
</label> autoComplete="current-password"
<input className="login-input"
type="password" data-filled={password ? 'true' : undefined}
className="w-full rounded-2xl border border-slate-200 bg-slate-50 px-4 py-3 text-sm text-slate-900 outline-none transition focus:border-sky-500 focus:bg-white"
value={password}
onChange={(event) => setPassword(event.target.value)}
disabled={loading}
placeholder="请输入密码" placeholder="请输入密码"
required variant="secondary"
/> />
</div> </TextField>
<div> <div className="login-field" data-has-value={captchaCode ? 'true' : undefined}>
<label className="mb-2 block text-sm font-medium text-slate-700"> <Label>验证码</Label>
验证码 <div className="login-captcha-row">
</label> <TextField className="min-w-0" fullWidth isDisabled={loading} isRequired value={captchaCode} onChange={setCaptchaCode}>
<div className="flex gap-3"> <Input
<input aria-label="验证码"
className="min-w-0 flex-1 rounded-2xl border border-slate-200 bg-slate-50 px-4 py-3 text-sm text-slate-900 outline-none transition focus:border-sky-500 focus:bg-white" autoComplete="off"
value={captchaCode} className="login-input"
onChange={(event) => setCaptchaCode(event.target.value)} data-filled={captchaCode ? 'true' : undefined}
disabled={loading}
placeholder="请输入验证码" placeholder="请输入验证码"
required variant="secondary"
/> />
<button </TextField>
<Button
aria-label="刷新验证码"
className="login-captcha-button overflow-hidden"
isDisabled={loading || captchaLoading}
type="button" type="button"
onClick={() => { variant="outline"
onPress={() => {
setError(''); setError('');
refreshCaptcha(); refreshCaptcha();
}} }}
disabled={loading || captchaLoading}
className="flex h-[56px] w-[148px] shrink-0 items-center justify-center overflow-hidden rounded-2xl border border-slate-200 bg-white px-2 text-xs text-slate-500 transition hover:border-sky-300 hover:text-sky-600 disabled:cursor-not-allowed disabled:opacity-70"
> >
{captchaData?.image ? ( {captchaData?.image ? (
<span <span
className="captcha-image flex h-full w-full items-center justify-center" className="captcha-image"
dangerouslySetInnerHTML={{ __html: captchaData.image }} dangerouslySetInnerHTML={{ __html: captchaData.image }}
/> />
) : ( ) : (
<span>{captchaLoading ? '加载中...' : '刷新验证码'}</span> <span className="text-xs">{captchaLoading ? '加载中...' : '刷新验证码'}</span>
)} )}
</button> </Button>
</div> </div>
</div> </div>
{error ? ( {error ? (
<div className="rounded-2xl border border-rose-200 bg-rose-50 px-4 py-3 text-sm text-rose-600"> <Alert status="danger">
{error} <Alert.Content><Alert.Description>{error}</Alert.Description></Alert.Content>
</div> </Alert>
) : null} ) : null}
<button <Button
fullWidth
className="login-submit-button"
isDisabled={!identity.trim() || !password || !captchaCode.trim() || captchaLoading}
isPending={loading}
type="submit" type="submit"
disabled={loading || captchaLoading} variant="primary"
className="flex w-full items-center justify-center rounded-2xl bg-[linear-gradient(135deg,#7f1d1d_0%,#be123c_55%,#e11d48_100%)] px-4 py-3 text-sm font-medium text-white shadow-[0_16px_40px_rgba(190,24,93,0.28)] transition hover:brightness-105 disabled:cursor-not-allowed disabled:opacity-70"
> >
{loading ? '登录中...' : '登录'} {loading ? '登录中...' : '登录'}
</button> </Button>
</form> </form>
</div> </Card.Content>
</Card>
</section> </section>
</div> </main>
</div>
); );
} }
import AppShell from '@/components/AppShell';
import ApplicationSwitcherDialog from '@/components/ApplicationSwitcherDialog'; import ApplicationSwitcherDialog from '@/components/ApplicationSwitcherDialog';
import xyLogoSmall from '@/assets/xy-logo_small.png'; import DashboardNavbar from '@/components/DashboardNavbar';
import DashboardSidebar from '@/components/DashboardSidebar';
import { ProcessList } from '@/components/AppIcons';
import { useUserInfo } from '@/hooks/user'; import { useUserInfo } from '@/hooks/user';
import { SiteContext } from '@/wrapper/Site'; import { SiteContext } from '@/wrapper/Site';
import { import { useContext, useLayoutEffect, useMemo, useState } from 'react';
Bars3Icon, import { history, Outlet, useLocation } from 'umi';
QueueListIcon,
Squares2X2Icon,
XMarkIcon,
} from '@heroicons/react/24/outline';
import clsx from 'clsx';
import { useContext, useEffect, useMemo, useState } from 'react';
import { Link, Outlet, useLocation } from 'umi';
const APP_NAME = '流程监控'; const APP_NAME = 'OA流程监控';
const THEME_STORAGE_KEY = 'xinyuan_color_theme';
const menuGroups = [{ title: '监控模块', items: [{ name: '流程监控', path: '/process_monitor', icon: ProcessList }] }];
const menuGroups = [ function getInitialTheme() {
{ if (typeof window === 'undefined') return 'light';
title: '监控模块', return window.localStorage.getItem(THEME_STORAGE_KEY) === 'dark' ? 'dark' : 'light';
items: [
{
name: '流程监控',
path: '/process_monitor',
icon: QueueListIcon,
},
],
},
];
function NavbarItem({ className, ...props }) {
return (
<button
type="button"
className={clsx(
'inline-flex items-center justify-center rounded-lg p-2 text-zinc-500 transition hover:bg-zinc-100 hover:text-zinc-900',
className,
)}
{...props}
/>
);
}
function NavItem({ name, path, active, collapsed, icon: Icon, onNavigate }) {
return (
<Link
to={path}
onClick={onNavigate}
title={collapsed ? name : undefined}
aria-label={collapsed ? name : undefined}
className={clsx(
'group relative flex items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium transition-all duration-200',
active
? 'bg-[var(--pm-brand)] text-white shadow-lg'
: 'text-white/90 hover:bg-zinc-800 hover:text-white',
collapsed && 'justify-center px-2',
)}
>
{Icon ? (
<Icon
className={clsx(
'size-5 shrink-0 transition-colors',
active ? 'text-white' : 'text-white/80 group-hover:text-white',
)}
/>
) : null}
{!collapsed ? (
<span
className={clsx(
'min-w-0 flex-1 truncate',
active ? 'text-white' : 'text-white/90 group-hover:text-white',
)}
>
{name}
</span>
) : null}
{active && !collapsed ? (
<span className="absolute right-2 size-1.5 rounded-full bg-white/50" />
) : null}
</Link>
);
}
function MobileSidebar({ open, close, children }) {
if (!open) {
return null;
}
return (
<div className="relative z-[140] lg:hidden">
<div className="fixed inset-0 z-[140] bg-black/30" onClick={close} aria-hidden="true" />
<div className="fixed inset-y-0 z-[150] w-full max-w-80 p-2">
<div className="flex h-full flex-col rounded-lg bg-zinc-900 shadow-xs ring-1 ring-white/10">
<div className="-mb-3 flex justify-end px-4 pt-3">
<NavbarItem
onClick={close}
aria-label="Close navigation"
className="text-zinc-400 hover:text-white"
>
<XMarkIcon className="size-5" />
</NavbarItem>
</div>
{children}
</div>
</div>
</div>
);
}
function CollapseSidebarIcon() {
return (
<svg data-slot="icon" viewBox="0 0 20 20" aria-hidden="true" fill="currentColor">
<path d="M12.78 15.53a.75.75 0 0 1-1.06 0l-4.5-4.5a.75.75 0 0 1 0-1.06l4.5-4.5a.75.75 0 1 1 1.06 1.06L8.81 10l3.97 3.97a.75.75 0 0 1 0 1.06Z" />
</svg>
);
}
function ExpandSidebarIcon() {
return (
<svg data-slot="icon" viewBox="0 0 20 20" aria-hidden="true" fill="currentColor">
<path d="M7.22 15.53a.75.75 0 0 0 1.06 0l4.5-4.5a.75.75 0 0 0 0-1.06l-4.5-4.5a.75.75 0 1 0-1.06 1.06L11.19 10l-3.97 3.97a.75.75 0 0 0 0 1.06Z" />
</svg>
);
} }
export default function ProcessMonitorLayout() { export default function ProcessMonitorLayout() {
const location = useLocation(); const location = useLocation();
const userInfo = useUserInfo(); const userInfo = useUserInfo();
const siteInfo = useContext(SiteContext); const siteInfo = useContext(SiteContext);
const [isMobile, setIsMobile] = useState(false); const [theme, setTheme] = useState(getInitialTheme);
const [sidebarOpen, setSidebarOpen] = useState(true);
const [isApplicationDialogOpen, setIsApplicationDialogOpen] = useState(false); const [isApplicationDialogOpen, setIsApplicationDialogOpen] = useState(false);
const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(false);
const [isMobileSidebarOpen, setIsMobileSidebarOpen] = useState(false);
useEffect(() => {
if (typeof window === 'undefined') {
return;
}
const media = window.matchMedia('(max-width: 1023px)');
const sync = () => { useLayoutEffect(() => {
const mobile = !!media.matches; const root = document.documentElement;
setIsMobile(mobile); root.classList.toggle('dark', theme === 'dark');
if (mobile) { root.classList.toggle('light', theme === 'light');
setIsMobileSidebarOpen(false); root.dataset.theme = theme;
setIsSidebarCollapsed(true); root.style.colorScheme = theme;
} else { window.localStorage.setItem(THEME_STORAGE_KEY, theme);
const storedCollapsed = window.localStorage?.getItem?.('pm_sidebar_collapsed'); }, [theme]);
if (storedCollapsed !== null && storedCollapsed !== undefined) {
setIsSidebarCollapsed(storedCollapsed === '1');
}
}
};
sync(); const currentTitle = useMemo(() => location.pathname === '/process_monitor' ? '流程监控' : '流程详情', [location.pathname]);
media.addEventListener?.('change', sync); useLayoutEffect(() => { document.title = `${currentTitle} - ${APP_NAME}`; }, [currentTitle]);
return () => {
media.removeEventListener?.('change', sync);
};
}, []);
const sidebarCollapsed = isMobile ? true : isSidebarCollapsed;
const currentGroupTitle = useMemo(
() =>
menuGroups.find((group) => group.items.some((item) => location.pathname.startsWith(item.path)))
?.title || '',
[location.pathname],
);
const applicationSwitcherButton = (
<button
type="button"
onClick={() => setIsApplicationDialogOpen(true)}
aria-label="Open application switcher"
title="应用切换"
className={clsx(
'inline-flex items-center justify-center rounded-[20px] border border-[#0ea5e9]/70 bg-[linear-gradient(180deg,rgba(39,39,42,0.92),rgba(24,24,27,0.96))] text-[#38bdf8] shadow-[0_16px_30px_rgba(14,165,233,0.16)] transition duration-200 hover:-translate-y-0.5 hover:border-[#7dd3fc] hover:text-[#bae6fd] hover:shadow-[0_18px_36px_rgba(14,165,233,0.26)] focus:outline-none focus-visible:ring-2 focus-visible:ring-[#7dd3fc]/50',
sidebarCollapsed ? 'size-11' : 'size-14',
)}
>
<Squares2X2Icon className={clsx(sidebarCollapsed ? 'size-5' : 'size-7')} />
</button>
);
return ( return (
<div <AppShell
className="flex h-screen overflow-hidden bg-[radial-gradient(circle_at_top_left,_rgba(186,230,253,0.26),_transparent_30%),radial-gradient(circle_at_bottom_right,_rgba(204,251,241,0.2),_transparent_28%),#f8fafc]" navigate={(href) => history.push(href)}
style={{ navbar={<DashboardNavbar theme={theme} title={currentTitle} onThemeChange={setTheme} />}
'--pm-brand': '#0f766e', onOpenChange={setSidebarOpen}
'--pm-brand-strong': '#115e59', open={sidebarOpen}
}} overlays={<ApplicationSwitcherDialog open={isApplicationDialogOpen} onClose={() => setIsApplicationDialogOpen(false)} userInfo={userInfo} siteInfo={siteInfo} />}
> sidebar={<DashboardSidebar appName={APP_NAME} menuGroups={menuGroups} pathname={location.pathname} userInfo={userInfo} onOpenApplications={() => setIsApplicationDialogOpen(true)} />}
<aside theme={theme}
className={clsx(
'relative z-30 hidden shrink-0 flex-col border-r border-zinc-800 bg-zinc-900 p-5 lg:flex',
sidebarCollapsed ? 'w-20' : 'w-72',
)}
>
<div
className={clsx(
'mb-7',
sidebarCollapsed
? 'flex flex-col items-center gap-3'
: 'flex items-start justify-between gap-4 px-1',
)}
> >
{sidebarCollapsed ? (
<>
<img
src={xyLogoSmall}
alt="XY Logo"
className="h-8 w-auto max-w-8 shrink-0 object-contain"
/>
{applicationSwitcherButton}
</>
) : (
<>
<div className="min-w-0 flex-1">
<h1 className="truncate text-sm font-semibold tracking-[0.02em] text-white/95">
{APP_NAME}
</h1>
</div>
{applicationSwitcherButton}
</>
)}
</div>
<nav className="flex-1 space-y-5 overflow-y-auto">
{menuGroups.map((group) => (
<div key={group.title}>
{!sidebarCollapsed ? (
<h2 className="mb-2 px-1 text-xs font-medium tracking-wide text-zinc-500">
{group.title}
</h2>
) : null}
<div className="space-y-1">
{group.items.map((item) => (
<NavItem
key={item.path}
name={item.name}
path={item.path}
active={location.pathname.startsWith(item.path)}
collapsed={sidebarCollapsed}
icon={item.icon}
/>
))}
</div>
</div>
))}
</nav>
{!sidebarCollapsed ? (
<div className="mt-6 rounded-2xl border border-zinc-800 bg-zinc-950/70 p-4 text-sm text-zinc-300">
<div className="font-medium text-white/90">
{userInfo?.display_name || userInfo?.username || '当前用户'}
</div>
<div className="mt-1 text-xs text-zinc-500">当前正在查看流程监控重构模块</div>
</div>
) : null}
</aside>
<div className="relative z-30 hidden lg:flex">
<button
type="button"
onClick={() =>
setIsSidebarCollapsed((prev) => {
const next = !prev;
window?.localStorage?.setItem?.('pm_sidebar_collapsed', next ? '1' : '0');
return next;
})
}
aria-label={sidebarCollapsed ? 'Expand sidebar' : 'Collapse sidebar'}
className="absolute -left-3.5 top-16 z-10 flex size-7 items-center justify-center rounded-full border border-zinc-700 bg-zinc-800 text-zinc-400 shadow hover:bg-zinc-700 hover:text-white [&_svg]:size-4"
>
{sidebarCollapsed ? <ExpandSidebarIcon /> : <CollapseSidebarIcon />}
</button>
</div>
<MobileSidebar open={isMobileSidebarOpen} close={() => setIsMobileSidebarOpen(false)}>
<div className="px-5 pt-6">
<h1 className="text-base font-semibold tracking-[0.02em] text-white">{APP_NAME}</h1>
<div className="text-xs text-zinc-500">流程监控重构版</div>
</div>
<nav className="space-y-5 overflow-y-auto px-5 pb-6 pt-6">
{menuGroups.map((group) => (
<div key={group.title}>
<h2 className="mb-2 px-1 text-xs font-medium tracking-wide text-zinc-600">
{group.title}
</h2>
<div className="space-y-1">
{group.items.map((item) => (
<NavItem
key={item.path}
name={item.name}
path={item.path}
active={location.pathname.startsWith(item.path)}
icon={item.icon}
onNavigate={() => setIsMobileSidebarOpen(false)}
/>
))}
</div>
</div>
))}
</nav>
</MobileSidebar>
<main className="flex flex-1 flex-col overflow-hidden p-4 sm:p-6">
<div className="mb-4 flex items-center justify-between gap-3 lg:hidden">
<NavbarItem onClick={() => setIsMobileSidebarOpen(true)} aria-label="Open navigation">
<Bars3Icon className="size-5" />
</NavbarItem>
<div className="text-sm text-zinc-500">{currentGroupTitle}</div>
<NavbarItem
onClick={() => setIsApplicationDialogOpen(true)}
aria-label="Open application switcher"
className="border border-sky-200 bg-white text-sky-500 shadow-sm hover:bg-sky-50 hover:text-sky-600"
>
<Squares2X2Icon className="size-5" />
</NavbarItem>
</div>
<div className="flex-1 overflow-y-auto rounded-[28px] border border-white/80 bg-white/80 p-4 shadow-sm backdrop-blur sm:p-6">
<Outlet /> <Outlet />
</div> </AppShell>
</main>
<ApplicationSwitcherDialog
open={isApplicationDialogOpen}
onClose={() => setIsApplicationDialogOpen(false)}
userInfo={userInfo}
siteInfo={siteInfo}
/>
</div>
); );
} }
...@@ -6,9 +6,10 @@ import { ...@@ -6,9 +6,10 @@ import {
getDisplayFieldMap, getDisplayFieldMap,
loadProcessInstanceDetail, loadProcessInstanceDetail,
} from '@/pages/process_monitor/processMonitorService'; } from '@/pages/process_monitor/processMonitorService';
import { ArrowLeftIcon } from '@heroicons/react/24/outline'; import DetailNavigation from '@/components/DetailNavigation';
import { useEffect, useMemo, useState } from 'react'; import { useEffect, useMemo, useState } from 'react';
import { Link, useParams, useSearchParams } from 'umi'; import { useParams, useSearchParams } from 'umi';
import { TitleInfo } from '@/components/XinyuanUi';
function InfoCard({ label, value }) { function InfoCard({ label, value }) {
return ( return (
...@@ -123,30 +124,18 @@ export default function ProcessDetailPage() { ...@@ -123,30 +124,18 @@ export default function ProcessDetailPage() {
const relatedCondition = record?.metadata?.related_progress?.metadata?.conditions; const relatedCondition = record?.metadata?.related_progress?.metadata?.conditions;
return ( return (
<div className="space-y-6"> <div className="rc-page-stack">
<div className="flex flex-wrap items-center gap-3 text-sm text-slate-500"> <DetailNavigation
<Link backHref={`/process_monitor/${processId}${tabName ? `?tab=${tabName}` : ''}`}
to={tabName ? `/process_monitor?tab=${tabName}` : '/process_monitor'} backLabel="返回实例列表"
className="inline-flex items-center gap-2 rounded-full border border-slate-200 bg-white px-3 py-1.5 font-medium text-slate-600 transition hover:border-sky-200 hover:text-sky-700" currentLabel="流程实例详情"
> items={[
<ArrowLeftIcon className="size-4" /> { label: '流程监控', href: tabName ? `/process_monitor?tab=${tabName}` : '/process_monitor' },
返回流程监控 { label: relatedTemplateTitle === '-' ? '实例列表' : relatedTemplateTitle, href: `/process_monitor/${processId}${tabName ? `?tab=${tabName}` : ''}` },
</Link> ]}
<Link />
to={`/process_monitor/${processId}${tabName ? `?tab=${tabName}` : ''}`}
className="inline-flex items-center gap-2 rounded-full border border-slate-200 bg-white px-3 py-1.5 font-medium text-slate-600 transition hover:border-sky-200 hover:text-sky-700"
>
返回实例列表
</Link>
</div>
<section className="overflow-hidden rounded-[32px] border border-slate-200/70 bg-[linear-gradient(135deg,rgba(15,118,110,0.10),rgba(14,165,233,0.12))] px-6 py-7 shadow-sm sm:px-8"> <section className="rc-detail-status">
<h1 className="text-3xl font-semibold tracking-tight text-slate-950 sm:text-4xl">
{record?.title || '流程实例详情'}
</h1>
<p className="mt-3 max-w-3xl text-sm leading-6 text-slate-600 sm:text-base">
对应旧版 `ProcessDetail` 的单条流程实例详情页,使用新的卡片布局展示提交人、部门、时间和动态表单字段。
</p>
{message ? ( {message ? (
<div className="mt-4 rounded-2xl border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-700"> <div className="mt-4 rounded-2xl border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-700">
{message} {message}
...@@ -174,7 +163,8 @@ export default function ProcessDetailPage() { ...@@ -174,7 +163,8 @@ export default function ProcessDetailPage() {
<InfoCard label="动态字段数" value={String(details.length || 0)} /> <InfoCard label="动态字段数" value={String(details.length || 0)} />
</div> </div>
<SectionCard title="表单字段详情" description="按实际提交流水中的明细字段逐项展开,附件保持单独下载入口。"> <section className="rc-detail-section">
<div className="rc-list-action-bar"><div className="flex items-center gap-2"><h2>表单字段详情</h2><TitleInfo label="表单字段详情" content="按实际提交流水中的明细字段逐项展开,附件保留独立下载入口。" /></div></div>
{loading ? ( {loading ? (
<div className="rounded-[24px] border border-slate-200 bg-slate-50/70 px-6 py-10 text-sm text-slate-500"> <div className="rounded-[24px] border border-slate-200 bg-slate-50/70 px-6 py-10 text-sm text-slate-500">
正在加载字段详情... 正在加载字段详情...
...@@ -188,7 +178,7 @@ export default function ProcessDetailPage() { ...@@ -188,7 +178,7 @@ export default function ProcessDetailPage() {
{details.map((field, index) => ( {details.map((field, index) => (
<article <article
key={`${field.label}-${index}`} key={`${field.label}-${index}`}
className="rounded-[24px] border border-slate-200 bg-[linear-gradient(180deg,rgba(255,255,255,0.96),rgba(248,250,252,0.96))] p-5 shadow-sm" className="rc-detail-field-card rounded-[24px] border border-slate-200 p-5"
> >
<div className="flex items-start justify-between gap-3"> <div className="flex items-start justify-between gap-3">
<div> <div>
...@@ -210,7 +200,7 @@ export default function ProcessDetailPage() { ...@@ -210,7 +200,7 @@ export default function ProcessDetailPage() {
))} ))}
</div> </div>
)} )}
</SectionCard> </section>
</div> </div>
); );
} }
...@@ -10,15 +10,15 @@ import { ...@@ -10,15 +10,15 @@ import {
import { Field, FieldGroup, Label } from '@/catalyst-ui-kit/javascript/fieldset'; import { Field, FieldGroup, Label } from '@/catalyst-ui-kit/javascript/fieldset';
import { Input } from '@/catalyst-ui-kit/javascript/input'; import { Input } from '@/catalyst-ui-kit/javascript/input';
import { Select } from '@/catalyst-ui-kit/javascript/select'; import { Select } from '@/catalyst-ui-kit/javascript/select';
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@/catalyst-ui-kit/javascript/table';
import { useAuthorization } from '@/hooks/user'; import { useAuthorization } from '@/hooks/user';
import { TitleInfo } from '@/components/XinyuanUi';
import FilterSelect from '@/components/FilterSelect';
import { DataStore, FileText, FolderOpen, Reload, Team } from '@/components/AppIcons';
import { Delete, Edit } from '@/components/AppIcons';
import { TableActionButton, TableActionGroup } from '@/components/TableActionButton';
import { Button as HeroButton, Tabs, Tooltip } from '@heroui/react';
import { Pagination } from '@heroui/react/pagination';
import { DataGrid } from '@heroui-pro/react/data-grid';
import { import {
addTemplatesToGroup, addTemplatesToGroup,
createProcessGroup, createProcessGroup,
...@@ -29,23 +29,25 @@ import { ...@@ -29,23 +29,25 @@ import {
} from '@/pages/process_monitor/processMonitorService'; } from '@/pages/process_monitor/processMonitorService';
import { import {
MagnifyingGlassIcon, MagnifyingGlassIcon,
PencilSquareIcon,
PlusIcon,
QueueListIcon, QueueListIcon,
TrashIcon,
} from '@heroicons/react/24/outline'; } from '@heroicons/react/24/outline';
import clsx from 'clsx'; import clsx from 'clsx';
import { useEffect, useMemo, useState } from 'react'; import { useEffect, useMemo, useState } from 'react';
import { Link, useSearchParams } from 'umi'; import { Link, useSearchParams } from 'umi';
function SummaryCard({ label, value, hint }) { function SummaryCard({ label, value, hint, icon: Icon, tone }) {
return ( return (
<div className="rounded-[24px] border border-slate-200/80 bg-[linear-gradient(180deg,rgba(255,255,255,0.94),rgba(240,249,255,0.94))] p-5 shadow-sm"> <div className="rc-card-surface rc-dashboard-card flex min-h-32 items-center justify-between gap-5 border border-[var(--rc-border-default)] p-5">
<div className="text-xs font-semibold uppercase tracking-[0.22em] text-slate-400"> <div className="min-w-0">
{label} <div className="flex items-center gap-2 text-xs font-semibold uppercase tracking-[0.16em] text-[var(--rc-text-muted)]">
<span>{label}</span>
<TitleInfo label={label} content={hint} />
</div>
<div className="mt-3 text-3xl font-semibold tracking-tight text-[var(--rc-text-primary)]">{value}</div>
</div>
<div className={clsx('rc-metric-icon-surface', `rc-tone-surface--${tone}`)}>
<Icon size={20} />
</div> </div>
<div className="mt-3 text-3xl font-semibold tracking-tight text-slate-950">{value}</div>
<div className="mt-2 text-sm text-slate-500">{hint}</div>
</div> </div>
); );
} }
...@@ -76,9 +78,9 @@ function SectionCard({ title, description, action, children }) { ...@@ -76,9 +78,9 @@ function SectionCard({ title, description, action, children }) {
return ( return (
<section className="rounded-[28px] border border-slate-200/80 bg-white/92 p-5 shadow-sm"> <section className="rounded-[28px] border border-slate-200/80 bg-white/92 p-5 shadow-sm">
<div className="flex flex-wrap items-start justify-between gap-4"> <div className="flex flex-wrap items-start justify-between gap-4">
<div> <div className="flex items-center gap-2">
<h2 className="text-lg font-semibold text-slate-950">{title}</h2> <h2 className="text-lg font-semibold text-slate-950">{title}</h2>
{description ? <p className="mt-1 text-sm text-slate-500">{description}</p> : null} <TitleInfo label={title} content={description} />
</div> </div>
{action} {action}
</div> </div>
...@@ -87,17 +89,6 @@ function SectionCard({ title, description, action, children }) { ...@@ -87,17 +89,6 @@ function SectionCard({ title, description, action, children }) {
); );
} }
function StatusPill({ children, tone = 'default' }) {
const toneClass =
tone === 'sky'
? 'bg-sky-50 text-sky-700'
: tone === 'emerald'
? 'bg-emerald-50 text-emerald-700'
: 'bg-zinc-100 text-zinc-700';
return <span className={clsx('rounded-full px-2.5 py-1 text-xs font-medium', toneClass)}>{children}</span>;
}
function EmptyState({ title, description, action }) { function EmptyState({ title, description, action }) {
return ( return (
<div className="rounded-[28px] border border-dashed border-slate-300 bg-slate-50/60 px-6 py-14 text-center"> <div className="rounded-[28px] border border-dashed border-slate-300 bg-slate-50/60 px-6 py-14 text-center">
...@@ -125,6 +116,8 @@ export default function ProcessMonitorPage() { ...@@ -125,6 +116,8 @@ export default function ProcessMonitorPage() {
const [activeGroupName, setActiveGroupName] = useState(initialTab); const [activeGroupName, setActiveGroupName] = useState(initialTab);
const [templateKeyword, setTemplateKeyword] = useState(''); const [templateKeyword, setTemplateKeyword] = useState('');
const [departmentFilter, setDepartmentFilter] = useState(''); const [departmentFilter, setDepartmentFilter] = useState('');
const [listPage, setListPage] = useState(0);
const [listPageSize, setListPageSize] = useState(10);
const [notice, setNotice] = useState(null); const [notice, setNotice] = useState(null);
const [createGroupOpen, setCreateGroupOpen] = useState(false); const [createGroupOpen, setCreateGroupOpen] = useState(false);
...@@ -211,6 +204,16 @@ export default function ProcessMonitorPage() { ...@@ -211,6 +204,16 @@ export default function ProcessMonitorPage() {
}); });
}, [activeGroup, departmentFilter, templateKeyword]); }, [activeGroup, departmentFilter, templateKeyword]);
const listTotalPages = Math.max(1, Math.ceil(filteredTemplates.length / listPageSize));
const pagedTemplates = useMemo(
() => filteredTemplates.slice(listPage * listPageSize, (listPage + 1) * listPageSize),
[filteredTemplates, listPage, listPageSize],
);
useEffect(() => {
setListPage(0);
}, [activeGroupName, departmentFilter, templateKeyword, listPageSize]);
const pickerTemplates = useMemo(() => { const pickerTemplates = useMemo(() => {
return availableTemplates.filter((template) => return availableTemplates.filter((template) =>
!templatePickerKeyword || template.title?.includes(templatePickerKeyword), !templatePickerKeyword || template.title?.includes(templatePickerKeyword),
...@@ -328,54 +331,95 @@ export default function ProcessMonitorPage() { ...@@ -328,54 +331,95 @@ export default function ProcessMonitorPage() {
} }
}; };
return ( const listColumns = useMemo(() => {
<div className="space-y-6"> const columns = [
<section className="overflow-hidden rounded-[32px] border border-slate-200/70 bg-[linear-gradient(135deg,rgba(15,118,110,0.94),rgba(14,165,233,0.88))] px-6 py-7 text-white shadow-[0_20px_60px_rgba(15,118,110,0.18)] sm:px-8"> {
<div className="flex flex-wrap items-start justify-between gap-4"> id: 'title',
<div className="max-w-3xl"> header: '模板名称',
<div className="inline-flex items-center gap-2 rounded-full bg-white/14 px-3 py-1 text-xs font-medium text-white/90"> isRowHeader: true,
<QueueListIcon className="size-4" /> width: 250,
OA Process Monitor minWidth: 220,
</div> cell: (template) => (
<h1 className="mt-4 text-3xl font-semibold tracking-tight sm:text-4xl">流程监控工作台</h1> <div className="pm-data-grid-text-pair">
<p className="mt-3 max-w-2xl text-sm leading-6 text-white/78 sm:text-base"> <Link
这里承接 `streams-admin` 中 `process_monitor` 的核心逻辑,用当前项目的新组件体系重建分组管理、模板监控、实例追踪和明细查看。 to={`/process_monitor/${template._id}?tab=${activeGroup?.name || ''}`}
</p> className="pm-data-grid-primary rc-data-grid-title-link"
</div>
<div className="flex flex-wrap gap-3">
{canManage ? (
<Button color="blue" onClick={() => setCreateGroupOpen(true)}>
<PlusIcon data-slot="icon" />
新建分组
</Button>
) : null}
{canManage ? (
<Button
outline
onClick={() => setAddTemplateOpen(true)}
disabled={!activeGroup || loading}
> >
<PlusIcon data-slot="icon" /> {template.title}
添加监控模板 </Link>
</Button> <span className="pm-data-grid-secondary">外部模板 ID:{template?.metadata?.external_id || '-'}</span>
) : null}
</div>
</div> </div>
</section> ),
},
{
id: 'department',
header: '所属部门',
width: 180,
minWidth: 160,
cell: (template) => <span className="pm-data-grid-text">{template?.metadata?.department || '-'}</span>,
},
{
id: 'templateCode',
header: '模板编码',
width: 200,
minWidth: 180,
cell: (template) => <span className="pm-data-grid-text">{template?.metadata?.template_code || '-'}</span>,
},
{
id: 'condition',
header: '显示条件',
width: 220,
minWidth: 190,
cell: (template) => (
<span className="pm-data-grid-text">
{template?.metadata?.conditions?.key
? `${template.metadata.conditions.key} = ${template.metadata.conditions.value || '-'}`
: '-'}
</span>
),
},
{
id: 'status',
header: '状态',
width: 120,
minWidth: 110,
cell: () => <span className="rc-status-chip rc-status-chip--success">监控中</span>,
},
];
if (canManage) {
columns.push({
id: 'actions',
header: '操作',
width: 112,
minWidth: 112,
align: 'end',
pinned: 'end',
cell: (template) => (
<TableActionGroup>
<TableActionButton icon={Edit} label="编辑" onPress={() => openEditDialog(template)} />
<TableActionButton icon={Delete} label="取消监控" tone="danger" onPress={() => setRemoveTarget(template)} />
</TableActionGroup>
),
});
}
return columns;
}, [activeGroup?.name, canManage]);
return (
<div className="rc-page-stack">
<InlineNotice notice={notice} onClose={() => setNotice(null)} /> <InlineNotice notice={notice} onClose={() => setNotice(null)} />
<div className="grid gap-4 lg:grid-cols-4"> <div className="grid gap-4 lg:grid-cols-4">
<SummaryCard label="监控分组" value={groups.length} hint="按业务视角组织模板监控范围" /> <SummaryCard label="监控分组" value={groups.length} hint="按业务视角组织模板监控范围" icon={Team} tone="info" />
<SummaryCard label="当前分组模板" value={monitoredTemplateCount} hint="当前选中分组的监控模板数量" /> <SummaryCard label="当前分组模板" value={monitoredTemplateCount} hint="当前选中分组的监控模板数量" icon={FileText} tone="success" />
<SummaryCard label="累计监控模板" value={monitoredTotalCount} hint="所有分组合计已纳入监控的模板数" /> <SummaryCard label="累计监控模板" value={monitoredTotalCount} hint="所有分组合计已纳入监控的模板数" icon={DataStore} tone="warning" />
<SummaryCard label="模板库" value={availableTemplates.length} hint="同步接口返回的可选流程模板数量" /> <SummaryCard label="模板库" value={availableTemplates.length} hint="同步接口返回的可选流程模板数量" icon={FolderOpen} tone="teal" />
</div> </div>
<SectionCard <div className="rc-tabs-command-row">
title="分组切换" <section className="rc-page-tabs-scroll" aria-label="监控分组">
description="保留旧版“分组 tab + 当前分组模板列表”的工作方式,但改成更轻的卡片导航。"
>
{!groups.length && !loading ? ( {!groups.length && !loading ? (
<EmptyState <EmptyState
title="还没有流程监控分组" title="还没有流程监控分组"
...@@ -389,61 +433,71 @@ export default function ProcessMonitorPage() { ...@@ -389,61 +433,71 @@ export default function ProcessMonitorPage() {
} }
/> />
) : ( ) : (
<div className="flex flex-wrap gap-3"> <Tabs className="filter-tabs-wrap" selectedKey={activeGroup?.name || ''} onSelectionChange={(key) => setActiveGroupName(String(key))}>
{groups.map((group) => { <Tabs.ListContainer>
const active = activeGroup?.name === group.name; <Tabs.List aria-label="监控分组">
{groups.map((group) => (
return ( <Tabs.Tab id={group.name} key={group.name}>
<button {group.title}<Tabs.Indicator />
key={group.name} </Tabs.Tab>
type="button" ))}
onClick={() => setActiveGroupName(group.name)} </Tabs.List>
className={clsx( </Tabs.ListContainer>
'min-w-[180px] rounded-[22px] border px-4 py-3 text-left transition', </Tabs>
active
? 'border-teal-400 bg-teal-50 shadow-sm'
: 'border-slate-200 bg-white hover:border-sky-200 hover:bg-sky-50/50',
)} )}
> </section>
<div className="flex items-center justify-between gap-3"> {canManage ? (
<div className="truncate text-sm font-semibold text-slate-950">{group.title}</div> <div className="rc-tabs-command-actions">
<StatusPill tone={active ? 'sky' : 'default'}>{group.monitoredCount} 项</StatusPill> <Button outline onClick={() => setAddTemplateOpen(true)} disabled={!activeGroup || loading}>
添加监控模板
</Button>
<Button color="blue" onClick={() => setCreateGroupOpen(true)}>
新建分组
</Button>
</div> </div>
<div className="mt-2 text-xs text-slate-500">点击查看该分组下的流程模板监控清单</div> ) : null}
</button>
);
})}
</div> </div>
)}
</SectionCard>
<SectionCard <section className="rc-filter-card">
title={activeGroup ? `模板列表 · ${activeGroup.title}` : '模板列表'} <div className="rc-filter-form">
description="这里展示当前分组下已启用监控的流程模板,可继续进入实例列表与单条明细。" <div className="rc-filter-primary-row">
action={ <div className="rc-filter-primary-fields">
<div className="flex flex-wrap gap-3"> <label className="rc-filter-field">
<div className="relative min-w-[220px]"> <span className="rc-filter-label">模板标题</span>
<MagnifyingGlassIcon className="pointer-events-none absolute left-3 top-3 size-4 text-slate-400" /> <div className="rc-filter-control relative min-w-0">
<MagnifyingGlassIcon className="pointer-events-none absolute left-3 top-1/2 z-10 size-4 -translate-y-1/2 text-[var(--rc-text-muted)]" />
<Input <Input
value={templateKeyword} value={templateKeyword}
onChange={(event) => setTemplateKeyword(event.target.value)} onChange={(event) => setTemplateKeyword(event.target.value)}
placeholder="搜索模板标题" placeholder="搜索模板标题"
className="pl-9" className="rc-form-input"
/> />
</div> </div>
<div className="min-w-[180px]"> </label>
<Select value={departmentFilter} onChange={(event) => setDepartmentFilter(event.target.value)}> <label className="rc-filter-field">
<option value="">全部部门</option> <span className="rc-filter-label">所属部门</span>
{monitoredDepartmentOptions.map((option) => ( <FilterSelect aria-label="所属部门" value={departmentFilter} onChange={setDepartmentFilter} placeholder="全部部门" options={[{ label: '全部部门', value: '' }, ...monitoredDepartmentOptions]} />
<option key={option.value} value={option.value}> </label>
{option.label}
</option>
))}
</Select>
</div> </div>
<div className="rc-filter-actions">
<Tooltip delay={0}>
<HeroButton isIconOnly aria-label="重置筛选" className="rc-filter-reset-button" size="sm" variant="outline" onPress={() => { setTemplateKeyword(''); setDepartmentFilter(''); }}><Reload size={15} /></HeroButton>
<Tooltip.Content>重置筛选</Tooltip.Content>
</Tooltip>
<HeroButton className="rc-filter-query-button" size="sm" variant="primary">查询</HeroButton>
</div> </div>
} </div>
> </div>
</section>
<div className="rc-list-action-bar">
<div className="flex items-center gap-2">
<h2>{activeGroup ? `模板列表 · ${activeGroup.title}` : '模板列表'}</h2>
<TitleInfo label="模板列表" content="展示当前分组下已启用监控的流程模板,可进入实例列表和单条明细。" />
</div>
</div>
<section className="rc-list-data-grid">
{loading ? ( {loading ? (
<div className="rounded-[24px] border border-slate-200 bg-slate-50/70 px-6 py-10 text-sm text-slate-500"> <div className="rounded-[24px] border border-slate-200 bg-slate-50/70 px-6 py-10 text-sm text-slate-500">
正在加载流程监控列表... 正在加载流程监控列表...
...@@ -461,71 +515,51 @@ export default function ProcessMonitorPage() { ...@@ -461,71 +515,51 @@ export default function ProcessMonitorPage() {
} }
/> />
) : ( ) : (
<Table bleed striped grid> <DataGrid
<TableHead> aria-label="流程监控模板列表"
<TableRow> className="pm-data-grid"
<TableHeader>模板名称</TableHeader> columns={listColumns}
<TableHeader>所属部门</TableHeader> contentClassName="min-w-[1074px]"
<TableHeader>模板编码</TableHeader> data={pagedTemplates}
<TableHeader>显示条件</TableHeader> getRowId={(template) => template._id || template.name}
<TableHeader>状态</TableHeader> scrollContainerClassName="pm-data-grid-scroll"
{canManage ? <TableHeader>操作</TableHeader> : null} verticalAlign="middle"
</TableRow> />
</TableHead>
<TableBody>
{filteredTemplates.map((template) => (
<TableRow key={template._id || template.name}>
<TableCell>
<div className="space-y-1">
<Link
to={`/process_monitor/${template._id}?tab=${activeGroup?.name || ''}`}
className="font-medium text-slate-950 transition hover:text-teal-700"
>
{template.title}
</Link>
<div className="text-xs text-slate-500">
外部模板 ID:{template?.metadata?.external_id || '-'}
</div>
</div>
</TableCell>
<TableCell>{template?.metadata?.department || '-'}</TableCell>
<TableCell>{template?.metadata?.template_code || '-'}</TableCell>
<TableCell>
{template?.metadata?.conditions?.key ? (
<div className="text-sm text-slate-600">
{template.metadata.conditions.key} = {template.metadata.conditions.value || '-'}
</div>
) : (
'-'
)} )}
</TableCell> </section>
<TableCell>
<StatusPill tone="emerald">监控中</StatusPill> {!loading && filteredTemplates.length ? (
</TableCell> <div className="pm-pagination-bar">
{canManage ? ( <Pagination size="sm" className="w-full">
<TableCell> <Pagination.Summary>
<div className="flex flex-wrap gap-2"> 共 {filteredTemplates.length} 条,第 {listPage + 1} / {listTotalPages} 页
<Button plain onClick={() => openEditDialog(template)}> </Pagination.Summary>
<PencilSquareIcon data-slot="icon" /> <Pagination.Content>
编辑 <Pagination.Item>
</Button> <Pagination.Previous isDisabled={listPage <= 0} onPress={() => setListPage((page) => Math.max(0, page - 1))}>
<Button plain color="red" onClick={() => setRemoveTarget(template)}> <Pagination.PreviousIcon /><span>上一页</span>
<TrashIcon data-slot="icon" /> </Pagination.Previous>
取消监控 </Pagination.Item>
</Button> {Array.from({ length: listTotalPages }, (_, pageIndex) => (
<Pagination.Item key={pageIndex}>
<Pagination.Link isActive={pageIndex === listPage} onPress={() => setListPage(pageIndex)}>{pageIndex + 1}</Pagination.Link>
</Pagination.Item>
))}
<Pagination.Item>
<Pagination.Next isDisabled={listPage + 1 >= listTotalPages} onPress={() => setListPage((page) => Math.min(listTotalPages - 1, page + 1))}>
<span>下一页</span><Pagination.NextIcon />
</Pagination.Next>
</Pagination.Item>
</Pagination.Content>
</Pagination>
<div className="w-28 shrink-0">
<FilterSelect aria-label="每页条数" value={String(listPageSize)} onChange={(value) => setListPageSize(Number(value))} options={[10, 20, 50].map((value) => ({ label: `${value} 条/页`, value: String(value) }))} />
</div>
</div> </div>
</TableCell>
) : null} ) : null}
</TableRow>
))}
</TableBody>
</Table>
)}
</SectionCard>
<Dialog open={createGroupOpen} onClose={setCreateGroupOpen}> <Dialog open={createGroupOpen} onClose={setCreateGroupOpen}>
<DialogTitle>新建流程监控分组</DialogTitle> <DialogTitle>新建流程监控分组</DialogTitle>
<DialogDescription>分组用于承载一组需要一起观察的流程模板。</DialogDescription>
<DialogBody> <DialogBody>
<FieldGroup> <FieldGroup>
<Field> <Field>
...@@ -559,8 +593,15 @@ export default function ProcessMonitorPage() { ...@@ -559,8 +593,15 @@ export default function ProcessMonitorPage() {
}} }}
size="3xl" size="3xl"
> >
<DialogTitle>添加流程监控模板</DialogTitle> <DialogTitle>
<DialogDescription>从同步模板库中选择一个或多个模板,加入当前分组的监控范围。</DialogDescription> <span className="inline-flex items-center gap-1.5">
<span>添加流程监控模板</span>
<TitleInfo
label="添加流程监控模板"
content="从同步模板库中选择一个或多个模板,加入当前分组的监控范围。"
/>
</span>
</DialogTitle>
<DialogBody> <DialogBody>
<div className="space-y-4"> <div className="space-y-4">
<Input <Input
...@@ -625,7 +666,7 @@ export default function ProcessMonitorPage() { ...@@ -625,7 +666,7 @@ export default function ProcessMonitorPage() {
<Dialog open={editTemplateOpen} onClose={setEditTemplateOpen} size="2xl"> <Dialog open={editTemplateOpen} onClose={setEditTemplateOpen} size="2xl">
<DialogTitle>编辑模板监控配置</DialogTitle> <DialogTitle>编辑模板监控配置</DialogTitle>
<DialogDescription>延续旧版的部门、模板编码和显示条件配置逻辑。</DialogDescription> <DialogDescription>配置模板所属部门、模板编码和显示条件。</DialogDescription>
<DialogBody> <DialogBody>
<FieldGroup> <FieldGroup>
<Field> <Field>
......
...@@ -6,17 +6,14 @@ import { ...@@ -6,17 +6,14 @@ import {
DialogDescription, DialogDescription,
DialogTitle, DialogTitle,
} from '@/catalyst-ui-kit/javascript/dialog'; } from '@/catalyst-ui-kit/javascript/dialog';
import { Field, FieldGroup, Label } from '@/catalyst-ui-kit/javascript/fieldset';
import { Input } from '@/catalyst-ui-kit/javascript/input'; import { Input } from '@/catalyst-ui-kit/javascript/input';
import { Select } from '@/catalyst-ui-kit/javascript/select'; import FilterSelect from '@/components/FilterSelect';
import { import DetailNavigation from '@/components/DetailNavigation';
Table, import { TitleInfo } from '@/components/XinyuanUi';
TableBody, import { DataStore, Delete, FieldTime, FileText, Filter, Reload } from '@/components/AppIcons';
TableCell, import { Button as HeroButton, Input as HeroInput, Tooltip } from '@heroui/react';
TableHead, import { Pagination } from '@heroui/react/pagination';
TableHeader, import { DataGrid } from '@heroui-pro/react/data-grid';
TableRow,
} from '@/catalyst-ui-kit/javascript/table';
import { import {
buildDepartmentLookup, buildDepartmentLookup,
buildMemberLookup, buildMemberLookup,
...@@ -29,23 +26,18 @@ import { ...@@ -29,23 +26,18 @@ import {
queryProcessInstances, queryProcessInstances,
updateTemplateDisplayFields, updateTemplateDisplayFields,
} from '@/pages/process_monitor/processMonitorService'; } from '@/pages/process_monitor/processMonitorService';
import { import { MagnifyingGlassIcon } from '@heroicons/react/24/outline';
ArrowLeftIcon,
ArrowDownTrayIcon,
MagnifyingGlassIcon,
PlusIcon,
TrashIcon,
} from '@heroicons/react/24/outline';
import { useEffect, useMemo, useState } from 'react'; import { useEffect, useMemo, useState } from 'react';
import { Link, useParams, useSearchParams } from 'umi'; import { Link, useParams, useSearchParams } from 'umi';
import clsx from 'clsx';
function SectionCard({ title, description, action, children }) { function SectionCard({ title, description, action, children }) {
return ( return (
<section className="rounded-[28px] border border-slate-200/80 bg-white/92 p-5 shadow-sm"> <section className="rounded-[28px] border border-slate-200/80 bg-white/92 p-5 shadow-sm">
<div className="flex flex-wrap items-start justify-between gap-4"> <div className="flex flex-wrap items-start justify-between gap-4">
<div> <div className="flex items-center gap-2">
<h2 className="text-lg font-semibold text-slate-950">{title}</h2> <h2 className="text-lg font-semibold text-slate-950">{title}</h2>
{description ? <p className="mt-1 text-sm text-slate-500">{description}</p> : null} <TitleInfo label={title} content={description} />
</div> </div>
{action} {action}
</div> </div>
...@@ -60,18 +52,34 @@ function StatusNotice({ message }) { ...@@ -60,18 +52,34 @@ function StatusNotice({ message }) {
} }
return ( return (
<div className="rounded-2xl border border-emerald-200 bg-emerald-50 px-4 py-3 text-sm text-emerald-700"> <div className="rc-status-toast rc-status-toast--success" role="status" aria-live="polite">
{message} {message}
</div> </div>
); );
} }
function SummaryCard({ label, value, hint }) { function createFieldDraft(field = {}) {
return {
...field,
_key: field._key || `${Date.now()}-${Math.random().toString(36).slice(2)}`,
display_name: field.display_name || '',
type: field.type || 'text',
};
}
function SummaryCard({ label, value, hint, icon: Icon, tone }) {
return ( return (
<div className="rounded-[24px] border border-slate-200/80 bg-[linear-gradient(180deg,rgba(255,255,255,0.94),rgba(240,249,255,0.94))] p-5 shadow-sm"> <div className="rc-card-surface rc-dashboard-card flex min-h-32 items-center justify-between gap-5 border border-[var(--rc-border-default)] p-5">
<div className="text-xs font-semibold uppercase tracking-[0.22em] text-slate-400">{label}</div> <div className="min-w-0">
<div className="mt-3 text-3xl font-semibold tracking-tight text-slate-950">{value}</div> <div className="flex items-center gap-2 text-xs font-semibold uppercase tracking-[0.16em] text-[var(--rc-text-muted)]">
<div className="mt-2 text-sm text-slate-500">{hint}</div> <span>{label}</span>
<TitleInfo label={label} content={hint} />
</div>
<div className="mt-3 text-3xl font-semibold tracking-tight text-[var(--rc-text-primary)]">{value}</div>
</div>
<div className={clsx('rc-metric-icon-surface', `rc-tone-surface--${tone}`)}>
<Icon size={20} />
</div>
</div> </div>
); );
} }
...@@ -111,7 +119,7 @@ function renderFieldValue(fieldDefinition, record, lookups, onDownload) { ...@@ -111,7 +119,7 @@ function renderFieldValue(fieldDefinition, record, lookups, onDownload) {
key={`${file.fileUrl || file.url}-${file.filename}`} key={`${file.fileUrl || file.url}-${file.filename}`}
type="button" type="button"
onClick={() => onDownload(file)} onClick={() => onDownload(file)}
className="rounded-full bg-sky-50 px-2.5 py-1 text-xs font-medium text-sky-700 transition hover:bg-sky-100" className="rc-status-chip rc-status-chip--info transition hover:border-[var(--rc-brand-primary)]"
> >
{file.filename || file.fileName || '附件'} {file.filename || file.fileName || '附件'}
</button> </button>
...@@ -196,6 +204,12 @@ export default function ProcessTemplateListPage() { ...@@ -196,6 +204,12 @@ export default function ProcessTemplateListPage() {
}); });
}, [page, pageSize, keyword, conditions]); }, [page, pageSize, keyword, conditions]);
useEffect(() => {
if (!message) return undefined;
const timer = window.setTimeout(() => setMessage(''), 3500);
return () => window.clearTimeout(timer);
}, [message]);
const lookups = useMemo( const lookups = useMemo(
() => ({ () => ({
memberLookup: buildMemberLookup(members), memberLookup: buildMemberLookup(members),
...@@ -206,12 +220,42 @@ export default function ProcessTemplateListPage() { ...@@ -206,12 +220,42 @@ export default function ProcessTemplateListPage() {
const totalPages = Math.max(Math.ceil(total / pageSize), 1); const totalPages = Math.max(Math.ceil(total / pageSize), 1);
const openFieldDialog = () => { const instanceColumns = useMemo(
setFieldDrafts( () => [
normalizeDisplayFieldDefinitions(fieldsDefinition).length {
? normalizeDisplayFieldDefinitions(fieldsDefinition) id: 'title',
: [{ display_name: '', type: 'text' }], header: '表单名称',
isRowHeader: true,
width: 260,
minWidth: 220,
pinned: 'start',
cell: (record) => (
<Link
to={`/process_monitor/${processId}/${record._id}?tab=${tabName}`}
className="pm-data-grid-primary rc-data-grid-title-link"
>
{record.title}
</Link>
),
},
...fieldsDefinition.map((field) => ({
id: `${field.display_name}-${field.type}`,
header: field.display_name,
width: 220,
minWidth: 180,
cell: (record) => (
<span className="pm-data-grid-text">
{renderFieldValue(field, record, lookups, downloadProcessAttachment)}
</span>
),
})),
],
[fieldsDefinition, lookups, processId, tabName],
); );
const openFieldDialog = () => {
const normalizedFields = normalizeDisplayFieldDefinitions(fieldsDefinition);
setFieldDrafts((normalizedFields.length ? normalizedFields : [{}]).map(createFieldDraft));
setFieldDialogOpen(true); setFieldDialogOpen(true);
}; };
...@@ -249,62 +293,49 @@ export default function ProcessTemplateListPage() { ...@@ -249,62 +293,49 @@ export default function ProcessTemplateListPage() {
}; };
return ( return (
<div className="space-y-6"> <div className="rc-page-stack">
<div className="flex flex-wrap items-center gap-3 text-sm text-slate-500"> <div className="rc-detail-toolbar">
<Link <DetailNavigation
to={tabName ? `/process_monitor?tab=${tabName}` : '/process_monitor'} backHref={tabName ? `/process_monitor?tab=${tabName}` : '/process_monitor'}
className="inline-flex items-center gap-2 rounded-full border border-slate-200 bg-white px-3 py-1.5 font-medium text-slate-600 transition hover:border-sky-200 hover:text-sky-700" backLabel="返回流程监控"
> currentLabel={template?.title || '模板实例列表'}
<ArrowLeftIcon className="size-4" /> items={[{ label: '流程监控', href: tabName ? `/process_monitor?tab=${tabName}` : '/process_monitor' }]}
返回流程监控 />
</Link> <div className="rc-page-command-bar">
<span>/</span>
<span>{template?.title || '模板实例列表'}</span>
</div>
<section className="overflow-hidden rounded-[32px] border border-slate-200/70 bg-[linear-gradient(135deg,rgba(15,118,110,0.10),rgba(14,165,233,0.12))] px-6 py-7 shadow-sm sm:px-8">
<div className="flex flex-wrap items-start justify-between gap-4">
<div className="max-w-3xl">
<h1 className="text-3xl font-semibold tracking-tight text-slate-950 sm:text-4xl">
{template?.title || '流程模板监控'}
</h1>
<p className="mt-3 text-sm leading-6 text-slate-600 sm:text-base">
这里复刻旧版 `ProcessList` 的模板实例追踪逻辑,包括动态显示字段、关键字检索和附件批量下载。
</p>
</div>
<div className="flex flex-wrap gap-3"> <div className="flex flex-wrap gap-3">
<Button outline onClick={handleDownloadAll} disabled={downloading || loading}> <Button outline onClick={handleDownloadAll} disabled={downloading || loading}>
<ArrowDownTrayIcon data-slot="icon" />
批量下载附件 批量下载附件
</Button> </Button>
<Button color="blue" onClick={openFieldDialog} disabled={loading}> <Button color="blue" onClick={openFieldDialog} disabled={loading}>
<PlusIcon data-slot="icon" />
定义显示字段 定义显示字段
</Button> </Button>
</div> </div>
</div> </div>
</section> </div>
<StatusNotice message={message} /> <StatusNotice message={message} />
<div className="grid gap-4 lg:grid-cols-4"> <div className="grid gap-4 lg:grid-cols-4">
<SummaryCard label="模板实例" value={total} hint="当前模板下命中的提交流程数量" /> <SummaryCard label="模板实例" value={total} hint="当前模板下命中的提交流程数量" icon={DataStore} tone="info" />
<SummaryCard label="显示字段" value={fieldsDefinition.length} hint="由模板配置决定表格展开的动态列" /> <SummaryCard label="显示字段" value={fieldsDefinition.length} hint="由模板配置决定表格展开的动态列" icon={FileText} tone="success" />
<SummaryCard <SummaryCard
label="条件筛选" label="条件筛选"
value={conditions?.key ? '已启用' : '未启用'} value={conditions?.key ? '已启用' : '未启用'}
hint={conditions?.key ? `${conditions.key} = ${conditions.value || '-'}` : '当前没有预设显示条件'} hint={conditions?.key ? `${conditions.key} = ${conditions.value || '-'}` : '当前没有预设显示条件'}
icon={Filter}
tone="warning"
/> />
<SummaryCard label="分页设置" value={pageSize} hint={`当前第 ${page} / ${totalPages} 页`} /> <SummaryCard label="分页设置" value={pageSize} hint={`当前第 ${page} / ${totalPages} 页`} icon={FieldTime} tone="teal" />
</div> </div>
<SectionCard <section className="rc-filter-card">
title="实例列表" <div className="rc-filter-form">
description="按模板展示实际提交的流程实例,点击表单名称进入单条详情。" <div className="rc-filter-primary-row">
action={ <div className="rc-filter-primary-fields">
<div className="flex flex-wrap gap-3"> <label className="rc-filter-field">
<div className="relative min-w-[240px]"> <span className="rc-filter-label">表单名称</span>
<MagnifyingGlassIcon className="pointer-events-none absolute left-3 top-3 size-4 text-slate-400" /> <div className="rc-filter-control relative min-w-0">
<MagnifyingGlassIcon className="pointer-events-none absolute left-3 top-1/2 z-10 size-4 -translate-y-1/2 text-[var(--rc-text-muted)]" />
<Input <Input
value={keyword} value={keyword}
onChange={(event) => { onChange={(event) => {
...@@ -312,100 +343,110 @@ export default function ProcessTemplateListPage() { ...@@ -312,100 +343,110 @@ export default function ProcessTemplateListPage() {
setKeyword(event.target.value); setKeyword(event.target.value);
}} }}
placeholder="搜索表单名称" placeholder="搜索表单名称"
className="pl-9" className="rc-form-input"
/> />
</div> </div>
<Select </label>
value={String(pageSize)}
onChange={(event) => {
setPage(1);
setPageSize(Number(event.target.value));
}}
>
{[10, 20, 50, 100].map((value) => (
<option key={value} value={String(value)}>
每页 {value} 条
</option>
))}
</Select>
</div> </div>
} <div className="rc-filter-actions">
> <Tooltip delay={0}>
<HeroButton isIconOnly aria-label="重置筛选" className="rc-filter-reset-button" size="sm" variant="outline" onPress={() => { setKeyword(''); setPage(1); }}>
<Reload size={15} />
</HeroButton>
<Tooltip.Content>重置筛选</Tooltip.Content>
</Tooltip>
</div>
</div>
</div>
</section>
<div className="rc-list-action-bar">
<div className="flex items-center gap-2"><h2>实例列表</h2><TitleInfo label="实例列表" content="按模板展示实际提交的流程实例,点击表单名称进入单条详情。" /></div>
</div>
<section className="rc-list-data-grid">
{loading ? ( {loading ? (
<div className="rounded-[24px] border border-slate-200 bg-slate-50/70 px-6 py-10 text-sm text-slate-500"> <div className="rounded-[24px] border border-slate-200 bg-slate-50/70 px-6 py-10 text-sm text-slate-500">
正在加载模板实例... 正在加载模板实例...
</div> </div>
) : ( ) : !instances.length ? (
<div className="space-y-4"> <div className="data-grid-empty-state rounded-[var(--rc-data-grid-radius)] border border-dashed border-[var(--rc-border-default)] bg-[var(--rc-bg-surface)] text-center text-sm text-[var(--rc-text-muted)]">
<Table bleed striped grid>
<TableHead>
<TableRow>
<TableHeader>表单名称</TableHeader>
{fieldsDefinition.map((field) => (
<TableHeader key={`${field.display_name}-${field.type}`}>
{field.display_name}
</TableHeader>
))}
</TableRow>
</TableHead>
<TableBody>
{instances.map((record) => (
<TableRow key={record._id || record.name}>
<TableCell>
<Link
to={`/process_monitor/${processId}/${record._id}?tab=${tabName}`}
className="font-medium text-slate-950 transition hover:text-teal-700"
>
{record.title}
</Link>
</TableCell>
{fieldsDefinition.map((field) => (
<TableCell key={`${record._id}-${field.display_name}`}>
{renderFieldValue(field, record, lookups, downloadProcessAttachment)}
</TableCell>
))}
</TableRow>
))}
</TableBody>
</Table>
{!instances.length ? (
<div className="rounded-[24px] border border-dashed border-slate-300 bg-slate-50/60 px-6 py-10 text-center text-sm text-slate-500">
当前筛选条件下没有找到流程实例。 当前筛选条件下没有找到流程实例。
</div> </div>
) : null} ) : (
<DataGrid
aria-label="流程实例列表"
className="pm-data-grid"
columns={instanceColumns}
contentClassName="min-w-[760px]"
data={instances}
getRowId={(record) => record._id || record.name}
scrollContainerClassName="pm-data-grid-scroll"
verticalAlign="middle"
/>
)}
</section>
<div className="flex flex-wrap items-center justify-between gap-3 rounded-2xl border border-slate-200 bg-slate-50/70 px-4 py-3 text-sm text-slate-600"> {!loading ? (
<div> <div className="pm-pagination-bar">
共 {total} 条,当前第 {page} / {totalPages} 页 <Pagination size="sm" className="w-full">
</div> <Pagination.Summary>共 {total} 条,第 {page} / {totalPages} 页</Pagination.Summary>
<div className="flex gap-2"> <Pagination.Content>
<Button outline onClick={() => setPage((current) => Math.max(current - 1, 1))} disabled={page <= 1}> <Pagination.Item>
上一页 <Pagination.Previous isDisabled={page <= 1} onPress={() => setPage((current) => Math.max(current - 1, 1))}>
</Button> <Pagination.PreviousIcon /><span>上一页</span>
<Button </Pagination.Previous>
outline </Pagination.Item>
onClick={() => setPage((current) => Math.min(current + 1, totalPages))} {Array.from({ length: totalPages }, (_, index) => index + 1).map((pageNumber) => (
disabled={page >= totalPages} <Pagination.Item key={pageNumber}>
> <Pagination.Link isActive={pageNumber === page} onPress={() => setPage(pageNumber)}>{pageNumber}</Pagination.Link>
下一页 </Pagination.Item>
</Button> ))}
</div> <Pagination.Item>
<Pagination.Next isDisabled={page >= totalPages} onPress={() => setPage((current) => Math.min(current + 1, totalPages))}>
<span>下一页</span><Pagination.NextIcon />
</Pagination.Next>
</Pagination.Item>
</Pagination.Content>
</Pagination>
<div className="w-28 shrink-0">
<FilterSelect
aria-label="每页条数"
value={String(pageSize)}
onChange={(value) => {
setPage(1);
setPageSize(Number(value));
}}
options={[10, 20, 50].map((value) => ({ label: `${value} 条/页`, value: String(value) }))}
/>
</div> </div>
</div> </div>
)} ) : null}
</SectionCard>
<Dialog open={fieldDialogOpen} onClose={setFieldDialogOpen} size="3xl"> <Dialog open={fieldDialogOpen} onClose={setFieldDialogOpen} size="3xl">
<DialogTitle>定义显示字段</DialogTitle> <DialogTitle>
<DialogDescription>保持旧版能力,允许为当前监控模板指定实例表格要展开的字段列。</DialogDescription> <span className="inline-flex items-center gap-1.5">
<span>定义显示字段</span>
<TitleInfo label="定义显示字段" content="为当前监控模板指定实例表格需要展示的字段列。" />
</span>
</DialogTitle>
<DialogBody> <DialogBody>
<FieldGroup> <div className="rc-field-editor">
<div className="rc-field-editor__header" aria-hidden="true">
<span>字段名</span>
<span>字段类型</span>
<span className="sr-only">操作</span>
</div>
<div className="rc-field-editor__rows">
{fieldDrafts.map((field, index) => ( {fieldDrafts.map((field, index) => (
<div key={`${index}-${field.display_name}`} className="grid gap-4 rounded-2xl border border-slate-200 bg-slate-50/60 p-4 sm:grid-cols-[1.4fr_1fr_auto]"> <div key={field._key} className="rc-field-editor__row">
<Field> <label className="rc-field-editor__cell">
<Label>字段名</Label> <span className="rc-field-editor__mobile-label">字段名</span>
<Input <HeroInput
aria-label={`字段 ${index + 1} 名称`}
className="rc-field-editor__input"
fullWidth
variant="secondary"
value={field.display_name} value={field.display_name}
onChange={(event) => onChange={(event) =>
setFieldDrafts((current) => setFieldDrafts((current) =>
...@@ -418,51 +459,55 @@ export default function ProcessTemplateListPage() { ...@@ -418,51 +459,55 @@ export default function ProcessTemplateListPage() {
} }
placeholder="例如:提交人" placeholder="例如:提交人"
/> />
</Field> </label>
<Field> <label className="rc-field-editor__cell">
<Label>字段类型</Label> <span className="rc-field-editor__mobile-label">字段类型</span>
<Select <FilterSelect
aria-label={`字段 ${index + 1} 类型`}
className="rc-field-editor__select"
value={field.type} value={field.type}
onChange={(event) => onChange={(value) =>
setFieldDrafts((current) => setFieldDrafts((current) =>
current.map((item, itemIndex) => current.map((item, itemIndex) =>
itemIndex === index ? { ...item, type: event.target.value } : item, itemIndex === index ? { ...item, type: value } : item,
), ),
) )
} }
options={[
{ label: '文本', value: 'text' },
{ label: '人员', value: 'member' },
{ label: '部门', value: 'department' },
{ label: '日期', value: 'date' },
{ label: '附件', value: 'attachment' },
]}
/>
</label>
<Tooltip delay={0}>
<HeroButton
isIconOnly
aria-label={`删除字段 ${index + 1}`}
className="rc-field-editor__delete"
size="sm"
variant="danger-soft"
onPress={() => setFieldDrafts((current) => current.filter((_, itemIndex) => itemIndex !== index))}
> >
<option value="text">文本</option> <Delete size={16} />
<option value="member">人员</option> </HeroButton>
<option value="department">部门</option> <Tooltip.Content>删除字段</Tooltip.Content>
<option value="date">日期</option> </Tooltip>
<option value="attachment">附件</option>
</Select>
</Field>
<div className="flex items-end">
<Button
plain
color="red"
onClick={() =>
setFieldDrafts((current) => current.filter((_, itemIndex) => itemIndex !== index))
}
>
<TrashIcon data-slot="icon" />
删除
</Button>
</div>
</div> </div>
))} ))}
</FieldGroup> {!fieldDrafts.length ? <div className="rc-field-editor__empty">暂未添加显示字段</div> : null}
<div className="mt-4"> </div>
<Button <HeroButton
outline className="rc-field-editor__add"
onClick={() => fullWidth
setFieldDrafts((current) => [...current, { display_name: '', type: 'text' }]) size="sm"
} variant="outline"
onPress={() => setFieldDrafts((current) => [...current, createFieldDraft()])}
> >
<PlusIcon data-slot="icon" />
添加字段 添加字段
</Button> </HeroButton>
</div> </div>
</DialogBody> </DialogBody>
<DialogActions> <DialogActions>
......
@import 'tailwindcss'; @import 'tailwindcss';
@import '@heroui/styles';
@import '@heroui-pro/react/css';
@import './design-system/tokens.css';
@import './design-system/shell.css';
@import './design-system/components.css';
@theme {
--font-sans: var(--rc-font-sans);
}
:root {
--pm-brand: var(--rc-brand-primary);
--pm-brand-strong: var(--rc-brand-dark);
--rc-page-title-inset: 68px;
color-scheme: light;
}
html.dark,
html[data-theme='dark'] {
color-scheme: dark;
}
body {
margin: 0;
font-family: var(--rc-font-sans);
color: var(--rc-text-primary);
background: var(--rc-bg-canvas);
}
/* Legacy utility bridge: keep behavior while unifying the visible palette. */
body :is(.text-sky-500,.text-sky-600,.text-sky-700,.text-teal-600,.text-teal-700,.text-rose-500,.text-rose-600) {
color: var(--rc-brand-primary) !important;
}
body :is(.bg-sky-50,.bg-sky-100,.bg-teal-50,.bg-teal-100,.bg-rose-50) {
background-color: var(--rc-brand-primary-soft) !important;
}
body :is(.border-sky-200,.border-sky-300,.border-teal-200,.border-rose-200) {
border-color: var(--rc-brand-primary-border) !important;
}
body [class*='from-teal-'],
body [class*='to-sky-'],
body [class*='linear-gradient(135deg,rgba(15,118,110'] {
background-image: none !important;
background-color: var(--rc-bg-surface) !important;
color: var(--rc-text-primary) !important;
}
body :is([class*='rounded-[32px]'],[class*='rounded-[28px]'],[class*='rounded-[24px]']) {
border-radius: var(--rc-radius-module) !important;
}
body [class*='shadow-[0_20px_60px'] {
box-shadow: var(--rc-shadow-card) !important;
}
@media (max-width: 767px) {
:root { --rc-page-title-inset: 72px; }
}
.rc-page-stack {
display: flex;
min-width: 0;
flex-direction: column;
gap: var(--rc-space-4);
}
.rc-page-command-bar,
.rc-list-action-bar {
display: flex;
min-width: 0;
align-items: center;
justify-content: flex-end;
gap: var(--rc-space-3);
background: transparent;
}
.rc-list-action-bar {
justify-content: space-between;
padding-top: var(--rc-space-1);
}
.rc-list-action-bar h2 {
margin: 0;
color: var(--rc-text-primary);
font-size: var(--rc-text-md);
font-weight: var(--rc-font-semibold);
line-height: 1.5rem;
}
.rc-breadcrumb-row {
display: flex;
min-width: 0;
flex-wrap: wrap;
align-items: center;
gap: var(--rc-space-2);
color: var(--rc-text-muted);
font-size: var(--rc-text-sm);
}
.rc-breadcrumb-row a {
display: inline-flex;
align-items: center;
gap: var(--rc-space-2);
padding: 0;
border: 0;
background: transparent;
color: var(--rc-text-secondary);
font-weight: var(--rc-font-medium);
text-decoration: none;
}
.rc-breadcrumb-row a:hover {
color: var(--rc-brand-primary);
}
.rc-filter-card {
padding: var(--rc-space-5);
overflow: visible;
border: 1px solid var(--rc-border-default);
border-radius: 1rem;
background: var(--rc-bg-surface);
box-shadow: var(--rc-shadow-card);
}
.rc-filter-field {
display: grid;
min-width: 0;
gap: var(--rc-space-2);
}
.rc-filter-primary-fields {
grid-template-columns: minmax(14rem, 1.5fr) minmax(12rem, 1fr);
}
.rc-list-table-shell {
min-width: 0;
overflow-x: auto;
border: 1px solid var(--rc-border-default);
border-radius: var(--rc-data-grid-radius);
background: var(--rc-bg-surface);
box-shadow: none;
}
.rc-detail-status:empty {
display: none;
}
.rc-detail-section {
display: grid;
min-width: 0;
gap: var(--rc-space-3);
}
body .login-captcha-row {
display: grid;
width: 100%;
align-items: stretch;
gap: 0.75rem;
grid-template-columns: minmax(0, 1fr) 10.5rem;
}
body .login-card-brand {
display: flex !important;
flex-direction: row !important;
align-items: center !important;
justify-content: center !important;
gap: 0.875rem !important;
}
body .login-captcha-button.button {
width: 100% !important;
min-width: 0 !important;
height: var(--rc-login-control-height) !important;
min-height: var(--rc-login-control-height) !important;
padding: 0.1875rem 0.5rem !important;
overflow: hidden;
border: 1px solid var(--rc-button-secondary-border) !important;
border-radius: var(--rc-radius-control) !important;
background: #fff !important;
box-shadow: none !important;
}
body .login-captcha-button .captcha-image {
display: grid;
width: 100%;
height: 100%;
min-width: 0;
place-items: center;
overflow: hidden;
}
body .login-captcha-button .captcha-image :is(svg, img) {
display: block !important;
width: 100% !important;
max-width: 100% !important;
height: 100% !important;
max-height: 2.125rem !important;
margin: 0 !important;
object-fit: contain;
}
@media (max-width: 480px) {
body .login-captcha-row {
grid-template-columns: minmax(0, 1fr) 8.75rem;
}
}
.rc-business-table {
min-width: 60rem;
}
.rc-business-table thead tr {
background: var(--rc-data-grid-header-background) !important;
}
.rc-business-table th {
height: var(--rc-data-grid-header-height);
color: var(--rc-data-grid-header-color) !important;
font-size: var(--rc-data-grid-header-font-size) !important;
font-weight: var(--rc-data-grid-header-font-weight) !important;
text-transform: none !important;
letter-spacing: 0 !important;
}
.rc-business-table td {
color: var(--rc-data-grid-body-color);
font-size: var(--rc-data-grid-body-font-size);
}
.rc-list-pagination {
background: transparent !important;
}
.rc-pagination-pages button[aria-current='page'] {
color: var(--rc-brand-on-primary) !important;
background: var(--rc-brand-primary) !important;
border-radius: 0.625rem;
}
@media (max-width: 767px) {
.rc-page-command-bar,
.rc-list-action-bar {
align-items: stretch;
flex-direction: column;
}
.rc-page-command-bar > div,
.rc-filter-actions {
width: 100%;
}
.rc-filter-primary-fields {
grid-template-columns: minmax(0, 1fr);
}
}
@theme { @theme {
--font-sans: --font-sans:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment