@oj-module/runtime 0.2.8 → 0.2.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,4 +4,5 @@ export declare function useMenu(): {
4
4
  sideNavMenuKeyInSplitMode: string;
5
5
  topNavItems: import("./types").MenuItemType[];
6
6
  sideNavItems: import("./types").MenuItemType[];
7
+ bottomNavItems: import("./types").MenuItemType[];
7
8
  };
@@ -16,6 +16,11 @@ interface Props extends ButtonProps {
16
16
  * 消息列表
17
17
  */
18
18
  notifications?: NotificationItem[];
19
+ /**
20
+ * 弹层开合回调(容器用它做「打开即重拉」:清空可能发生在通知中心页等
21
+ * 别处,铃铛列表不重拉会一直展示已清空的消息)
22
+ */
23
+ onOpenChange?: (open: boolean) => void;
19
24
  }
20
25
  export declare const NotificationPopup: React.FC<Props>;
21
26
  export {};
@@ -6,6 +6,7 @@ import type { ButtonProps } from "antd";
6
6
  * (popup 按 onEventChange 是否存在推导,评审 A3——不加新 prop);
7
7
  * - 写操作成功后重拉刷新;**重拉失败不清空现有列表**(评审 b4);
8
8
  * - 20x 复制残留已删除(评审 b4,同一 id 复制 20 份会让 markRead 语义失真);
9
- * - viewAll 不接线(N3,模板无通知中心页)。
9
+ * - viewAll 由弹层内直接导航到通知中心页(N3 落地,不经过 provider——
10
+ * 本组件的 onEventChange 仍只承载写事件,read-only 推导不受影响)。
10
11
  */
11
12
  export declare function NotificationContainer({ ...restProps }: ButtonProps): import("#node_modules/@types/react").JSX.Element;
@@ -1,5 +1,13 @@
1
1
  import type { AppRouteRecordRaw } from "../types";
2
- /** 按照路由中 order 升序来排序路由 */
2
+ /**
3
+ * 按照路由中 order 升序来排序路由(双段序轴,2026-10-20):
4
+ * - order >= 0:主菜单区,升序在前;
5
+ * - order < 0 :底部固定区,升序在后(-2 在 -1 上面)——渲染层
6
+ * (layout-sidebar / layout-mixed-sidebar 第二列)把这一段 pin 在
7
+ * 侧边栏底部,其余菜单形态按列表末尾回落;
8
+ * - 未声明 order:沿用数组下标兜底(下标 + 2)。order: 0 是合法值,
9
+ * 用 ?? 判定(历史实现用 ||,0 会被误当「未设置」改写成兜底值)。
10
+ */
3
11
  export declare function ascending(arr: AppRouteRecordRaw[]): ({
4
12
  handle: {
5
13
  order: number;
@@ -0,0 +1,28 @@
1
+ import type { SolutionRouteRow } from "../../api/rbac/types";
2
+ import type { MenuItemType } from "../../layout/layout-menu/types";
3
+ /**
4
+ * 方案路由注册菜单归组(2026-10-21,docs/plans/2026-10-21-1028-solution-menu-grouping.md)。
5
+ *
6
+ * 纯函数、单一职责(SRP):只把已生成的菜单做"视觉层归组",不动路由树、不触碰
7
+ * i18n/翻译(组标题存裸 i18n key,交由渲染层 translateMenus 翻译)。跨列表操作
8
+ * (admin 项在 wholeMenus、`/system` 在 bottomMenus),故一次调用吃两段菜单。
9
+ *
10
+ * 依赖倒置(DIP):告警通道 onWarn 由调用方注入,缺省为模块级 warnOnce,便于单测
11
+ * 断言与生产环境接管。无副作用、不 mutate 入参(未变动项复用原引用,返回新数组)。
12
+ */
13
+ export interface GroupSolutionMenusOptions {
14
+ /** 宿主系统设置菜单 key,默认 "/system" */
15
+ systemKey?: string;
16
+ /** 告警回调;缺省走模块级 warnOnce(同消息只打一次) */
17
+ onWarn?: (msg: string) => void;
18
+ }
19
+ /**
20
+ * 归组入口。
21
+ *
22
+ * - 空表(未安装/端点失败)或无命中行 → 返回新数组(内容相等),开发形态不变;
23
+ * - 不 mutate 入参对象,未变动项复用原 menuItem 引用(仅重组数组与合成父项)。
24
+ */
25
+ export declare function groupSolutionMenus(top: MenuItemType[], bottom: MenuItemType[], rows: SolutionRouteRow[], opts?: GroupSolutionMenusOptions): {
26
+ top: MenuItemType[];
27
+ bottom: MenuItemType[];
28
+ };
@@ -11,7 +11,9 @@ export type AnnotatedRoute = AppRouteRecordRaw;
11
11
  * - 三值 category 原样落 handle.category(main=常规组、admin=管理组、hidden=不进菜单);
12
12
  * - hidden 与 enabled=0(禁用)复用既有 hideInMenu 通路——只过滤菜单层,路由仍可达
13
13
  * (禁用的路由摘除归装载层三处同写,D12);
14
- * - order 覆写为声明序:框架项保留 100 间隔带、方案项从 200 起编,共用一条序轴;
14
+ * - order 覆写为声明序(2026-10-20 双段序轴):框架常规项 ≥0 升序、管理面负数入
15
+ * 底部固定区(pin 侧边栏底部,ascending 双段排序)、方案项从 200 起编,共用一条序轴;
16
+ * 同 order 按根 path 字母序;
15
17
  * - 未匹配路由(框架/后端)原样保留(同一对象引用),入参不突变;
16
18
  * - solRoutes 为空(端点失败/未登录降级空表)时原样返回——降级不阻断,路由照常。
17
19
  *
package/dist/runtime.js CHANGED
@@ -2,7 +2,7 @@
2
2
  if (typeof document !== "undefined" && !document.querySelector("style[data-ojm-runtime-css]")) {
3
3
  const s = document.createElement("style");
4
4
  s.setAttribute("data-ojm-runtime-css", "");
5
- s.textContent = "\n@layer properties, reset, antd;\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n@layer reset{\n/* stylelint-disable */\nhtml,\nbody {\n width: 100%;\n height: 100%;\n}\ninput::-ms-clear,\ninput::-ms-reveal {\n display: none;\n}\n*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\nhtml {\n font-family: sans-serif;\n line-height: 1.15;\n -webkit-text-size-adjust: 100%;\n -ms-text-size-adjust: 100%;\n -ms-overflow-style: scrollbar;\n -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\n\nbody {\n margin: 0;\n}\n[tabindex='-1']:focus {\n outline: none;\n}\nhr {\n box-sizing: content-box;\n height: 0;\n overflow: visible;\n}\nh1,\nh2,\nh3,\nh4,\nh5,\nh6 {\n margin-top: 0;\n margin-bottom: 0.5em;\n font-weight: 500;\n}\np {\n margin-top: 0;\n margin-bottom: 1em;\n}\nabbr[title],\nabbr[data-original-title] {\n -webkit-text-decoration: underline dotted;\n text-decoration: underline dotted;\n border-bottom: 0;\n cursor: help;\n}\naddress {\n margin-bottom: 1em;\n font-style: normal;\n line-height: inherit;\n}\ninput[type='text'],\ninput[type='password'],\ninput[type='number'],\ntextarea {\n -webkit-appearance: none;\n}\nol,\nul,\ndl {\n margin-top: 0;\n margin-bottom: 1em;\n}\nol ol,\nul ul,\nol ul,\nul ol {\n margin-bottom: 0;\n}\ndt {\n font-weight: 500;\n}\ndd {\n margin-bottom: 0.5em;\n margin-left: 0;\n}\nblockquote {\n margin: 0 0 1em;\n}\ndfn {\n font-style: italic;\n}\nb,\nstrong {\n font-weight: bolder;\n}\nsmall {\n font-size: 80%;\n}\nsub,\nsup {\n position: relative;\n font-size: 75%;\n line-height: 0;\n vertical-align: baseline;\n}\nsub {\n bottom: -0.25em;\n}\nsup {\n top: -0.5em;\n}\npre,\ncode,\nkbd,\nsamp {\n font-size: 1em;\n font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace;\n}\npre {\n margin-top: 0;\n margin-bottom: 1em;\n overflow: auto;\n}\nfigure {\n margin: 0 0 1em;\n}\nimg {\n vertical-align: middle;\n border-style: none;\n}\na,\narea,\nbutton,\n[role='button'],\ninput:not([type='range']),\nlabel,\nselect,\nsummary,\ntextarea {\n touch-action: manipulation;\n}\ntable {\n border-collapse: collapse;\n}\ncaption {\n padding-top: 0.75em;\n padding-bottom: 0.3em;\n text-align: left;\n caption-side: bottom;\n}\ninput,\nbutton,\nselect,\noptgroup,\ntextarea {\n margin: 0;\n color: inherit;\n font-size: inherit;\n font-family: inherit;\n line-height: inherit;\n}\nbutton,\ninput {\n overflow: visible;\n}\nbutton,\nselect {\n text-transform: none;\n}\nbutton,\nhtml [type='button'],\n[type='reset'],\n[type='submit'] {\n -webkit-appearance: button;\n}\nbutton::-moz-focus-inner,\n[type='button']::-moz-focus-inner,\n[type='reset']::-moz-focus-inner,\n[type='submit']::-moz-focus-inner {\n padding: 0;\n border-style: none;\n}\ninput[type='radio'],\ninput[type='checkbox'] {\n box-sizing: border-box;\n padding: 0;\n}\ninput[type='date'],\ninput[type='time'],\ninput[type='datetime-local'],\ninput[type='month'] {\n -webkit-appearance: listbox;\n}\ntextarea {\n overflow: auto;\n resize: vertical;\n}\nfieldset {\n min-width: 0;\n margin: 0;\n padding: 0;\n border: 0;\n}\nlegend {\n display: block;\n width: 100%;\n max-width: 100%;\n margin-bottom: 0.5em;\n padding: 0;\n color: inherit;\n font-size: 1.5em;\n line-height: inherit;\n white-space: normal;\n}\nprogress {\n vertical-align: baseline;\n}\n[type='number']::-webkit-inner-spin-button,\n[type='number']::-webkit-outer-spin-button {\n height: auto;\n}\n[type='search'] {\n outline-offset: -2px;\n -webkit-appearance: none;\n}\n[type='search']::-webkit-search-cancel-button,\n[type='search']::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n::-webkit-file-upload-button {\n font: inherit;\n -webkit-appearance: button;\n}\noutput {\n display: inline-block;\n}\nsummary {\n display: list-item;\n}\ntemplate {\n display: none;\n}\n[hidden] {\n display: none !important;\n}\n}\n@layer simplebar{\n[data-simplebar]{position:relative;flex-direction:column;flex-wrap:wrap;justify-content:flex-start;align-content:flex-start;align-items:flex-start}.simplebar-wrapper{overflow:hidden;width:inherit;height:inherit;max-width:inherit;max-height:inherit}.simplebar-mask{direction:inherit;position:absolute;overflow:hidden;padding:0;margin:0;left:0;top:0;bottom:0;right:0;width:auto!important;height:auto!important;z-index:0}.simplebar-offset{direction:inherit!important;box-sizing:inherit!important;resize:none!important;position:absolute;top:0;left:0;bottom:0;right:0;padding:0;margin:0;-webkit-overflow-scrolling:touch}.simplebar-content-wrapper{direction:inherit;box-sizing:border-box!important;position:relative;display:block;height:100%;width:auto;max-width:100%;max-height:100%;overflow:auto;scrollbar-width:none;-ms-overflow-style:none}.simplebar-content-wrapper::-webkit-scrollbar,.simplebar-hide-scrollbar::-webkit-scrollbar{display:none;width:0;height:0}.simplebar-content:after,.simplebar-content:before{content:' ';display:table}.simplebar-placeholder{max-height:100%;max-width:100%;width:100%;pointer-events:none}.simplebar-height-auto-observer-wrapper{box-sizing:inherit!important;height:100%;width:100%;max-width:1px;position:relative;float:left;max-height:1px;overflow:hidden;z-index:-1;padding:0;margin:0;pointer-events:none;flex-grow:inherit;flex-shrink:0;flex-basis:0}.simplebar-height-auto-observer{box-sizing:inherit;display:block;opacity:0;position:absolute;top:0;left:0;height:1000%;width:1000%;min-height:1px;min-width:1px;overflow:hidden;pointer-events:none;z-index:-1}.simplebar-track{z-index:1;position:absolute;right:0;bottom:0;pointer-events:none;overflow:hidden}[data-simplebar].simplebar-dragging{pointer-events:none;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}[data-simplebar].simplebar-dragging .simplebar-content{pointer-events:none;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}[data-simplebar].simplebar-dragging .simplebar-track{pointer-events:all}.simplebar-scrollbar{position:absolute;left:0;right:0;min-height:10px}.simplebar-scrollbar:before{position:absolute;content:'';background:#000;border-radius:7px;left:2px;right:2px;opacity:0;transition:opacity .2s .5s linear}.simplebar-scrollbar.simplebar-visible:before{opacity:.5;transition-delay:0s;transition-duration:0s}.simplebar-track.simplebar-vertical{top:0;width:11px}.simplebar-scrollbar:before{top:2px;bottom:2px;left:2px;right:2px}.simplebar-track.simplebar-horizontal{left:0;height:11px}.simplebar-track.simplebar-horizontal .simplebar-scrollbar{right:auto;left:0;top:0;bottom:0;min-height:0;min-width:10px;width:auto}[data-simplebar-direction=rtl] .simplebar-track.simplebar-vertical{right:auto;left:0}.simplebar-dummy-scrollbar-size{direction:rtl;position:fixed;opacity:0;visibility:hidden;height:500px;width:500px;overflow-y:hidden;overflow-x:scroll;-ms-overflow-style:scrollbar!important}.simplebar-dummy-scrollbar-size>div{width:200%;height:200%;margin:10px 0}.simplebar-hide-scrollbar{position:fixed;left:0;visibility:hidden;overflow-y:scroll;scrollbar-width:none;-ms-overflow-style:none}\n}\n@layer simplebar {\n .simplebar-scrollbar:before {\n background-color: #909399;\n }\n\n .simplebar-content {\n height: 100%;\n }\n}\n\n#root {\n height: 100vh;\n}\n\nimg {\n max-width: 100%;\n height: auto;\n}\n\nhtml.color-blind-mode {\n --tw-invert: invert(100%);\n filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );\n}\n\nhtml.gray-mode {\n --tw-grayscale: grayscale(100%);\n filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );\n}\n\n@layer theme {\n :root, :host {\n --font-sans: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", \"Noto Sans\", Arial,\n sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";\n --spacing: .25rem;\n --container-md: 28rem;\n --text-xs: .75rem;\n --text-xs--line-height: calc(1 / .75);\n --text-sm: .875rem;\n --text-sm--line-height: calc(1.25 / .875);\n --text-lg: 1.125rem;\n --text-lg--line-height: calc(1.75 / 1.125);\n --text-xl: 1.25rem;\n --text-xl--line-height: calc(1.75 / 1.25);\n --text-2xl: 1.5rem;\n --text-2xl--line-height: calc(2 / 1.5);\n --text-3xl: 1.875rem;\n --text-3xl--line-height: calc(2.25 / 1.875);\n --font-weight-medium: 500;\n --font-weight-semibold: 600;\n --font-weight-bold: 700;\n --tracking-tight: -.025em;\n --radius-sm: .25rem;\n --radius-md: .375rem;\n --radius-xl: .75rem;\n --ease-in: cubic-bezier(.4, 0, 1, 1);\n --animate-spin: spin 1s linear infinite;\n --default-transition-duration: .15s;\n --default-transition-timing-function: cubic-bezier(.4, 0, .2, 1);\n --animate-wiggle: wiggle 1s both;\n --animate-bounce-in-down-out-up: bounce-in-down-out-up 4s ease-in-out 0s infinite;\n }\n}\n\n@layer base, components;\n\n@layer utilities {\n .visible {\n visibility: visible;\n }\n\n .absolute {\n position: absolute;\n }\n\n .fixed {\n position: fixed;\n }\n\n .relative {\n position: relative;\n }\n\n .static {\n position: static;\n }\n\n .top-0 {\n top: 0;\n }\n\n .top-1\\.5 {\n top: calc(var(--spacing) * 1.5);\n }\n\n .top-2 {\n top: calc(var(--spacing) * 2);\n }\n\n .top-3 {\n top: calc(var(--spacing) * 3);\n }\n\n .right-2 {\n right: calc(var(--spacing) * 2);\n }\n\n .right-3 {\n right: calc(var(--spacing) * 3);\n }\n\n .right-4 {\n right: calc(var(--spacing) * 4);\n }\n\n .bottom-0 {\n bottom: 0;\n }\n\n .bottom-3 {\n bottom: calc(var(--spacing) * 3);\n }\n\n .left-0 {\n left: 0;\n }\n\n .left-1\\/2 {\n left: 50%;\n }\n\n .left-3 {\n left: calc(var(--spacing) * 3);\n }\n\n .z-10 {\n z-index: 10;\n }\n\n .container {\n width: 100%;\n }\n\n @media (min-width: 480px) {\n .container {\n max-width: 480px;\n }\n }\n\n @media (min-width: 576px) {\n .container {\n max-width: 576px;\n }\n }\n\n @media (min-width: 768px) {\n .container {\n max-width: 768px;\n }\n }\n\n @media (min-width: 992px) {\n .container {\n max-width: 992px;\n }\n }\n\n @media (min-width: 1200px) {\n .container {\n max-width: 1200px;\n }\n }\n\n @media (min-width: 1600px) {\n .container {\n max-width: 1600px;\n }\n }\n\n .m-0 {\n margin: 0;\n }\n\n .m-152 {\n margin: calc(var(--spacing) * 152);\n }\n\n .mx-3 {\n margin-inline: calc(var(--spacing) * 3);\n }\n\n .mx-4 {\n margin-inline: calc(var(--spacing) * 4);\n }\n\n .mx-auto {\n margin-inline: auto;\n }\n\n .my-0 {\n margin-block: 0;\n }\n\n .my-1 {\n margin-block: var(--spacing);\n }\n\n .my-4 {\n margin-block: calc(var(--spacing) * 4);\n }\n\n .my-8 {\n margin-block: calc(var(--spacing) * 8);\n }\n\n .mt-2 {\n margin-top: calc(var(--spacing) * 2);\n }\n\n .mt-2\\.5 {\n margin-top: calc(var(--spacing) * 2.5);\n }\n\n .mt-4 {\n margin-top: calc(var(--spacing) * 4);\n }\n\n .mt-6 {\n margin-top: calc(var(--spacing) * 6);\n }\n\n .mr-2 {\n margin-right: calc(var(--spacing) * 2);\n }\n\n .mr-3 {\n margin-right: calc(var(--spacing) * 3);\n }\n\n .mr-8 {\n margin-right: calc(var(--spacing) * 8);\n }\n\n .mr-17 {\n margin-right: calc(var(--spacing) * 17);\n }\n\n .mb-0 {\n margin-bottom: 0;\n }\n\n .mb-2 {\n margin-bottom: calc(var(--spacing) * 2);\n }\n\n .mb-3 {\n margin-bottom: calc(var(--spacing) * 3);\n }\n\n .mb-6 {\n margin-bottom: calc(var(--spacing) * 6);\n }\n\n .ml-2 {\n margin-left: calc(var(--spacing) * 2);\n }\n\n .ml-4 {\n margin-left: calc(var(--spacing) * 4);\n }\n\n .box-border {\n box-sizing: border-box;\n }\n\n .line-clamp-2 {\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n display: -webkit-box;\n overflow: hidden;\n }\n\n .block {\n display: block;\n }\n\n .flex {\n display: flex;\n }\n\n .hidden {\n display: none;\n }\n\n .inline {\n display: inline;\n }\n\n .inline-block {\n display: inline-block;\n }\n\n .table {\n display: table;\n }\n\n .aspect-square {\n aspect-ratio: 1;\n }\n\n .size-5 {\n width: calc(var(--spacing) * 5);\n height: calc(var(--spacing) * 5);\n }\n\n .h-2 {\n height: calc(var(--spacing) * 2);\n }\n\n .h-5 {\n height: calc(var(--spacing) * 5);\n }\n\n .h-10 {\n height: calc(var(--spacing) * 10);\n }\n\n .h-64 {\n height: calc(var(--spacing) * 64);\n }\n\n .h-\\[0\\.63em\\] {\n height: .63em;\n }\n\n .h-full {\n height: 100%;\n }\n\n .h-screen {\n height: 100vh;\n }\n\n .w-1\\/3 {\n width: 33.3333%;\n }\n\n .w-2 {\n width: calc(var(--spacing) * 2);\n }\n\n .w-2\\/5 {\n width: 40%;\n }\n\n .w-7\\/12 {\n width: 58.3333%;\n }\n\n .w-10 {\n width: calc(var(--spacing) * 10);\n }\n\n .w-11 {\n width: calc(var(--spacing) * 11);\n }\n\n .w-12 {\n width: calc(var(--spacing) * 12);\n }\n\n .w-40 {\n width: calc(var(--spacing) * 40);\n }\n\n .w-72 {\n width: calc(var(--spacing) * 72);\n }\n\n .w-full {\n width: 100%;\n }\n\n .max-w-90 {\n max-width: calc(var(--spacing) * 90);\n }\n\n .min-w-0 {\n min-width: 0;\n }\n\n .flex-1 {\n flex: 1;\n }\n\n .flex-auto {\n flex: auto;\n }\n\n .flex-shrink-0, .shrink-0 {\n flex-shrink: 0;\n }\n\n .grow {\n flex-grow: 1;\n }\n\n .-translate-x-1\\/2 {\n --tw-translate-x: calc(calc(1 / 2 * 100%) * -1);\n translate: var(--tw-translate-x) var(--tw-translate-y);\n }\n\n .scale-75 {\n --tw-scale-x: 75%;\n --tw-scale-y: 75%;\n --tw-scale-z: 75%;\n scale: var(--tw-scale-x) var(--tw-scale-y);\n }\n\n .transform {\n transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );\n }\n\n .animate-spin {\n animation: var(--animate-spin);\n }\n\n .cursor-help {\n cursor: help;\n }\n\n .cursor-pointer {\n cursor: pointer;\n }\n\n .list-none {\n list-style-type: none;\n }\n\n .flex-col {\n flex-direction: column;\n }\n\n .flex-row-reverse {\n flex-direction: row-reverse;\n }\n\n .flex-wrap {\n flex-wrap: wrap;\n }\n\n .items-center {\n align-items: center;\n }\n\n .justify-between {\n justify-content: space-between;\n }\n\n .justify-center {\n justify-content: center;\n }\n\n .justify-start {\n justify-content: flex-start;\n }\n\n .gap-1 {\n gap: var(--spacing);\n }\n\n .gap-2 {\n gap: calc(var(--spacing) * 2);\n }\n\n .gap-3 {\n gap: calc(var(--spacing) * 3);\n }\n\n .gap-5 {\n gap: calc(var(--spacing) * 5);\n }\n\n .gap-x-3 {\n column-gap: calc(var(--spacing) * 3);\n }\n\n .gap-y-5 {\n row-gap: calc(var(--spacing) * 5);\n }\n\n .overflow-hidden {\n overflow: hidden;\n }\n\n .overflow-x-auto {\n overflow-x: auto;\n }\n\n .overflow-x-hidden {\n overflow-x: hidden;\n }\n\n .overflow-y-auto {\n overflow-y: auto;\n }\n\n .rounded {\n border-radius: .25rem;\n }\n\n .rounded-full {\n border-radius: 3.40282e38px;\n }\n\n .rounded-md {\n border-radius: var(--radius-md);\n }\n\n .rounded-none {\n border-radius: 0;\n }\n\n .rounded-sm {\n border-radius: var(--radius-sm);\n }\n\n .rounded-r-xl {\n border-top-right-radius: var(--radius-xl);\n border-bottom-right-radius: var(--radius-xl);\n }\n\n .border {\n border-style: var(--tw-border-style);\n border-width: 1px;\n }\n\n .border-t {\n border-top-style: var(--tw-border-style);\n border-top-width: 1px;\n }\n\n .border-r {\n border-right-style: var(--tw-border-style);\n border-right-width: 1px;\n }\n\n .border-l {\n border-left-style: var(--tw-border-style);\n border-left-width: 1px;\n }\n\n .\\!border-none {\n --tw-border-style: none !important;\n border-style: none !important;\n }\n\n .border-t-\\[\\#303030\\] {\n border-top-color: #303030;\n }\n\n .border-t-colorBorderSecondary {\n border-top-color: var(--oo-colorBorderSecondary);\n }\n\n .border-r-\\[\\#303030\\] {\n border-right-color: #303030;\n }\n\n .border-r-colorBorderSecondary {\n border-right-color: var(--oo-colorBorderSecondary);\n }\n\n .border-l-colorBorderSecondary {\n border-left-color: var(--oo-colorBorderSecondary);\n }\n\n .bg-\\[\\#F3F4F5\\] {\n background-color: #f3f4f5;\n }\n\n .bg-blue-500\\/20 {\n background-color: rgb(var(--oo-blue-5));\n }\n\n @supports (color: color-mix(in lab, red, red)) {\n .bg-blue-500\\/20 {\n background-color: color-mix(in oklab, rgb(var(--oo-blue-5)) 20%, transparent);\n }\n }\n\n .bg-blue-600 {\n background-color: rgb(var(--oo-blue-6));\n }\n\n .bg-colorBgContainer {\n background-color: var(--oo-colorBgContainer);\n }\n\n .bg-colorBgLayout {\n background-color: var(--oo-colorBgLayout);\n }\n\n .bg-gray-100 {\n background-color: #f5f5f5;\n }\n\n .bg-primary {\n background-color: rgb(var(--oo-colorPrimary));\n }\n\n .bg-primaryActive {\n background-color: rgb(var(--oo-colorPrimaryActive));\n }\n\n .object-cover {\n object-fit: cover;\n }\n\n .p-0 {\n padding: 0;\n }\n\n .p-1 {\n padding: var(--spacing);\n }\n\n .p-2 {\n padding: calc(var(--spacing) * 2);\n }\n\n .p-4 {\n padding: calc(var(--spacing) * 4);\n }\n\n .px-0 {\n padding-inline: 0;\n }\n\n .px-1 {\n padding-inline: var(--spacing);\n }\n\n .px-1\\.5 {\n padding-inline: calc(var(--spacing) * 1.5);\n }\n\n .px-2 {\n padding-inline: calc(var(--spacing) * 2);\n }\n\n .px-2\\.75 {\n padding-inline: calc(var(--spacing) * 2.75);\n }\n\n .px-3 {\n padding-inline: calc(var(--spacing) * 3);\n }\n\n .px-4 {\n padding-inline: calc(var(--spacing) * 4);\n }\n\n .px-6 {\n padding-inline: calc(var(--spacing) * 6);\n }\n\n .px-9 {\n padding-inline: calc(var(--spacing) * 9);\n }\n\n .px-10 {\n padding-inline: calc(var(--spacing) * 10);\n }\n\n .px-\\[11px\\] {\n padding-inline: 11px;\n }\n\n .py-1 {\n padding-block: var(--spacing);\n }\n\n .py-1\\.5 {\n padding-block: calc(var(--spacing) * 1.5);\n }\n\n .py-2 {\n padding-block: calc(var(--spacing) * 2);\n }\n\n .py-2\\.5 {\n padding-block: calc(var(--spacing) * 2.5);\n }\n\n .py-4 {\n padding-block: calc(var(--spacing) * 4);\n }\n\n .py-10 {\n padding-block: calc(var(--spacing) * 10);\n }\n\n .pb-4 {\n padding-bottom: calc(var(--spacing) * 4);\n }\n\n .pl-2 {\n padding-left: calc(var(--spacing) * 2);\n }\n\n .text-center {\n text-align: center;\n }\n\n .font-sans {\n font-family: var(--font-sans);\n }\n\n .text-3xl {\n font-size: var(--text-3xl);\n line-height: var(--tw-leading, var(--text-3xl--line-height));\n }\n\n .text-lg {\n font-size: var(--text-lg);\n line-height: var(--tw-leading, var(--text-lg--line-height));\n }\n\n .text-sm {\n font-size: var(--text-sm);\n line-height: var(--tw-leading, var(--text-sm--line-height));\n }\n\n .text-xl {\n font-size: var(--text-xl);\n line-height: var(--tw-leading, var(--text-xl--line-height));\n }\n\n .text-xs {\n font-size: var(--text-xs);\n line-height: var(--tw-leading, var(--text-xs--line-height));\n }\n\n .text-\\[4rem\\] {\n font-size: 4rem;\n }\n\n .leading-none {\n --tw-leading: 1;\n line-height: 1;\n }\n\n .font-bold {\n --tw-font-weight: var(--font-weight-bold);\n font-weight: var(--font-weight-bold);\n }\n\n .font-medium {\n --tw-font-weight: var(--font-weight-medium);\n font-weight: var(--font-weight-medium);\n }\n\n .font-semibold {\n --tw-font-weight: var(--font-weight-semibold);\n font-weight: var(--font-weight-semibold);\n }\n\n .tracking-tight {\n --tw-tracking: var(--tracking-tight);\n letter-spacing: var(--tracking-tight);\n }\n\n .text-colorBgContainer {\n color: var(--oo-colorBgContainer);\n }\n\n .text-colorBgContainer\\! {\n color: var(--oo-colorBgContainer) !important;\n }\n\n .text-colorText {\n color: var(--oo-colorText);\n }\n\n .text-colorText\\! {\n color: var(--oo-colorText) !important;\n }\n\n .text-colorTextSecondary {\n color: var(--oo-colorTextSecondary);\n }\n\n .text-colorTextTertiary {\n color: var(--oo-colorTextTertiary);\n }\n\n .opacity-50 {\n opacity: .5;\n }\n\n .opacity-90 {\n opacity: .9;\n }\n\n .outline, .outline-1 {\n outline-style: var(--tw-outline-style);\n outline-width: 1px;\n }\n\n .outline-2 {\n outline-style: var(--tw-outline-style);\n outline-width: 2px;\n }\n\n .outline-blue-600 {\n outline-color: rgb(var(--oo-blue-6));\n }\n\n .outline-gray-300 {\n outline-color: #d9d9d9;\n }\n\n .filter {\n filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );\n }\n\n .transition {\n transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, content-visibility, overlay, pointer-events;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n }\n\n .transition-all {\n transition-property: all;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n }\n\n .duration-300 {\n --tw-duration: .3s;\n transition-duration: .3s;\n }\n\n .ease-in {\n --tw-ease: var(--ease-in);\n transition-timing-function: var(--ease-in);\n }\n\n @media (hover: hover) {\n .group-hover\\:animate-wiggle:is(:where(.group):hover *) {\n animation: var(--animate-wiggle);\n }\n\n .group-hover\\:opacity-100:is(:where(.group):hover *) {\n opacity: 1;\n }\n }\n\n .before\\:absolute:before {\n content: var(--tw-content);\n position: absolute;\n }\n\n .before\\:top-1\\/2:before {\n content: var(--tw-content);\n top: 50%;\n }\n\n .before\\:left-1\\/2:before {\n content: var(--tw-content);\n left: 50%;\n }\n\n .before\\:h-0:before {\n content: var(--tw-content);\n height: 0;\n }\n\n .before\\:w-0:before {\n content: var(--tw-content);\n width: 0;\n }\n\n .before\\:rounded-sm:before {\n content: var(--tw-content);\n border-radius: var(--radius-sm);\n }\n\n .before\\:opacity-0:before {\n content: var(--tw-content);\n opacity: 0;\n }\n\n .before\\:outline:before {\n content: var(--tw-content);\n outline-style: var(--tw-outline-style);\n outline-width: 1px;\n }\n\n .before\\:outline-2:before {\n content: var(--tw-content);\n outline-style: var(--tw-outline-style);\n outline-width: 2px;\n }\n\n .before\\:outline-transparent:before {\n content: var(--tw-content);\n outline-color: #0000;\n }\n\n .before\\:transition-all:before {\n content: var(--tw-content);\n transition-property: all;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n }\n\n .before\\:duration-300:before {\n content: var(--tw-content);\n --tw-duration: .3s;\n transition-duration: .3s;\n }\n\n .before\\:content-\\[\\'\\'\\]:before {\n --tw-content: \"\";\n content: var(--tw-content);\n }\n\n .last\\:mr-auto:last-child {\n margin-right: auto;\n }\n\n @media (hover: hover) {\n .hover\\:bg-gray-100:hover {\n background-color: #f5f5f5;\n }\n\n .hover\\:text-colorText:hover {\n color: var(--oo-colorText);\n }\n }\n\n .before\\:hover\\:top-0:before {\n content: var(--tw-content);\n }\n\n @media (hover: hover) {\n .before\\:hover\\:top-0:before:hover {\n top: 0;\n }\n }\n\n .before\\:hover\\:left-0:before {\n content: var(--tw-content);\n }\n\n @media (hover: hover) {\n .before\\:hover\\:left-0:before:hover {\n left: 0;\n }\n }\n\n .before\\:hover\\:h-full:before {\n content: var(--tw-content);\n }\n\n @media (hover: hover) {\n .before\\:hover\\:h-full:before:hover {\n height: 100%;\n }\n }\n\n .before\\:hover\\:w-full:before {\n content: var(--tw-content);\n }\n\n @media (hover: hover) {\n .before\\:hover\\:w-full:before:hover {\n width: 100%;\n }\n }\n\n .before\\:hover\\:p-1:before {\n content: var(--tw-content);\n }\n\n @media (hover: hover) {\n .before\\:hover\\:p-1:before:hover {\n padding: var(--spacing);\n }\n }\n\n .before\\:hover\\:opacity-100:before {\n content: var(--tw-content);\n }\n\n @media (hover: hover) {\n .before\\:hover\\:opacity-100:before:hover {\n opacity: 1;\n }\n }\n\n .before\\:hover\\:outline-blue-600:before {\n content: var(--tw-content);\n }\n\n @media (hover: hover) {\n .before\\:hover\\:outline-blue-600:before:hover {\n outline-color: rgb(var(--oo-blue-6));\n }\n }\n\n @media (prefers-reduced-motion: no-preference) {\n .motion-safe\\:animate-bounce-in-down-out-up {\n animation: var(--animate-bounce-in-down-out-up);\n }\n }\n\n @media (min-width: 576px) {\n .sm\\:mx-auto {\n margin-inline: auto;\n }\n }\n\n @media (min-width: 768px) {\n .md\\:mr-2\\.5 {\n margin-right: calc(var(--spacing) * 2.5);\n }\n\n .md\\:block {\n display: block;\n }\n\n .md\\:w-3\\/12 {\n width: 25%;\n }\n\n .md\\:w-96 {\n width: calc(var(--spacing) * 96);\n }\n\n .md\\:max-w-md {\n max-width: var(--container-md);\n }\n\n .md\\:bg-colorBgLayout {\n background-color: var(--oo-colorBgLayout);\n }\n\n .md\\:px-4 {\n padding-inline: calc(var(--spacing) * 4);\n }\n\n .md\\:pb-0 {\n padding-bottom: 0;\n }\n\n .md\\:text-sm {\n font-size: var(--text-sm);\n line-height: var(--tw-leading, var(--text-sm--line-height));\n }\n }\n\n @media (min-width: 992px) {\n .lg\\:text-2xl {\n font-size: var(--text-2xl);\n line-height: var(--tw-leading, var(--text-2xl--line-height));\n }\n }\n\n @media (min-width: 1200px) {\n .xl\\:w-2\\/12 {\n width: 16.6667%;\n }\n\n .xl\\:px-8 {\n padding-inline: calc(var(--spacing) * 8);\n }\n }\n\n .dark\\:bg-\\[\\#26313C\\]:where(.dark, .dark *) {\n background-color: #26313c;\n }\n\n .dark\\:bg-black:where(.dark, .dark *) {\n background-color: #000;\n }\n\n .dark\\:bg-gray-700:where(.dark, .dark *) {\n background-color: #434343;\n }\n\n .dark\\:outline-blue-700:where(.dark, .dark *) {\n outline-color: rgb(var(--oo-blue-7));\n }\n\n .dark\\:outline-gray-700:where(.dark, .dark *) {\n outline-color: #434343;\n }\n\n @media (hover: hover) {\n .dark\\:hover\\:bg-gray-700:where(.dark, .dark *):hover {\n background-color: #434343;\n }\n }\n\n .dark\\:before\\:hover\\:outline-blue-700:where(.dark, .dark *):before {\n content: var(--tw-content);\n }\n\n @media (hover: hover) {\n .dark\\:before\\:hover\\:outline-blue-700:where(.dark, .dark *):before:hover {\n outline-color: rgb(var(--oo-blue-7));\n }\n }\n\n .en-US\\:gap-y-3:where(:lang(en-US)) {\n row-gap: calc(var(--spacing) * 3);\n }\n\n .en-US\\:text-\\[9rem\\]:where(:lang(en-US)) {\n font-size: 9rem;\n }\n\n .zh-CN\\:hidden:where(:lang(zh-CN)) {\n display: none;\n }\n}\n\n@keyframes fade-in {\n from {\n opacity: 0;\n }\n\n to {\n opacity: 1;\n }\n}\n\n@keyframes fade-out {\n from {\n opacity: 1;\n }\n\n to {\n opacity: 0;\n }\n}\n\n@keyframes slide-in {\n from {\n transform: translateX(-30px);\n }\n\n to {\n transform: translateX(0);\n }\n}\n\n@keyframes slide-out {\n from {\n transform: translateX(0);\n }\n\n to {\n transform: translateX(30px);\n }\n}\n\n@keyframes slide-top-in {\n from {\n transform: translateY(-10%);\n }\n\n to {\n transform: translateY(0);\n }\n}\n\n@keyframes slide-top-out {\n from {\n transform: translateY(0);\n }\n\n to {\n transform: translateY(-10%);\n }\n}\n\n@keyframes slide-bottom-in {\n from {\n transform: translateY(10%);\n }\n\n to {\n transform: translateY(0);\n }\n}\n\n@keyframes slide-bottom-out {\n from {\n transform: translateY(0);\n }\n\n to {\n transform: translateY(10%);\n }\n}\n\n@keyframes fade-slide {\n 0% {\n opacity: 0;\n transform: translate(-30px);\n }\n\n 50% {\n opacity: 1;\n }\n\n 100% {\n opacity: 0;\n transform: translate(30px);\n }\n}\n\n@keyframes fade-up {\n 0% {\n opacity: 0;\n transform: translateY(10%);\n }\n\n 50% {\n opacity: 1;\n }\n\n 100% {\n opacity: 0;\n transform: translateY(-10%);\n }\n}\n\n@keyframes fade-down {\n 0% {\n opacity: 0;\n transform: translateY(-10%);\n }\n\n 50% {\n opacity: 1;\n }\n\n 100% {\n opacity: 0;\n transform: translateY(10%);\n }\n}\n\n.fade-slide {\n animation: 3s linear infinite fade-slide;\n}\n\n.fade {\n animation: 3s linear infinite alternate fade-in;\n}\n\n.fade-up {\n animation: 3s infinite fade-up;\n}\n\n.fade-down {\n animation: 3s infinite fade-down;\n}\n\n@keyframes zoom-in {\n 0% {\n transform: scale(.8);\n }\n\n 100% {\n opacity: 1;\n transform: scale(1);\n }\n}\n\n@keyframes zoom-out {\n 0% {\n transform: scale(1);\n }\n\n 100% {\n opacity: 1;\n transform: scale(1.25);\n }\n}\n\n@keyframes fade-zoom {\n 0% {\n opacity: 0;\n transform: scale(.8);\n }\n\n 50% {\n opacity: 1;\n transform: scale(1);\n }\n\n 100% {\n opacity: 0;\n transform: scale(1.25);\n }\n}\n\n.fade-zoom {\n animation: 3s infinite fade-zoom;\n}\n\n.keepalive-fade.active {\n animation: .3s ease-in-out fade-in;\n}\n\n.keepalive-fade.inactive {\n animation: .3s ease-in-out fade-out;\n}\n\n.keepalive-fade-slide.active {\n animation: .3s ease-in-out fade-in, .3s ease-in-out slide-in;\n}\n\n.keepalive-fade-slide.inactive {\n animation: .3s ease-in-out fade-out, .3s ease-in-out slide-out;\n}\n\n.keepalive-fade-up.active {\n animation: .3s ease-in-out fade-in, .3s ease-in-out slide-bottom-in;\n}\n\n.keepalive-fade-up.inactive {\n animation: .3s ease-in-out fade-out, .3s ease-in-out slide-top-out;\n}\n\n.keepalive-fade-down.active {\n animation: .3s ease-in-out fade-in, .3s ease-in-out slide-top-in;\n}\n\n.keepalive-fade-down.inactive {\n animation: .3s ease-in-out fade-out, .3s ease-in-out slide-bottom-out;\n}\n\n.keepalive-fade-zoom.active {\n animation: .3s ease-in-out zoom-in, .3s ease-in-out zoom-in;\n}\n\n.keepalive-fade-zoom.inactive {\n animation: .3s ease-in-out zoom-out, .3s ease-in-out fade-out;\n}\n\n@property --tw-blur {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-brightness {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-contrast {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-grayscale {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-hue-rotate {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-invert {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-opacity {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-saturate {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-sepia {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-drop-shadow {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-drop-shadow-color {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-drop-shadow-alpha {\n syntax: \"<percentage>\";\n inherits: false;\n initial-value: 100%;\n}\n\n@property --tw-drop-shadow-size {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-translate-x {\n syntax: \"*\";\n inherits: false;\n initial-value: 0;\n}\n\n@property --tw-translate-y {\n syntax: \"*\";\n inherits: false;\n initial-value: 0;\n}\n\n@property --tw-translate-z {\n syntax: \"*\";\n inherits: false;\n initial-value: 0;\n}\n\n@property --tw-scale-x {\n syntax: \"*\";\n inherits: false;\n initial-value: 1;\n}\n\n@property --tw-scale-y {\n syntax: \"*\";\n inherits: false;\n initial-value: 1;\n}\n\n@property --tw-scale-z {\n syntax: \"*\";\n inherits: false;\n initial-value: 1;\n}\n\n@property --tw-rotate-x {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-rotate-y {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-rotate-z {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-skew-x {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-skew-y {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-border-style {\n syntax: \"*\";\n inherits: false;\n initial-value: solid;\n}\n\n@property --tw-leading {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-font-weight {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-tracking {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-outline-style {\n syntax: \"*\";\n inherits: false;\n initial-value: solid;\n}\n\n@property --tw-duration {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-ease {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-content {\n syntax: \"*\";\n inherits: false;\n initial-value: \"\";\n}\n\n@keyframes spin {\n to {\n transform: rotate(360deg);\n }\n}\n\n@keyframes wiggle {\n 0%, 100% {\n transform-origin: top;\n }\n\n 15% {\n transform: rotateZ(10deg);\n }\n\n 30% {\n transform: rotateZ(-10deg);\n }\n\n 45% {\n transform: rotateZ(5deg);\n }\n\n 60% {\n transform: rotateZ(-5deg);\n }\n\n 75% {\n transform: rotateZ(2deg);\n }\n}\n\n@keyframes bounce-in-down-out-up {\n 0% {\n transform: translateY(0);\n }\n\n 50% {\n transform: translateY(-20px);\n }\n\n 100% {\n transform: translateY(0);\n }\n}\n\n@layer properties {\n @supports (((-webkit-hyphens: none)) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color: rgb(from red r g b)))) {\n *, :before, :after, ::backdrop {\n --tw-blur: initial;\n --tw-brightness: initial;\n --tw-contrast: initial;\n --tw-grayscale: initial;\n --tw-hue-rotate: initial;\n --tw-invert: initial;\n --tw-opacity: initial;\n --tw-saturate: initial;\n --tw-sepia: initial;\n --tw-drop-shadow: initial;\n --tw-drop-shadow-color: initial;\n --tw-drop-shadow-alpha: 100%;\n --tw-drop-shadow-size: initial;\n --tw-translate-x: 0;\n --tw-translate-y: 0;\n --tw-translate-z: 0;\n --tw-scale-x: 1;\n --tw-scale-y: 1;\n --tw-scale-z: 1;\n --tw-rotate-x: initial;\n --tw-rotate-y: initial;\n --tw-rotate-z: initial;\n --tw-skew-x: initial;\n --tw-skew-y: initial;\n --tw-border-style: solid;\n --tw-leading: initial;\n --tw-font-weight: initial;\n --tw-tracking: initial;\n --tw-outline-style: solid;\n --tw-duration: initial;\n --tw-ease: initial;\n --tw-content: \"\";\n }\n }\n}\n/*$vite$:1*/";
5
+ s.textContent = "\n@layer properties, reset, antd;\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n@layer reset{\n/* stylelint-disable */\nhtml,\nbody {\n width: 100%;\n height: 100%;\n}\ninput::-ms-clear,\ninput::-ms-reveal {\n display: none;\n}\n*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\nhtml {\n font-family: sans-serif;\n line-height: 1.15;\n -webkit-text-size-adjust: 100%;\n -ms-text-size-adjust: 100%;\n -ms-overflow-style: scrollbar;\n -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\n\nbody {\n margin: 0;\n}\n[tabindex='-1']:focus {\n outline: none;\n}\nhr {\n box-sizing: content-box;\n height: 0;\n overflow: visible;\n}\nh1,\nh2,\nh3,\nh4,\nh5,\nh6 {\n margin-top: 0;\n margin-bottom: 0.5em;\n font-weight: 500;\n}\np {\n margin-top: 0;\n margin-bottom: 1em;\n}\nabbr[title],\nabbr[data-original-title] {\n -webkit-text-decoration: underline dotted;\n text-decoration: underline dotted;\n border-bottom: 0;\n cursor: help;\n}\naddress {\n margin-bottom: 1em;\n font-style: normal;\n line-height: inherit;\n}\ninput[type='text'],\ninput[type='password'],\ninput[type='number'],\ntextarea {\n -webkit-appearance: none;\n}\nol,\nul,\ndl {\n margin-top: 0;\n margin-bottom: 1em;\n}\nol ol,\nul ul,\nol ul,\nul ol {\n margin-bottom: 0;\n}\ndt {\n font-weight: 500;\n}\ndd {\n margin-bottom: 0.5em;\n margin-left: 0;\n}\nblockquote {\n margin: 0 0 1em;\n}\ndfn {\n font-style: italic;\n}\nb,\nstrong {\n font-weight: bolder;\n}\nsmall {\n font-size: 80%;\n}\nsub,\nsup {\n position: relative;\n font-size: 75%;\n line-height: 0;\n vertical-align: baseline;\n}\nsub {\n bottom: -0.25em;\n}\nsup {\n top: -0.5em;\n}\npre,\ncode,\nkbd,\nsamp {\n font-size: 1em;\n font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace;\n}\npre {\n margin-top: 0;\n margin-bottom: 1em;\n overflow: auto;\n}\nfigure {\n margin: 0 0 1em;\n}\nimg {\n vertical-align: middle;\n border-style: none;\n}\na,\narea,\nbutton,\n[role='button'],\ninput:not([type='range']),\nlabel,\nselect,\nsummary,\ntextarea {\n touch-action: manipulation;\n}\ntable {\n border-collapse: collapse;\n}\ncaption {\n padding-top: 0.75em;\n padding-bottom: 0.3em;\n text-align: left;\n caption-side: bottom;\n}\ninput,\nbutton,\nselect,\noptgroup,\ntextarea {\n margin: 0;\n color: inherit;\n font-size: inherit;\n font-family: inherit;\n line-height: inherit;\n}\nbutton,\ninput {\n overflow: visible;\n}\nbutton,\nselect {\n text-transform: none;\n}\nbutton,\nhtml [type='button'],\n[type='reset'],\n[type='submit'] {\n -webkit-appearance: button;\n}\nbutton::-moz-focus-inner,\n[type='button']::-moz-focus-inner,\n[type='reset']::-moz-focus-inner,\n[type='submit']::-moz-focus-inner {\n padding: 0;\n border-style: none;\n}\ninput[type='radio'],\ninput[type='checkbox'] {\n box-sizing: border-box;\n padding: 0;\n}\ninput[type='date'],\ninput[type='time'],\ninput[type='datetime-local'],\ninput[type='month'] {\n -webkit-appearance: listbox;\n}\ntextarea {\n overflow: auto;\n resize: vertical;\n}\nfieldset {\n min-width: 0;\n margin: 0;\n padding: 0;\n border: 0;\n}\nlegend {\n display: block;\n width: 100%;\n max-width: 100%;\n margin-bottom: 0.5em;\n padding: 0;\n color: inherit;\n font-size: 1.5em;\n line-height: inherit;\n white-space: normal;\n}\nprogress {\n vertical-align: baseline;\n}\n[type='number']::-webkit-inner-spin-button,\n[type='number']::-webkit-outer-spin-button {\n height: auto;\n}\n[type='search'] {\n outline-offset: -2px;\n -webkit-appearance: none;\n}\n[type='search']::-webkit-search-cancel-button,\n[type='search']::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n::-webkit-file-upload-button {\n font: inherit;\n -webkit-appearance: button;\n}\noutput {\n display: inline-block;\n}\nsummary {\n display: list-item;\n}\ntemplate {\n display: none;\n}\n[hidden] {\n display: none !important;\n}\n}\n@layer simplebar{\n[data-simplebar]{position:relative;flex-direction:column;flex-wrap:wrap;justify-content:flex-start;align-content:flex-start;align-items:flex-start}.simplebar-wrapper{overflow:hidden;width:inherit;height:inherit;max-width:inherit;max-height:inherit}.simplebar-mask{direction:inherit;position:absolute;overflow:hidden;padding:0;margin:0;left:0;top:0;bottom:0;right:0;width:auto!important;height:auto!important;z-index:0}.simplebar-offset{direction:inherit!important;box-sizing:inherit!important;resize:none!important;position:absolute;top:0;left:0;bottom:0;right:0;padding:0;margin:0;-webkit-overflow-scrolling:touch}.simplebar-content-wrapper{direction:inherit;box-sizing:border-box!important;position:relative;display:block;height:100%;width:auto;max-width:100%;max-height:100%;overflow:auto;scrollbar-width:none;-ms-overflow-style:none}.simplebar-content-wrapper::-webkit-scrollbar,.simplebar-hide-scrollbar::-webkit-scrollbar{display:none;width:0;height:0}.simplebar-content:after,.simplebar-content:before{content:' ';display:table}.simplebar-placeholder{max-height:100%;max-width:100%;width:100%;pointer-events:none}.simplebar-height-auto-observer-wrapper{box-sizing:inherit!important;height:100%;width:100%;max-width:1px;position:relative;float:left;max-height:1px;overflow:hidden;z-index:-1;padding:0;margin:0;pointer-events:none;flex-grow:inherit;flex-shrink:0;flex-basis:0}.simplebar-height-auto-observer{box-sizing:inherit;display:block;opacity:0;position:absolute;top:0;left:0;height:1000%;width:1000%;min-height:1px;min-width:1px;overflow:hidden;pointer-events:none;z-index:-1}.simplebar-track{z-index:1;position:absolute;right:0;bottom:0;pointer-events:none;overflow:hidden}[data-simplebar].simplebar-dragging{pointer-events:none;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}[data-simplebar].simplebar-dragging .simplebar-content{pointer-events:none;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}[data-simplebar].simplebar-dragging .simplebar-track{pointer-events:all}.simplebar-scrollbar{position:absolute;left:0;right:0;min-height:10px}.simplebar-scrollbar:before{position:absolute;content:'';background:#000;border-radius:7px;left:2px;right:2px;opacity:0;transition:opacity .2s .5s linear}.simplebar-scrollbar.simplebar-visible:before{opacity:.5;transition-delay:0s;transition-duration:0s}.simplebar-track.simplebar-vertical{top:0;width:11px}.simplebar-scrollbar:before{top:2px;bottom:2px;left:2px;right:2px}.simplebar-track.simplebar-horizontal{left:0;height:11px}.simplebar-track.simplebar-horizontal .simplebar-scrollbar{right:auto;left:0;top:0;bottom:0;min-height:0;min-width:10px;width:auto}[data-simplebar-direction=rtl] .simplebar-track.simplebar-vertical{right:auto;left:0}.simplebar-dummy-scrollbar-size{direction:rtl;position:fixed;opacity:0;visibility:hidden;height:500px;width:500px;overflow-y:hidden;overflow-x:scroll;-ms-overflow-style:scrollbar!important}.simplebar-dummy-scrollbar-size>div{width:200%;height:200%;margin:10px 0}.simplebar-hide-scrollbar{position:fixed;left:0;visibility:hidden;overflow-y:scroll;scrollbar-width:none;-ms-overflow-style:none}\n}\n@layer simplebar {\n .simplebar-scrollbar:before {\n background-color: #909399;\n }\n\n .simplebar-content {\n height: 100%;\n }\n}\n\n#root {\n height: 100vh;\n}\n\nimg {\n max-width: 100%;\n height: auto;\n}\n\nhtml.color-blind-mode {\n --tw-invert: invert(100%);\n filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );\n}\n\nhtml.gray-mode {\n --tw-grayscale: grayscale(100%);\n filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );\n}\n\n@layer theme {\n :root, :host {\n --font-sans: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", \"Noto Sans\", Arial,\n sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";\n --spacing: .25rem;\n --container-md: 28rem;\n --text-xs: .75rem;\n --text-xs--line-height: calc(1 / .75);\n --text-sm: .875rem;\n --text-sm--line-height: calc(1.25 / .875);\n --text-lg: 1.125rem;\n --text-lg--line-height: calc(1.75 / 1.125);\n --text-xl: 1.25rem;\n --text-xl--line-height: calc(1.75 / 1.25);\n --text-2xl: 1.5rem;\n --text-2xl--line-height: calc(2 / 1.5);\n --text-3xl: 1.875rem;\n --text-3xl--line-height: calc(2.25 / 1.875);\n --font-weight-medium: 500;\n --font-weight-semibold: 600;\n --font-weight-bold: 700;\n --tracking-tight: -.025em;\n --radius-sm: .25rem;\n --radius-md: .375rem;\n --radius-xl: .75rem;\n --ease-in: cubic-bezier(.4, 0, 1, 1);\n --animate-spin: spin 1s linear infinite;\n --default-transition-duration: .15s;\n --default-transition-timing-function: cubic-bezier(.4, 0, .2, 1);\n --animate-wiggle: wiggle 1s both;\n --animate-bounce-in-down-out-up: bounce-in-down-out-up 4s ease-in-out 0s infinite;\n }\n}\n\n@layer base, components;\n\n@layer utilities {\n .visible {\n visibility: visible;\n }\n\n .absolute {\n position: absolute;\n }\n\n .fixed {\n position: fixed;\n }\n\n .relative {\n position: relative;\n }\n\n .static {\n position: static;\n }\n\n .top-0 {\n top: 0;\n }\n\n .top-1\\.5 {\n top: calc(var(--spacing) * 1.5);\n }\n\n .top-2 {\n top: calc(var(--spacing) * 2);\n }\n\n .top-3 {\n top: calc(var(--spacing) * 3);\n }\n\n .right-2 {\n right: calc(var(--spacing) * 2);\n }\n\n .right-3 {\n right: calc(var(--spacing) * 3);\n }\n\n .right-4 {\n right: calc(var(--spacing) * 4);\n }\n\n .bottom-0 {\n bottom: 0;\n }\n\n .bottom-3 {\n bottom: calc(var(--spacing) * 3);\n }\n\n .left-0 {\n left: 0;\n }\n\n .left-1\\/2 {\n left: 50%;\n }\n\n .left-3 {\n left: calc(var(--spacing) * 3);\n }\n\n .z-10 {\n z-index: 10;\n }\n\n .container {\n width: 100%;\n }\n\n @media (min-width: 480px) {\n .container {\n max-width: 480px;\n }\n }\n\n @media (min-width: 576px) {\n .container {\n max-width: 576px;\n }\n }\n\n @media (min-width: 768px) {\n .container {\n max-width: 768px;\n }\n }\n\n @media (min-width: 992px) {\n .container {\n max-width: 992px;\n }\n }\n\n @media (min-width: 1200px) {\n .container {\n max-width: 1200px;\n }\n }\n\n @media (min-width: 1600px) {\n .container {\n max-width: 1600px;\n }\n }\n\n .m-0 {\n margin: 0;\n }\n\n .m-152 {\n margin: calc(var(--spacing) * 152);\n }\n\n .mx-3 {\n margin-inline: calc(var(--spacing) * 3);\n }\n\n .mx-4 {\n margin-inline: calc(var(--spacing) * 4);\n }\n\n .mx-auto {\n margin-inline: auto;\n }\n\n .my-0 {\n margin-block: 0;\n }\n\n .my-1 {\n margin-block: var(--spacing);\n }\n\n .my-4 {\n margin-block: calc(var(--spacing) * 4);\n }\n\n .my-8 {\n margin-block: calc(var(--spacing) * 8);\n }\n\n .mt-2 {\n margin-top: calc(var(--spacing) * 2);\n }\n\n .mt-2\\.5 {\n margin-top: calc(var(--spacing) * 2.5);\n }\n\n .mt-4 {\n margin-top: calc(var(--spacing) * 4);\n }\n\n .mt-6 {\n margin-top: calc(var(--spacing) * 6);\n }\n\n .mr-2 {\n margin-right: calc(var(--spacing) * 2);\n }\n\n .mr-3 {\n margin-right: calc(var(--spacing) * 3);\n }\n\n .mr-8 {\n margin-right: calc(var(--spacing) * 8);\n }\n\n .mr-17 {\n margin-right: calc(var(--spacing) * 17);\n }\n\n .mb-0 {\n margin-bottom: 0;\n }\n\n .mb-2 {\n margin-bottom: calc(var(--spacing) * 2);\n }\n\n .mb-3 {\n margin-bottom: calc(var(--spacing) * 3);\n }\n\n .mb-6 {\n margin-bottom: calc(var(--spacing) * 6);\n }\n\n .ml-1 {\n margin-left: var(--spacing);\n }\n\n .ml-2 {\n margin-left: calc(var(--spacing) * 2);\n }\n\n .ml-4 {\n margin-left: calc(var(--spacing) * 4);\n }\n\n .box-border {\n box-sizing: border-box;\n }\n\n .line-clamp-2 {\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n display: -webkit-box;\n overflow: hidden;\n }\n\n .block {\n display: block;\n }\n\n .flex {\n display: flex;\n }\n\n .hidden {\n display: none;\n }\n\n .inline {\n display: inline;\n }\n\n .inline-block {\n display: inline-block;\n }\n\n .table {\n display: table;\n }\n\n .aspect-square {\n aspect-ratio: 1;\n }\n\n .size-5 {\n width: calc(var(--spacing) * 5);\n height: calc(var(--spacing) * 5);\n }\n\n .h-2 {\n height: calc(var(--spacing) * 2);\n }\n\n .h-5 {\n height: calc(var(--spacing) * 5);\n }\n\n .h-10 {\n height: calc(var(--spacing) * 10);\n }\n\n .h-64 {\n height: calc(var(--spacing) * 64);\n }\n\n .h-\\[0\\.63em\\] {\n height: .63em;\n }\n\n .h-full {\n height: 100%;\n }\n\n .h-screen {\n height: 100vh;\n }\n\n .min-h-0 {\n min-height: 0;\n }\n\n .w-1\\/3 {\n width: 33.3333%;\n }\n\n .w-2 {\n width: calc(var(--spacing) * 2);\n }\n\n .w-2\\/5 {\n width: 40%;\n }\n\n .w-7\\/12 {\n width: 58.3333%;\n }\n\n .w-10 {\n width: calc(var(--spacing) * 10);\n }\n\n .w-11 {\n width: calc(var(--spacing) * 11);\n }\n\n .w-12 {\n width: calc(var(--spacing) * 12);\n }\n\n .w-40 {\n width: calc(var(--spacing) * 40);\n }\n\n .w-72 {\n width: calc(var(--spacing) * 72);\n }\n\n .w-full {\n width: 100%;\n }\n\n .max-w-90 {\n max-width: calc(var(--spacing) * 90);\n }\n\n .min-w-0 {\n min-width: 0;\n }\n\n .flex-1 {\n flex: 1;\n }\n\n .flex-auto {\n flex: auto;\n }\n\n .flex-shrink-0, .shrink-0 {\n flex-shrink: 0;\n }\n\n .grow {\n flex-grow: 1;\n }\n\n .-translate-x-1\\/2 {\n --tw-translate-x: calc(calc(1 / 2 * 100%) * -1);\n translate: var(--tw-translate-x) var(--tw-translate-y);\n }\n\n .scale-75 {\n --tw-scale-x: 75%;\n --tw-scale-y: 75%;\n --tw-scale-z: 75%;\n scale: var(--tw-scale-x) var(--tw-scale-y);\n }\n\n .transform {\n transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );\n }\n\n .animate-spin {\n animation: var(--animate-spin);\n }\n\n .cursor-help {\n cursor: help;\n }\n\n .cursor-pointer {\n cursor: pointer;\n }\n\n .list-none {\n list-style-type: none;\n }\n\n .flex-col {\n flex-direction: column;\n }\n\n .flex-row-reverse {\n flex-direction: row-reverse;\n }\n\n .flex-wrap {\n flex-wrap: wrap;\n }\n\n .items-center {\n align-items: center;\n }\n\n .justify-between {\n justify-content: space-between;\n }\n\n .justify-center {\n justify-content: center;\n }\n\n .justify-start {\n justify-content: flex-start;\n }\n\n .gap-1 {\n gap: var(--spacing);\n }\n\n .gap-2 {\n gap: calc(var(--spacing) * 2);\n }\n\n .gap-3 {\n gap: calc(var(--spacing) * 3);\n }\n\n .gap-5 {\n gap: calc(var(--spacing) * 5);\n }\n\n .gap-x-3 {\n column-gap: calc(var(--spacing) * 3);\n }\n\n .gap-y-5 {\n row-gap: calc(var(--spacing) * 5);\n }\n\n .overflow-hidden {\n overflow: hidden;\n }\n\n .overflow-x-auto {\n overflow-x: auto;\n }\n\n .overflow-x-hidden {\n overflow-x: hidden;\n }\n\n .overflow-y-auto {\n overflow-y: auto;\n }\n\n .rounded {\n border-radius: .25rem;\n }\n\n .rounded-full {\n border-radius: 3.40282e38px;\n }\n\n .rounded-md {\n border-radius: var(--radius-md);\n }\n\n .rounded-none {\n border-radius: 0;\n }\n\n .rounded-sm {\n border-radius: var(--radius-sm);\n }\n\n .rounded-r-xl {\n border-top-right-radius: var(--radius-xl);\n border-bottom-right-radius: var(--radius-xl);\n }\n\n .border {\n border-style: var(--tw-border-style);\n border-width: 1px;\n }\n\n .border-t {\n border-top-style: var(--tw-border-style);\n border-top-width: 1px;\n }\n\n .border-r {\n border-right-style: var(--tw-border-style);\n border-right-width: 1px;\n }\n\n .border-l {\n border-left-style: var(--tw-border-style);\n border-left-width: 1px;\n }\n\n .\\!border-none {\n --tw-border-style: none !important;\n border-style: none !important;\n }\n\n .border-t-\\[\\#303030\\] {\n border-top-color: #303030;\n }\n\n .border-t-colorBorderSecondary {\n border-top-color: var(--oo-colorBorderSecondary);\n }\n\n .border-r-\\[\\#303030\\] {\n border-right-color: #303030;\n }\n\n .border-r-colorBorderSecondary {\n border-right-color: var(--oo-colorBorderSecondary);\n }\n\n .border-l-colorBorderSecondary {\n border-left-color: var(--oo-colorBorderSecondary);\n }\n\n .bg-\\[\\#F3F4F5\\] {\n background-color: #f3f4f5;\n }\n\n .bg-blue-500\\/20 {\n background-color: rgb(var(--oo-blue-5));\n }\n\n @supports (color: color-mix(in lab, red, red)) {\n .bg-blue-500\\/20 {\n background-color: color-mix(in oklab, rgb(var(--oo-blue-5)) 20%, transparent);\n }\n }\n\n .bg-blue-600 {\n background-color: rgb(var(--oo-blue-6));\n }\n\n .bg-colorBgContainer {\n background-color: var(--oo-colorBgContainer);\n }\n\n .bg-colorBgLayout {\n background-color: var(--oo-colorBgLayout);\n }\n\n .bg-gray-100 {\n background-color: #f5f5f5;\n }\n\n .bg-gray-200 {\n background-color: #f0f0f0;\n }\n\n .bg-primary {\n background-color: rgb(var(--oo-colorPrimary));\n }\n\n .bg-primaryActive {\n background-color: rgb(var(--oo-colorPrimaryActive));\n }\n\n .object-cover {\n object-fit: cover;\n }\n\n .p-0 {\n padding: 0;\n }\n\n .p-1 {\n padding: var(--spacing);\n }\n\n .p-2 {\n padding: calc(var(--spacing) * 2);\n }\n\n .p-4 {\n padding: calc(var(--spacing) * 4);\n }\n\n .px-0 {\n padding-inline: 0;\n }\n\n .px-1 {\n padding-inline: var(--spacing);\n }\n\n .px-1\\.5 {\n padding-inline: calc(var(--spacing) * 1.5);\n }\n\n .px-2 {\n padding-inline: calc(var(--spacing) * 2);\n }\n\n .px-2\\.75 {\n padding-inline: calc(var(--spacing) * 2.75);\n }\n\n .px-3 {\n padding-inline: calc(var(--spacing) * 3);\n }\n\n .px-4 {\n padding-inline: calc(var(--spacing) * 4);\n }\n\n .px-6 {\n padding-inline: calc(var(--spacing) * 6);\n }\n\n .px-9 {\n padding-inline: calc(var(--spacing) * 9);\n }\n\n .px-10 {\n padding-inline: calc(var(--spacing) * 10);\n }\n\n .px-\\[11px\\] {\n padding-inline: 11px;\n }\n\n .py-1 {\n padding-block: var(--spacing);\n }\n\n .py-1\\.5 {\n padding-block: calc(var(--spacing) * 1.5);\n }\n\n .py-2 {\n padding-block: calc(var(--spacing) * 2);\n }\n\n .py-2\\.5 {\n padding-block: calc(var(--spacing) * 2.5);\n }\n\n .py-4 {\n padding-block: calc(var(--spacing) * 4);\n }\n\n .py-10 {\n padding-block: calc(var(--spacing) * 10);\n }\n\n .pb-4 {\n padding-bottom: calc(var(--spacing) * 4);\n }\n\n .pl-2 {\n padding-left: calc(var(--spacing) * 2);\n }\n\n .text-center {\n text-align: center;\n }\n\n .font-sans {\n font-family: var(--font-sans);\n }\n\n .text-3xl {\n font-size: var(--text-3xl);\n line-height: var(--tw-leading, var(--text-3xl--line-height));\n }\n\n .text-lg {\n font-size: var(--text-lg);\n line-height: var(--tw-leading, var(--text-lg--line-height));\n }\n\n .text-sm {\n font-size: var(--text-sm);\n line-height: var(--tw-leading, var(--text-sm--line-height));\n }\n\n .text-xl {\n font-size: var(--text-xl);\n line-height: var(--tw-leading, var(--text-xl--line-height));\n }\n\n .text-xs {\n font-size: var(--text-xs);\n line-height: var(--tw-leading, var(--text-xs--line-height));\n }\n\n .text-\\[4rem\\] {\n font-size: 4rem;\n }\n\n .leading-none {\n --tw-leading: 1;\n line-height: 1;\n }\n\n .font-bold {\n --tw-font-weight: var(--font-weight-bold);\n font-weight: var(--font-weight-bold);\n }\n\n .font-medium {\n --tw-font-weight: var(--font-weight-medium);\n font-weight: var(--font-weight-medium);\n }\n\n .font-semibold {\n --tw-font-weight: var(--font-weight-semibold);\n font-weight: var(--font-weight-semibold);\n }\n\n .tracking-tight {\n --tw-tracking: var(--tracking-tight);\n letter-spacing: var(--tracking-tight);\n }\n\n .text-colorBgContainer {\n color: var(--oo-colorBgContainer);\n }\n\n .text-colorBgContainer\\! {\n color: var(--oo-colorBgContainer) !important;\n }\n\n .text-colorText {\n color: var(--oo-colorText);\n }\n\n .text-colorText\\! {\n color: var(--oo-colorText) !important;\n }\n\n .text-colorTextSecondary {\n color: var(--oo-colorTextSecondary);\n }\n\n .text-colorTextTertiary {\n color: var(--oo-colorTextTertiary);\n }\n\n .text-gray-500 {\n color: #8c8c8c;\n }\n\n .opacity-50 {\n opacity: .5;\n }\n\n .opacity-90 {\n opacity: .9;\n }\n\n .outline, .outline-1 {\n outline-style: var(--tw-outline-style);\n outline-width: 1px;\n }\n\n .outline-2 {\n outline-style: var(--tw-outline-style);\n outline-width: 2px;\n }\n\n .outline-blue-600 {\n outline-color: rgb(var(--oo-blue-6));\n }\n\n .outline-gray-300 {\n outline-color: #d9d9d9;\n }\n\n .filter {\n filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );\n }\n\n .transition {\n transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, content-visibility, overlay, pointer-events;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n }\n\n .transition-all {\n transition-property: all;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n }\n\n .duration-300 {\n --tw-duration: .3s;\n transition-duration: .3s;\n }\n\n .ease-in {\n --tw-ease: var(--ease-in);\n transition-timing-function: var(--ease-in);\n }\n\n @media (hover: hover) {\n .group-hover\\:animate-wiggle:is(:where(.group):hover *) {\n animation: var(--animate-wiggle);\n }\n\n .group-hover\\:opacity-100:is(:where(.group):hover *) {\n opacity: 1;\n }\n }\n\n .before\\:absolute:before {\n content: var(--tw-content);\n position: absolute;\n }\n\n .before\\:top-1\\/2:before {\n content: var(--tw-content);\n top: 50%;\n }\n\n .before\\:left-1\\/2:before {\n content: var(--tw-content);\n left: 50%;\n }\n\n .before\\:h-0:before {\n content: var(--tw-content);\n height: 0;\n }\n\n .before\\:w-0:before {\n content: var(--tw-content);\n width: 0;\n }\n\n .before\\:rounded-sm:before {\n content: var(--tw-content);\n border-radius: var(--radius-sm);\n }\n\n .before\\:opacity-0:before {\n content: var(--tw-content);\n opacity: 0;\n }\n\n .before\\:outline:before {\n content: var(--tw-content);\n outline-style: var(--tw-outline-style);\n outline-width: 1px;\n }\n\n .before\\:outline-2:before {\n content: var(--tw-content);\n outline-style: var(--tw-outline-style);\n outline-width: 2px;\n }\n\n .before\\:outline-transparent:before {\n content: var(--tw-content);\n outline-color: #0000;\n }\n\n .before\\:transition-all:before {\n content: var(--tw-content);\n transition-property: all;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n }\n\n .before\\:duration-300:before {\n content: var(--tw-content);\n --tw-duration: .3s;\n transition-duration: .3s;\n }\n\n .before\\:content-\\[\\'\\'\\]:before {\n --tw-content: \"\";\n content: var(--tw-content);\n }\n\n .last\\:mr-auto:last-child {\n margin-right: auto;\n }\n\n @media (hover: hover) {\n .hover\\:bg-gray-100:hover {\n background-color: #f5f5f5;\n }\n\n .hover\\:text-colorText:hover {\n color: var(--oo-colorText);\n }\n }\n\n .before\\:hover\\:top-0:before {\n content: var(--tw-content);\n }\n\n @media (hover: hover) {\n .before\\:hover\\:top-0:before:hover {\n top: 0;\n }\n }\n\n .before\\:hover\\:left-0:before {\n content: var(--tw-content);\n }\n\n @media (hover: hover) {\n .before\\:hover\\:left-0:before:hover {\n left: 0;\n }\n }\n\n .before\\:hover\\:h-full:before {\n content: var(--tw-content);\n }\n\n @media (hover: hover) {\n .before\\:hover\\:h-full:before:hover {\n height: 100%;\n }\n }\n\n .before\\:hover\\:w-full:before {\n content: var(--tw-content);\n }\n\n @media (hover: hover) {\n .before\\:hover\\:w-full:before:hover {\n width: 100%;\n }\n }\n\n .before\\:hover\\:p-1:before {\n content: var(--tw-content);\n }\n\n @media (hover: hover) {\n .before\\:hover\\:p-1:before:hover {\n padding: var(--spacing);\n }\n }\n\n .before\\:hover\\:opacity-100:before {\n content: var(--tw-content);\n }\n\n @media (hover: hover) {\n .before\\:hover\\:opacity-100:before:hover {\n opacity: 1;\n }\n }\n\n .before\\:hover\\:outline-blue-600:before {\n content: var(--tw-content);\n }\n\n @media (hover: hover) {\n .before\\:hover\\:outline-blue-600:before:hover {\n outline-color: rgb(var(--oo-blue-6));\n }\n }\n\n @media (prefers-reduced-motion: no-preference) {\n .motion-safe\\:animate-bounce-in-down-out-up {\n animation: var(--animate-bounce-in-down-out-up);\n }\n }\n\n @media (min-width: 576px) {\n .sm\\:mx-auto {\n margin-inline: auto;\n }\n }\n\n @media (min-width: 768px) {\n .md\\:mr-2\\.5 {\n margin-right: calc(var(--spacing) * 2.5);\n }\n\n .md\\:block {\n display: block;\n }\n\n .md\\:w-3\\/12 {\n width: 25%;\n }\n\n .md\\:w-96 {\n width: calc(var(--spacing) * 96);\n }\n\n .md\\:max-w-md {\n max-width: var(--container-md);\n }\n\n .md\\:bg-colorBgLayout {\n background-color: var(--oo-colorBgLayout);\n }\n\n .md\\:px-4 {\n padding-inline: calc(var(--spacing) * 4);\n }\n\n .md\\:pb-0 {\n padding-bottom: 0;\n }\n\n .md\\:text-sm {\n font-size: var(--text-sm);\n line-height: var(--tw-leading, var(--text-sm--line-height));\n }\n }\n\n @media (min-width: 992px) {\n .lg\\:text-2xl {\n font-size: var(--text-2xl);\n line-height: var(--tw-leading, var(--text-2xl--line-height));\n }\n }\n\n @media (min-width: 1200px) {\n .xl\\:w-2\\/12 {\n width: 16.6667%;\n }\n\n .xl\\:px-8 {\n padding-inline: calc(var(--spacing) * 8);\n }\n }\n\n .dark\\:bg-\\[\\#26313C\\]:where(.dark, .dark *) {\n background-color: #26313c;\n }\n\n .dark\\:bg-black:where(.dark, .dark *) {\n background-color: #000;\n }\n\n .dark\\:bg-gray-700:where(.dark, .dark *) {\n background-color: #434343;\n }\n\n .dark\\:outline-blue-700:where(.dark, .dark *) {\n outline-color: rgb(var(--oo-blue-7));\n }\n\n .dark\\:outline-gray-700:where(.dark, .dark *) {\n outline-color: #434343;\n }\n\n @media (hover: hover) {\n .dark\\:hover\\:bg-gray-700:where(.dark, .dark *):hover {\n background-color: #434343;\n }\n }\n\n .dark\\:before\\:hover\\:outline-blue-700:where(.dark, .dark *):before {\n content: var(--tw-content);\n }\n\n @media (hover: hover) {\n .dark\\:before\\:hover\\:outline-blue-700:where(.dark, .dark *):before:hover {\n outline-color: rgb(var(--oo-blue-7));\n }\n }\n\n .en-US\\:gap-y-3:where(:lang(en-US)) {\n row-gap: calc(var(--spacing) * 3);\n }\n\n .en-US\\:text-\\[9rem\\]:where(:lang(en-US)) {\n font-size: 9rem;\n }\n\n .zh-CN\\:hidden:where(:lang(zh-CN)) {\n display: none;\n }\n}\n\n@keyframes fade-in {\n from {\n opacity: 0;\n }\n\n to {\n opacity: 1;\n }\n}\n\n@keyframes fade-out {\n from {\n opacity: 1;\n }\n\n to {\n opacity: 0;\n }\n}\n\n@keyframes slide-in {\n from {\n transform: translateX(-30px);\n }\n\n to {\n transform: translateX(0);\n }\n}\n\n@keyframes slide-out {\n from {\n transform: translateX(0);\n }\n\n to {\n transform: translateX(30px);\n }\n}\n\n@keyframes slide-top-in {\n from {\n transform: translateY(-10%);\n }\n\n to {\n transform: translateY(0);\n }\n}\n\n@keyframes slide-top-out {\n from {\n transform: translateY(0);\n }\n\n to {\n transform: translateY(-10%);\n }\n}\n\n@keyframes slide-bottom-in {\n from {\n transform: translateY(10%);\n }\n\n to {\n transform: translateY(0);\n }\n}\n\n@keyframes slide-bottom-out {\n from {\n transform: translateY(0);\n }\n\n to {\n transform: translateY(10%);\n }\n}\n\n@keyframes fade-slide {\n 0% {\n opacity: 0;\n transform: translate(-30px);\n }\n\n 50% {\n opacity: 1;\n }\n\n 100% {\n opacity: 0;\n transform: translate(30px);\n }\n}\n\n@keyframes fade-up {\n 0% {\n opacity: 0;\n transform: translateY(10%);\n }\n\n 50% {\n opacity: 1;\n }\n\n 100% {\n opacity: 0;\n transform: translateY(-10%);\n }\n}\n\n@keyframes fade-down {\n 0% {\n opacity: 0;\n transform: translateY(-10%);\n }\n\n 50% {\n opacity: 1;\n }\n\n 100% {\n opacity: 0;\n transform: translateY(10%);\n }\n}\n\n.fade-slide {\n animation: 3s linear infinite fade-slide;\n}\n\n.fade {\n animation: 3s linear infinite alternate fade-in;\n}\n\n.fade-up {\n animation: 3s infinite fade-up;\n}\n\n.fade-down {\n animation: 3s infinite fade-down;\n}\n\n@keyframes zoom-in {\n 0% {\n transform: scale(.8);\n }\n\n 100% {\n opacity: 1;\n transform: scale(1);\n }\n}\n\n@keyframes zoom-out {\n 0% {\n transform: scale(1);\n }\n\n 100% {\n opacity: 1;\n transform: scale(1.25);\n }\n}\n\n@keyframes fade-zoom {\n 0% {\n opacity: 0;\n transform: scale(.8);\n }\n\n 50% {\n opacity: 1;\n transform: scale(1);\n }\n\n 100% {\n opacity: 0;\n transform: scale(1.25);\n }\n}\n\n.fade-zoom {\n animation: 3s infinite fade-zoom;\n}\n\n.keepalive-fade.active {\n animation: .3s ease-in-out fade-in;\n}\n\n.keepalive-fade.inactive {\n animation: .3s ease-in-out fade-out;\n}\n\n.keepalive-fade-slide.active {\n animation: .3s ease-in-out fade-in, .3s ease-in-out slide-in;\n}\n\n.keepalive-fade-slide.inactive {\n animation: .3s ease-in-out fade-out, .3s ease-in-out slide-out;\n}\n\n.keepalive-fade-up.active {\n animation: .3s ease-in-out fade-in, .3s ease-in-out slide-bottom-in;\n}\n\n.keepalive-fade-up.inactive {\n animation: .3s ease-in-out fade-out, .3s ease-in-out slide-top-out;\n}\n\n.keepalive-fade-down.active {\n animation: .3s ease-in-out fade-in, .3s ease-in-out slide-top-in;\n}\n\n.keepalive-fade-down.inactive {\n animation: .3s ease-in-out fade-out, .3s ease-in-out slide-bottom-out;\n}\n\n.keepalive-fade-zoom.active {\n animation: .3s ease-in-out zoom-in, .3s ease-in-out zoom-in;\n}\n\n.keepalive-fade-zoom.inactive {\n animation: .3s ease-in-out zoom-out, .3s ease-in-out fade-out;\n}\n\n@property --tw-blur {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-brightness {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-contrast {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-grayscale {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-hue-rotate {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-invert {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-opacity {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-saturate {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-sepia {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-drop-shadow {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-drop-shadow-color {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-drop-shadow-alpha {\n syntax: \"<percentage>\";\n inherits: false;\n initial-value: 100%;\n}\n\n@property --tw-drop-shadow-size {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-translate-x {\n syntax: \"*\";\n inherits: false;\n initial-value: 0;\n}\n\n@property --tw-translate-y {\n syntax: \"*\";\n inherits: false;\n initial-value: 0;\n}\n\n@property --tw-translate-z {\n syntax: \"*\";\n inherits: false;\n initial-value: 0;\n}\n\n@property --tw-scale-x {\n syntax: \"*\";\n inherits: false;\n initial-value: 1;\n}\n\n@property --tw-scale-y {\n syntax: \"*\";\n inherits: false;\n initial-value: 1;\n}\n\n@property --tw-scale-z {\n syntax: \"*\";\n inherits: false;\n initial-value: 1;\n}\n\n@property --tw-rotate-x {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-rotate-y {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-rotate-z {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-skew-x {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-skew-y {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-border-style {\n syntax: \"*\";\n inherits: false;\n initial-value: solid;\n}\n\n@property --tw-leading {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-font-weight {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-tracking {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-outline-style {\n syntax: \"*\";\n inherits: false;\n initial-value: solid;\n}\n\n@property --tw-duration {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-ease {\n syntax: \"*\";\n inherits: false\n}\n\n@property --tw-content {\n syntax: \"*\";\n inherits: false;\n initial-value: \"\";\n}\n\n@keyframes spin {\n to {\n transform: rotate(360deg);\n }\n}\n\n@keyframes wiggle {\n 0%, 100% {\n transform-origin: top;\n }\n\n 15% {\n transform: rotateZ(10deg);\n }\n\n 30% {\n transform: rotateZ(-10deg);\n }\n\n 45% {\n transform: rotateZ(5deg);\n }\n\n 60% {\n transform: rotateZ(-5deg);\n }\n\n 75% {\n transform: rotateZ(2deg);\n }\n}\n\n@keyframes bounce-in-down-out-up {\n 0% {\n transform: translateY(0);\n }\n\n 50% {\n transform: translateY(-20px);\n }\n\n 100% {\n transform: translateY(0);\n }\n}\n\n@layer properties {\n @supports (((-webkit-hyphens: none)) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color: rgb(from red r g b)))) {\n *, :before, :after, ::backdrop {\n --tw-blur: initial;\n --tw-brightness: initial;\n --tw-contrast: initial;\n --tw-grayscale: initial;\n --tw-hue-rotate: initial;\n --tw-invert: initial;\n --tw-opacity: initial;\n --tw-saturate: initial;\n --tw-sepia: initial;\n --tw-drop-shadow: initial;\n --tw-drop-shadow-color: initial;\n --tw-drop-shadow-alpha: 100%;\n --tw-drop-shadow-size: initial;\n --tw-translate-x: 0;\n --tw-translate-y: 0;\n --tw-translate-z: 0;\n --tw-scale-x: 1;\n --tw-scale-y: 1;\n --tw-scale-z: 1;\n --tw-rotate-x: initial;\n --tw-rotate-y: initial;\n --tw-rotate-z: initial;\n --tw-skew-x: initial;\n --tw-skew-y: initial;\n --tw-border-style: solid;\n --tw-leading: initial;\n --tw-font-weight: initial;\n --tw-tracking: initial;\n --tw-outline-style: solid;\n --tw-duration: initial;\n --tw-ease: initial;\n --tw-content: \"\";\n }\n }\n}\n/*$vite$:1*/";
6
6
  document.head.appendChild(s);
7
7
  }
8
8
  import ky from "ky";
@@ -11,7 +11,7 @@ import { persist } from "zustand/middleware";
11
11
  import { Link, Navigate, Outlet, createBrowserRouter, matchRoutes, useLocation, useMatches, useNavigate, useOutlet, useSearchParams } from "react-router";
12
12
  import { ErrorBoundary, ErrorBoundary as ErrorBoundary$1 } from "react-error-boundary";
13
13
  import { AntDesignOutlined, ApartmentOutlined, AppstoreOutlined, ArrowDownOutlined, ArrowLeftOutlined, ArrowUpOutlined, BellOutlined, CloseOutlined, CloudOutlined, ContainerOutlined, CopyOutlined, CopyrightOutlined, DownOutlined, EnterOutlined, ExclamationCircleFilled, EyeOutlined, FileTextOutlined, FullscreenExitOutlined, FullscreenOutlined, HomeOutlined, LoadingOutlined, LockOutlined, LogoutOutlined, MenuFoldOutlined, MenuOutlined, MenuUnfoldOutlined, NodeExpandOutlined, QuestionCircleOutlined, RedoOutlined, ReloadOutlined, RocketOutlined, SafetyOutlined, SearchOutlined, SettingOutlined, SisternodeOutlined, SubnodeOutlined, SwapOutlined, TeamOutlined, TranslationOutlined, UploadOutlined, UserOutlined, VerticalAlignBottomOutlined, VerticalAlignMiddleOutlined, VerticalAlignTopOutlined } from "@ant-design/icons";
14
- import { App, Avatar, Badge, Breadcrumb, Button, Checkbox, Col, ColorPicker, ConfigProvider, Divider, Drawer, Dropdown, Empty, FloatButton, Form, Grid, Input, InputNumber, List, Menu, Modal, Popover, Result, Row, Select, Slider, Space, Spin, Switch, Tabs, Tooltip, Tree, Typography, Upload, Watermark, message, notification, theme } from "antd";
14
+ import { App, Avatar, Badge, Breadcrumb, Button, Checkbox, Col, ColorPicker, ConfigProvider, Divider, Drawer, Dropdown, Empty, FloatButton, Form, Grid, Input, InputNumber, List, Menu, Modal, Popover, Result, Row, Select, Slider, Space, Spin, Switch, Tabs, Tag, Tooltip, Tree, Typography, Upload, Watermark, message, notification, theme } from "antd";
15
15
  import { Children, Suspense, cloneElement, createElement, forwardRef, isValidElement, lazy, use, useCallback, useEffect, useMemo, useRef, useState } from "react";
16
16
  import { initReactI18next, useTranslation } from "react-i18next";
17
17
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -256,10 +256,10 @@ function getAppInfo() {
256
256
  return {
257
257
  "pkg": {
258
258
  "name": "@oj-module/runtime",
259
- "version": "0.2.8",
259
+ "version": "0.2.15",
260
260
  "license": "MIT"
261
261
  },
262
- "lastBuildTime": "2026-10-20 00:16:33"
262
+ "lastBuildTime": "2026-10-21 12:22:16"
263
263
  };
264
264
  }
265
265
  var init_get_app_info = __esmMin((() => {}));
@@ -875,7 +875,7 @@ var init_preferences$2 = __esmMin((() => {
875
875
  }));
876
876
  //#endregion
877
877
  //#region src/locales/zh-CN/widgets.json
878
- var document$2, qa$1, setting$1, logoutTip$1, viewAll$1, notifications$1, markAllAsRead$1, clearNotifications$1, versionMonitorTitle$1, versionMonitorContent$1, versionMonitorConfirm$1, versionMonitorCancel$1, search$2, widgets_default$1;
878
+ var document$2, qa$1, setting$1, logoutTip$1, viewAll$1, notifications$1, notiCategory$1, markAllAsRead$1, clearNotifications$1, versionMonitorTitle$1, versionMonitorContent$1, versionMonitorConfirm$1, versionMonitorCancel$1, search$2, widgets_default$1;
879
879
  var init_widgets$1 = __esmMin((() => {
880
880
  document$2 = "文档";
881
881
  qa$1 = "问题 & 帮助";
@@ -883,6 +883,11 @@ var init_widgets$1 = __esmMin((() => {
883
883
  logoutTip$1 = "是否退出登录?";
884
884
  viewAll$1 = "查看所有消息";
885
885
  notifications$1 = "通知";
886
+ notiCategory$1 = {
887
+ "notice": "通知",
888
+ "pm": "私信",
889
+ "mention": "@我"
890
+ };
886
891
  markAllAsRead$1 = "全部标记为已读";
887
892
  clearNotifications$1 = "清空";
888
893
  versionMonitorTitle$1 = "系统版本更新通知";
@@ -906,6 +911,7 @@ var init_widgets$1 = __esmMin((() => {
906
911
  logoutTip: logoutTip$1,
907
912
  viewAll: viewAll$1,
908
913
  notifications: notifications$1,
914
+ notiCategory: notiCategory$1,
909
915
  markAllAsRead: markAllAsRead$1,
910
916
  clearNotifications: clearNotifications$1,
911
917
  versionMonitorTitle: versionMonitorTitle$1,
@@ -1309,13 +1315,18 @@ var init_preferences$1 = __esmMin((() => {
1309
1315
  general,
1310
1316
  footer
1311
1317
  };
1312
- })), document$1, setting, logoutTip, viewAll, notifications, markAllAsRead, clearNotifications, versionMonitorTitle, versionMonitorContent, versionMonitorConfirm, versionMonitorCancel, search, widgets_default;
1318
+ })), document$1, setting, logoutTip, viewAll, notifications, notiCategory, markAllAsRead, clearNotifications, versionMonitorTitle, versionMonitorContent, versionMonitorConfirm, versionMonitorCancel, search, widgets_default;
1313
1319
  var init_widgets = __esmMin((() => {
1314
1320
  document$1 = "Document";
1315
1321
  setting = "Settings";
1316
1322
  logoutTip = "Do you want to logout?";
1317
1323
  viewAll = "View All Messages";
1318
1324
  notifications = "Notifications";
1325
+ notiCategory = {
1326
+ "notice": "Notice",
1327
+ "pm": "Direct",
1328
+ "mention": "Mentions"
1329
+ };
1319
1330
  markAllAsRead = "Make All as Read";
1320
1331
  clearNotifications = "Clear";
1321
1332
  versionMonitorTitle = "System Version Update Notification";
@@ -1339,6 +1350,7 @@ var init_widgets = __esmMin((() => {
1339
1350
  logoutTip,
1340
1351
  viewAll,
1341
1352
  notifications,
1353
+ notiCategory,
1342
1354
  markAllAsRead,
1343
1355
  clearNotifications,
1344
1356
  versionMonitorTitle,
@@ -1511,17 +1523,29 @@ var init_terms_of_service = __esmMin((() => {
1511
1523
  }));
1512
1524
  //#endregion
1513
1525
  //#region src/router/utils/ascending.ts
1514
- /** 按照路由中 order 升序来排序路由 */
1526
+ /**
1527
+ * 按照路由中 order 升序来排序路由(双段序轴,2026-10-20):
1528
+ * - order >= 0:主菜单区,升序在前;
1529
+ * - order < 0 :底部固定区,升序在后(-2 在 -1 上面)——渲染层
1530
+ * (layout-sidebar / layout-mixed-sidebar 第二列)把这一段 pin 在
1531
+ * 侧边栏底部,其余菜单形态按列表末尾回落;
1532
+ * - 未声明 order:沿用数组下标兜底(下标 + 2)。order: 0 是合法值,
1533
+ * 用 ?? 判定(历史实现用 ||,0 会被误当「未设置」改写成兜底值)。
1534
+ */
1515
1535
  function ascending(arr) {
1516
- return arr.map((routeItem, routeIndex) => ({
1536
+ const normalized = arr.map((routeItem, routeIndex) => ({
1517
1537
  ...routeItem,
1518
1538
  handle: {
1519
1539
  ...routeItem.handle,
1520
- order: routeItem?.handle?.order || routeIndex + 2
1540
+ order: routeItem?.handle?.order ?? routeIndex + 2
1521
1541
  }
1522
- })).sort((a, b) => {
1523
- return a?.handle?.order - b?.handle?.order;
1524
- });
1542
+ }));
1543
+ const byOrder = (a, b) => {
1544
+ const delta = (a.handle.order ?? 0) - (b.handle.order ?? 0);
1545
+ if (delta !== 0) return delta;
1546
+ return (a.path ?? "").localeCompare(b.path ?? "");
1547
+ };
1548
+ return [...normalized.filter((routeItem) => (routeItem.handle.order ?? 0) >= 0).sort(byOrder), ...normalized.filter((routeItem) => (routeItem.handle.order ?? 0) < 0).sort(byOrder)];
1525
1549
  }
1526
1550
  var init_ascending = __esmMin((() => {}));
1527
1551
  //#endregion
@@ -4273,6 +4297,7 @@ function transformMenuToFlatMenu(menus, flatMap = []) {
4273
4297
  }
4274
4298
  function GlobalSearch() {
4275
4299
  const wholeMenus = useAccessStore((state) => state.wholeMenus);
4300
+ const bottomMenus = useAccessStore((state) => state.bottomMenus);
4276
4301
  const { isMobile } = useDeviceType();
4277
4302
  const [open, setOpen] = useState(false);
4278
4303
  const navigate = useNavigate();
@@ -4283,7 +4308,7 @@ function GlobalSearch() {
4283
4308
  const inputRef = useRef(null);
4284
4309
  const listRef = useRef(null);
4285
4310
  const [searchHistory = [], setSearchHistory] = useLocalStorageState(searchHistoryLocalStorageKey, { defaultValue: [] });
4286
- const searchMenuList = useMemo(() => transformMenuToFlatMenu(wholeMenus), [wholeMenus]);
4311
+ const searchMenuList = useMemo(() => transformMenuToFlatMenu([...wholeMenus, ...bottomMenus]), [wholeMenus, bottomMenus]);
4287
4312
  function onClose() {
4288
4313
  setOpen(false);
4289
4314
  }
@@ -4491,11 +4516,12 @@ var init_notifications = __esmMin((() => {
4491
4516
  }));
4492
4517
  //#endregion
4493
4518
  //#region src/layout/widgets/notification/index.tsx
4494
- var useStyles$5, NotificationPopup;
4519
+ var NOTIFICATION_CENTER_PATH, useStyles$5, NotificationPopup;
4495
4520
  var init_notification = __esmMin((() => {
4496
4521
  init_basic_button();
4497
4522
  init_icons();
4498
4523
  init_cn();
4524
+ NOTIFICATION_CENTER_PATH = "/notification-center";
4499
4525
  useStyles$5 = createUseStyles(({ token }) => ({ notification: {
4500
4526
  "& .ant-popover-inner": { padding: 0 },
4501
4527
  "& .ant-list-footer": { borderTop: `1px solid ${token.colorBorder}` },
@@ -4504,16 +4530,17 @@ var init_notification = __esmMin((() => {
4504
4530
  overflowY: "auto"
4505
4531
  }
4506
4532
  } }));
4507
- NotificationPopup = ({ dot, notifications, onEventChange, ...restProps }) => {
4533
+ NotificationPopup = ({ dot, notifications, onEventChange, onOpenChange, ...restProps }) => {
4508
4534
  const [open, action] = useToggle();
4509
4535
  const classes = useStyles$5();
4510
4536
  const { t } = useTranslation();
4511
4537
  const readOnly = !onEventChange;
4538
+ const navigate = useNavigate();
4512
4539
  const close = () => {
4513
4540
  action.set(false);
4514
4541
  };
4515
4542
  const handleViewAll = () => {
4516
- onEventChange && onEventChange("viewAll");
4543
+ navigate(NOTIFICATION_CENTER_PATH);
4517
4544
  close();
4518
4545
  };
4519
4546
  const handleMakeAll = () => {
@@ -4529,6 +4556,15 @@ var init_notification = __esmMin((() => {
4529
4556
  onEventChange && onEventChange("read", item);
4530
4557
  if (item.link) window.open(item.link, "_blank", "noopener");
4531
4558
  };
4559
+ const categoryTag = (item) => {
4560
+ if (!item.category) return null;
4561
+ const color = item.category === "pm" ? "magenta" : item.category === "mention" ? "orange" : "blue";
4562
+ return /* @__PURE__ */ jsx(Tag, {
4563
+ color,
4564
+ className: "ml-1 text-xs",
4565
+ children: t(`widgets.notiCategory.${item.category}`)
4566
+ });
4567
+ };
4532
4568
  dot = useMemo(() => {
4533
4569
  return !!notifications?.filter((item) => !item?.isRead).length;
4534
4570
  }, [notifications]);
@@ -4538,7 +4574,10 @@ var init_notification = __esmMin((() => {
4538
4574
  open,
4539
4575
  arrow: false,
4540
4576
  trigger: "click",
4541
- onOpenChange: action.set,
4577
+ onOpenChange: (o) => {
4578
+ action.set(o);
4579
+ onOpenChange?.(o);
4580
+ },
4542
4581
  content: /* @__PURE__ */ jsx(List, {
4543
4582
  size: "small",
4544
4583
  bordered: true,
@@ -4574,18 +4613,21 @@ var init_notification = __esmMin((() => {
4574
4613
  !item.isRead && /* @__PURE__ */ jsx("span", { className: "absolute w-2 h-2 rounded bg-primary right-2 top-2" }),
4575
4614
  /* @__PURE__ */ jsx("span", {
4576
4615
  className: "relative flex w-10 h-10 overflow-hidden rounded-full shrink-0",
4577
- children: /* @__PURE__ */ jsx("img", {
4616
+ children: item.avatar ? /* @__PURE__ */ jsx("img", {
4578
4617
  src: item.avatar,
4579
4618
  className: "object-cover w-full h-full aspect-square",
4580
4619
  role: "img"
4620
+ }) : /* @__PURE__ */ jsx("span", {
4621
+ className: "flex w-full h-full items-center justify-center bg-gray-200 dark:bg-gray-700 text-gray-500",
4622
+ children: /* @__PURE__ */ jsx(BellOutlined, {})
4581
4623
  })
4582
4624
  }),
4583
4625
  /* @__PURE__ */ jsxs("div", {
4584
4626
  className: "flex flex-col gap-1 leading-none",
4585
4627
  children: [
4586
- /* @__PURE__ */ jsx("p", {
4587
- className: "font-semibold",
4588
- children: item.title
4628
+ /* @__PURE__ */ jsxs("p", {
4629
+ className: "font-semibold flex items-center",
4630
+ children: [item.title, categoryTag(item)]
4589
4631
  }),
4590
4632
  /* @__PURE__ */ jsx("p", {
4591
4633
  className: "my-1 text-xs text-muted-foreground line-clamp-2",
@@ -4620,7 +4662,8 @@ var init_notification = __esmMin((() => {
4620
4662
  * (popup 按 onEventChange 是否存在推导,评审 A3——不加新 prop);
4621
4663
  * - 写操作成功后重拉刷新;**重拉失败不清空现有列表**(评审 b4);
4622
4664
  * - 20x 复制残留已删除(评审 b4,同一 id 复制 20 份会让 markRead 语义失真);
4623
- * - viewAll 不接线(N3,模板无通知中心页)。
4665
+ * - viewAll 由弹层内直接导航到通知中心页(N3 落地,不经过 provider——
4666
+ * 本组件的 onEventChange 仍只承载写事件,read-only 推导不受影响)。
4624
4667
  */
4625
4668
  function NotificationContainer({ ...restProps }) {
4626
4669
  const [notifications, setNotifications] = useState([]);
@@ -4646,6 +4689,7 @@ function NotificationContainer({ ...restProps }) {
4646
4689
  if (!p) return;
4647
4690
  (event === "read" ? () => p.markRead(item.id) : event === "makeAll" ? () => p.markAllRead() : event === "clear" ? () => p.clearAll() : void 0)?.().then(reload).catch(() => {});
4648
4691
  } : void 0,
4692
+ onOpenChange: (open) => open && reload(),
4649
4693
  ...restProps
4650
4694
  });
4651
4695
  }
@@ -5853,12 +5897,13 @@ function LayoutMenu({ mode = "inline", autoExpandCurrentMenu, handleMenuSelect,
5853
5897
  const classes = useStyles$4();
5854
5898
  const matches = useMatches();
5855
5899
  const wholeMenus = useAccessStore((state) => state.wholeMenus);
5900
+ const bottomMenus = useAccessStore((state) => state.bottomMenus);
5856
5901
  const { sidebarCollapsed, sidebarTheme, isDark, accordion } = usePreferences();
5857
5902
  const [openKeys, setOpenKeys] = useState([]);
5858
5903
  const { isMobile } = useDeviceType();
5859
5904
  const menuParentKeys = useMemo(() => {
5860
- return getParentKeys(wholeMenus);
5861
- }, [wholeMenus]);
5905
+ return getParentKeys([...wholeMenus, ...bottomMenus]);
5906
+ }, [wholeMenus, bottomMenus]);
5862
5907
  const getSelectedKeys = useMemo(() => {
5863
5908
  const currentActiveMatch = matches.findLast((routeItem) => routeItem.handle?.currentActiveMenu);
5864
5909
  if (currentActiveMatch?.handle?.currentActiveMenu) {
@@ -5969,10 +6014,13 @@ var init_layout_menu = __esmMin((() => {
5969
6014
  //#region src/layout/layout-menu/use-menu.ts
5970
6015
  function useMenu() {
5971
6016
  const wholeMenus = useAccessStore((state) => state.wholeMenus);
6017
+ const bottomMenus = useAccessStore((state) => state.bottomMenus);
5972
6018
  const { isMixedNav, isTwoColumnNav } = useLayout();
5973
6019
  const navigate = useNavigate();
5974
6020
  const { t } = useTranslation();
5975
6021
  const translatedMenus = translateMenus(wholeMenus, t);
6022
+ const translatedBottomMenus = translateMenus(bottomMenus, t);
6023
+ const bottomBandMenuItems = useMemo(() => [...translatedMenus, ...translatedBottomMenus], [translatedMenus, translatedBottomMenus]);
5976
6024
  const { pathname } = useCurrentRoute();
5977
6025
  const matches = useMatches();
5978
6026
  /**
@@ -5986,32 +6034,33 @@ function useMenu() {
5986
6034
  if (!shouldSplitMenuItems) return "";
5987
6035
  const activeMenuPath = matches.findLast((routeItem) => routeItem.handle?.currentActiveMenu)?.handle?.currentActiveMenu;
5988
6036
  const targetPath = activeMenuPath ? removeTrailingSlash(activeMenuPath) : removeTrailingSlash(pathname);
5989
- const { rootMenuPath } = findRootMenuByPath(translatedMenus, targetPath);
6037
+ const { rootMenuPath } = findRootMenuByPath(bottomBandMenuItems, targetPath);
5990
6038
  return rootMenuPath ?? "";
5991
6039
  }, [
5992
6040
  shouldSplitMenuItems,
5993
6041
  pathname,
5994
- matches
6042
+ matches,
6043
+ bottomBandMenuItems
5995
6044
  ]);
5996
6045
  const splitSideNavItems = useMemo(() => {
5997
- const foundMenu = translatedMenus.find((item) => item?.key === sideNavMenuKeyInSplitMode);
6046
+ const foundMenu = bottomBandMenuItems.find((item) => item?.key === sideNavMenuKeyInSplitMode);
5998
6047
  if (!foundMenu) return [];
5999
6048
  return foundMenu?.children ?? [foundMenu];
6000
- }, [sideNavMenuKeyInSplitMode, translatedMenus]);
6049
+ }, [sideNavMenuKeyInSplitMode, bottomBandMenuItems]);
6001
6050
  /**
6002
- * 头部菜单
6051
+ * 头部菜单(含底部区条目回落到末尾:顶部导航/双列第一列无底槽)
6003
6052
  */
6004
6053
  const topNavItems = useMemo(() => {
6005
- if (!shouldSplitMenuItems) return translatedMenus;
6006
- return translatedMenus.map((item) => {
6054
+ if (!shouldSplitMenuItems) return bottomBandMenuItems;
6055
+ return bottomBandMenuItems.map((item) => {
6007
6056
  return {
6008
6057
  ...item,
6009
6058
  children: void 0
6010
6059
  };
6011
6060
  });
6012
- }, [shouldSplitMenuItems, translatedMenus]);
6061
+ }, [shouldSplitMenuItems, bottomBandMenuItems]);
6013
6062
  /**
6014
- * 侧边菜单
6063
+ * 侧边菜单(仅主区:底部固定区由侧边栏底槽单独渲染)
6015
6064
  */
6016
6065
  const sideNavItems = useMemo(() => {
6017
6066
  return shouldSplitMenuItems ? splitSideNavItems : translatedMenus;
@@ -6021,15 +6070,20 @@ function useMenu() {
6021
6070
  translatedMenus
6022
6071
  ]);
6023
6072
  /**
6073
+ * 底部固定区菜单(主区之后、SiderTrigger 之上渲染)
6074
+ */
6075
+ const bottomNavItems = translatedBottomMenus;
6076
+ /**
6024
6077
  * 菜单点击事件处理
6025
6078
  */
6026
6079
  const handleMenuSelect = (key, mode) => {
6080
+ if (key.startsWith("solgroup:")) return;
6027
6081
  if (key === removeTrailingSlash(pathname)) return;
6028
6082
  if (!shouldSplitMenuItems || mode !== "horizontal") {
6029
6083
  if (/http(s)?:/.test(key)) window.open(key);
6030
6084
  else navigate(key);
6031
6085
  } else {
6032
- const targetMenu = findDeepestFirstItem(translatedMenus.find((item) => item?.key === key)?.children ?? []);
6086
+ const targetMenu = findDeepestFirstItem(bottomBandMenuItems.find((item) => item?.key === key)?.children ?? []);
6033
6087
  if (!targetMenu) navigate(key);
6034
6088
  else navigate(targetMenu.key);
6035
6089
  }
@@ -6038,7 +6092,8 @@ function useMenu() {
6038
6092
  handleMenuSelect,
6039
6093
  sideNavMenuKeyInSplitMode,
6040
6094
  topNavItems,
6041
- sideNavItems
6095
+ sideNavItems,
6096
+ bottomNavItems
6042
6097
  };
6043
6098
  }
6044
6099
  var init_use_menu = __esmMin((() => {
@@ -6222,7 +6277,8 @@ function LayoutMobileMenu() {
6222
6277
  const { token: { Menu } } = theme.useToken();
6223
6278
  const { sidebarCollapsed, setPreferences, isDark, sidebarTheme } = usePreferences();
6224
6279
  const { isMobile } = useDeviceType();
6225
- const { sideNavItems, handleMenuSelect } = useMenu();
6280
+ const { sideNavItems, bottomNavItems, handleMenuSelect } = useMenu();
6281
+ const menuItems = useMemo(() => [...sideNavItems, ...bottomNavItems], [sideNavItems, bottomNavItems]);
6226
6282
  return isMobile ? /* @__PURE__ */ jsx(Drawer, {
6227
6283
  styles: { body: { backgroundColor: isDark || sidebarTheme === "dark" ? Menu?.darkItemBg : Menu?.itemBg } },
6228
6284
  open: sidebarCollapsed,
@@ -6232,7 +6288,7 @@ function LayoutMobileMenu() {
6232
6288
  onClose: () => setPreferences("sidebarCollapsed", false),
6233
6289
  children: /* @__PURE__ */ jsx(Scrollbar, { children: /* @__PURE__ */ jsx(LayoutMenu, {
6234
6290
  autoExpandCurrentMenu: true,
6235
- menus: sideNavItems,
6291
+ menus: menuItems,
6236
6292
  handleMenuSelect
6237
6293
  }) })
6238
6294
  }) : null;
@@ -6257,6 +6313,7 @@ var init_layout_mobile_menu = __esmMin((() => {
6257
6313
  //#region src/layout/layout-sidebar/index.tsx
6258
6314
  function LayoutSidebar({ children, computedSidebarWidth }) {
6259
6315
  const { sidebarCollapsed, sidebarTheme, isDark } = usePreferences();
6316
+ const { bottomNavItems, handleMenuSelect } = useMenu();
6260
6317
  const { token: { Menu } } = theme.useToken();
6261
6318
  const isFixedDarkTheme = isDark || sidebarTheme === "dark";
6262
6319
  return /* @__PURE__ */ jsx(ConfigProvider, {
@@ -6267,14 +6324,21 @@ function LayoutSidebar({ children, computedSidebarWidth }) {
6267
6324
  backgroundColor: isFixedDarkTheme ? Menu?.darkItemBg : Menu?.itemBg,
6268
6325
  boxShadow: "3px 0 5px 0 rgb(29, 35, 41, 0.05)"
6269
6326
  },
6270
- className: "fixed top-0 bottom-0 left-0 overflow-x-hidden overflow-y-auto transition-all border-r border-r-colorBorderSecondary",
6327
+ className: "fixed top-0 bottom-0 left-0 flex flex-col overflow-x-hidden overflow-y-auto transition-all border-r border-r-colorBorderSecondary",
6271
6328
  children: [
6272
6329
  /* @__PURE__ */ jsx(Logo, { sidebarCollapsed }),
6273
6330
  /* @__PURE__ */ jsx("div", {
6274
- className: "overflow-hidden",
6275
- style: { height: `calc(100% - 48px - 40px)` },
6331
+ className: "flex-1 min-h-0 overflow-hidden",
6276
6332
  children: /* @__PURE__ */ jsx(Scrollbar, { children })
6277
6333
  }),
6334
+ bottomNavItems.length > 0 ? /* @__PURE__ */ jsx("div", {
6335
+ className: "shrink-0",
6336
+ children: /* @__PURE__ */ jsx(LayoutMenu, {
6337
+ autoExpandCurrentMenu: true,
6338
+ menus: bottomNavItems,
6339
+ handleMenuSelect
6340
+ })
6341
+ }) : null,
6278
6342
  /* @__PURE__ */ jsx(SiderTrigger, {})
6279
6343
  ]
6280
6344
  })
@@ -6283,7 +6347,8 @@ function LayoutSidebar({ children, computedSidebarWidth }) {
6283
6347
  var init_layout_sidebar = __esmMin((() => {
6284
6348
  init_scrollbar();
6285
6349
  init_use_preferences();
6286
- init_constants$1();
6350
+ init_layout_menu();
6351
+ init_use_menu();
6287
6352
  init_logo();
6288
6353
  init_sider_trigger();
6289
6354
  }));
@@ -8322,6 +8387,135 @@ function generateMenuItemsFromRoutes(routeList, parentPath = "/") {
8322
8387
  }
8323
8388
  var init_generate_menu_items_from_routes = __esmMin((() => {}));
8324
8389
  //#endregion
8390
+ //#region src/router/utils/group-solution-menus.ts
8391
+ function defaultWarn(msg) {
8392
+ if (warnedOnce.has(msg)) return;
8393
+ warnedOnce.add(msg);
8394
+ console.warn(msg);
8395
+ }
8396
+ /**
8397
+ * 处理单段菜单(顶层扫描,不递归 children):
8398
+ * - main 路由:模块可见项 ≥2 则延迟建组(组插到该模块首个被摘项原序位);否则原样直出;
8399
+ * - admin 路由:可挂载 `/system` 时摘除(交由调用方挂入 bottom 的 /system children),
8400
+ * 否则原样直出(回落顶层平铺,保持原序);
8401
+ * - 无对应行项:原样直出。
8402
+ */
8403
+ function processList(list, byPath, groupedModules, mountPossible) {
8404
+ const out = [];
8405
+ const groupsByModule = /* @__PURE__ */ new Map();
8406
+ const adminItems = [];
8407
+ list.forEach((it, idx) => {
8408
+ const row = byPath.get(it.key);
8409
+ if (!row) {
8410
+ out.push(it);
8411
+ return;
8412
+ }
8413
+ if (row.category === "admin") {
8414
+ adminItems.push({
8415
+ item: it,
8416
+ row
8417
+ });
8418
+ if (mountPossible) return;
8419
+ out.push(it);
8420
+ return;
8421
+ }
8422
+ if (groupedModules.has(row.module)) {
8423
+ let g = groupsByModule.get(row.module);
8424
+ if (!g) {
8425
+ g = {
8426
+ items: [],
8427
+ rows: [],
8428
+ firstIdx: idx
8429
+ };
8430
+ groupsByModule.set(row.module, g);
8431
+ }
8432
+ g.items.push(it);
8433
+ g.rows.push(row);
8434
+ return;
8435
+ }
8436
+ out.push(it);
8437
+ });
8438
+ const inserts = [...groupsByModule.values()].map((g) => ({
8439
+ index: g.firstIdx,
8440
+ group: makeGroup(MAIN_PREFIX, g.rows[0].module, g.items, g.rows)
8441
+ })).sort((a, b) => b.index - a.index);
8442
+ for (const ins of inserts) out.splice(ins.index, 0, ins.group);
8443
+ return {
8444
+ out,
8445
+ adminItems
8446
+ };
8447
+ }
8448
+ function makeGroup(prefix, module, items, rows) {
8449
+ const paired = items.map((item, i) => ({
8450
+ item,
8451
+ order: rows[i].order
8452
+ })).sort((a, b) => a.order - b.order);
8453
+ return {
8454
+ key: `${prefix}${module}`,
8455
+ label: `${module}:menu.group`,
8456
+ children: paired.map((p) => p.item)
8457
+ };
8458
+ }
8459
+ /**
8460
+ * 归组入口。
8461
+ *
8462
+ * - 空表(未安装/端点失败)或无命中行 → 返回新数组(内容相等),开发形态不变;
8463
+ * - 不 mutate 入参对象,未变动项复用原 menuItem 引用(仅重组数组与合成父项)。
8464
+ */
8465
+ function groupSolutionMenus(top, bottom, rows, opts = {}) {
8466
+ const systemKey = opts.systemKey ?? "/system";
8467
+ const onWarn = opts.onWarn ?? defaultWarn;
8468
+ if (rows.length === 0) return {
8469
+ top: [...top],
8470
+ bottom: [...bottom]
8471
+ };
8472
+ const byPath = /* @__PURE__ */ new Map();
8473
+ for (const r of rows) if ((r.category === "main" || r.category === "admin") && r.enabled !== false) byPath.set(r.path, r);
8474
+ if (byPath.size === 0) return {
8475
+ top: [...top],
8476
+ bottom: [...bottom]
8477
+ };
8478
+ const mainCount = /* @__PURE__ */ new Map();
8479
+ for (const list of [top, bottom]) for (const it of list) {
8480
+ const row = byPath.get(it.key);
8481
+ if (row?.category === "main") mainCount.set(row.module, (mainCount.get(row.module) ?? 0) + 1);
8482
+ }
8483
+ const groupedModules = new Set([...mainCount].filter(([, n]) => n >= 2).map(([module]) => module));
8484
+ const mountPossible = bottom.some((it) => it.key === systemKey);
8485
+ const topRes = processList(top, byPath, groupedModules, mountPossible);
8486
+ const bottomRes = processList(bottom, byPath, groupedModules, mountPossible);
8487
+ const adminGroupsMap = /* @__PURE__ */ new Map();
8488
+ for (const a of [...topRes.adminItems, ...bottomRes.adminItems]) {
8489
+ const arr = adminGroupsMap.get(a.row.module) ?? [];
8490
+ arr.push(a);
8491
+ adminGroupsMap.set(a.row.module, arr);
8492
+ }
8493
+ const adminGroups = [...adminGroupsMap.entries()].map(([module, items]) => ({
8494
+ minOrder: Math.min(...items.map((i) => i.row.order)),
8495
+ group: makeGroup(ADMIN_PREFIX, module, items.map((i) => i.item), items.map((i) => i.row))
8496
+ })).sort((a, b) => a.minOrder - b.minOrder);
8497
+ let newBottom = bottomRes.out;
8498
+ const sysIdx = newBottom.findIndex((it) => it.key === systemKey);
8499
+ if (mountPossible && sysIdx !== -1) {
8500
+ const system = newBottom[sysIdx];
8501
+ newBottom = newBottom.slice();
8502
+ newBottom[sysIdx] = {
8503
+ ...system,
8504
+ children: [...system.children ?? [], ...adminGroups.map((g) => g.group)]
8505
+ };
8506
+ } else if (adminGroups.length > 0) onWarn(`[solution-menu-grouping] system menu "${systemKey}" not found; admin items keep top-level (grouping degraded).`);
8507
+ return {
8508
+ top: topRes.out,
8509
+ bottom: newBottom
8510
+ };
8511
+ }
8512
+ var MAIN_PREFIX, ADMIN_PREFIX, warnedOnce;
8513
+ var init_group_solution_menus = __esmMin((() => {
8514
+ MAIN_PREFIX = "solgroup:main:";
8515
+ ADMIN_PREFIX = "solgroup:admin:";
8516
+ warnedOnce = /* @__PURE__ */ new Set();
8517
+ }));
8518
+ //#endregion
8325
8519
  //#region src/router/utils/merge-solution-categories.ts
8326
8520
  /**
8327
8521
  * 方案路由归并(纯函数,R21):按 path 把 sys_solution_route 行注记到已注册路由上。
@@ -8329,7 +8523,9 @@ var init_generate_menu_items_from_routes = __esmMin((() => {}));
8329
8523
  * - 三值 category 原样落 handle.category(main=常规组、admin=管理组、hidden=不进菜单);
8330
8524
  * - hidden 与 enabled=0(禁用)复用既有 hideInMenu 通路——只过滤菜单层,路由仍可达
8331
8525
  * (禁用的路由摘除归装载层三处同写,D12);
8332
- * - order 覆写为声明序:框架项保留 100 间隔带、方案项从 200 起编,共用一条序轴;
8526
+ * - order 覆写为声明序(2026-10-20 双段序轴):框架常规项 ≥0 升序、管理面负数入
8527
+ * 底部固定区(pin 侧边栏底部,ascending 双段排序)、方案项从 200 起编,共用一条序轴;
8528
+ * 同 order 按根 path 字母序;
8333
8529
  * - 未匹配路由(框架/后端)原样保留(同一对象引用),入参不突变;
8334
8530
  * - solRoutes 为空(端点失败/未登录降级空表)时原样返回——降级不阻断,路由照常。
8335
8531
  *
@@ -8406,7 +8602,22 @@ var init_resolve_login_route = __esmMin((() => {
8406
8602
  }));
8407
8603
  //#endregion
8408
8604
  //#region src/store/access.ts
8409
- var initialState$1, lastRegisteredRoutes, useAccessStore;
8605
+ /**
8606
+ * 切分主区/底部固定区路由(ascending 已双段排序:负 order 段整体在后)。
8607
+ * 按首个负 order 找边界一次切分,两段各自保持升序。
8608
+ */
8609
+ function splitMenuRoutes(routes) {
8610
+ const boundary = routes.findIndex((route) => (route.handle.order ?? 0) < 0);
8611
+ if (boundary === -1) return {
8612
+ top: routes,
8613
+ bottom: []
8614
+ };
8615
+ return {
8616
+ top: routes.slice(0, boundary),
8617
+ bottom: routes.slice(boundary)
8618
+ };
8619
+ }
8620
+ var baseMenuRoutes, initialState$1, lastRegisteredRoutes, useAccessStore;
8410
8621
  var init_access = __esmMin((() => {
8411
8622
  init_router();
8412
8623
  init_constants();
@@ -8414,10 +8625,13 @@ var init_access = __esmMin((() => {
8414
8625
  init_ascending();
8415
8626
  init_flatten_routes();
8416
8627
  init_generate_menu_items_from_routes();
8628
+ init_group_solution_menus();
8417
8629
  init_merge_solution_categories();
8418
8630
  init_resolve_login_route();
8631
+ baseMenuRoutes = splitMenuRoutes(baseRoutes);
8419
8632
  initialState$1 = {
8420
- wholeMenus: generateMenuItemsFromRoutes(baseRoutes),
8633
+ wholeMenus: generateMenuItemsFromRoutes(baseMenuRoutes.top),
8634
+ bottomMenus: generateMenuItemsFromRoutes(baseMenuRoutes.bottom),
8421
8635
  routeList: baseRoutes,
8422
8636
  flatRouteList: flattenRoutes(baseRoutes),
8423
8637
  isAccessChecked: false,
@@ -8430,8 +8644,11 @@ var init_access = __esmMin((() => {
8430
8644
  const newRoutes = ascending([...resolveLoginRoute(baseRoutes, routes, router, rootRoute), ...mergeSolutionCategories(routes, get().solutionRoutes)]);
8431
8645
  router.patchRoutes(ROOT_ROUTE_ID, routes);
8432
8646
  const flatRouteList = flattenRoutes(newRoutes);
8647
+ const { top, bottom } = splitMenuRoutes(newRoutes);
8648
+ const grouped = groupSolutionMenus(generateMenuItemsFromRoutes(top), generateMenuItemsFromRoutes(bottom), get().solutionRoutes);
8433
8649
  const newState = {
8434
- wholeMenus: generateMenuItemsFromRoutes(newRoutes),
8650
+ wholeMenus: grouped.top,
8651
+ bottomMenus: grouped.bottom,
8435
8652
  routeList: newRoutes,
8436
8653
  flatRouteList,
8437
8654
  isAccessChecked: true
@@ -3,6 +3,7 @@ import type { MenuItemType } from "../layout/layout-menu/types";
3
3
  import type { AppRouteRecordRaw } from "../router/types";
4
4
  interface AccessState {
5
5
  wholeMenus: MenuItemType[];
6
+ bottomMenus: MenuItemType[];
6
7
  routeList: AppRouteRecordRaw[];
7
8
  flatRouteList: Record<string, AppRouteRecordRaw>;
8
9
  isAccessChecked: boolean;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@oj-module/runtime",
3
3
  "type": "module",
4
- "version": "0.2.8",
4
+ "version": "0.2.15",
5
5
  "description": "React Antd Admin 框架运行时,供模块工程消费",
6
6
  "license": "MIT",
7
7
  "imports": {