@morehao/ark-iam-react 0.0.0-stage → 1.0.0
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.
Potentially problematic release.
This version of @morehao/ark-iam-react might be problematic. Click here for more details.
- package/README.md +83 -2
- package/dist/_types/api/index.d.ts +5 -0
- package/dist/_types/api/index.js +185 -0
- package/dist/_types/api/index.js.map +1 -0
- package/dist/_types/api/request.d.ts +34 -0
- package/dist/_types/api/resources/auth.d.ts +13 -0
- package/dist/_types/api/resources/platform.d.ts +80 -0
- package/dist/_types/api/sessionProbe.d.ts +13 -0
- package/dist/_types/auth/AuthProvider.d.ts +27 -0
- package/dist/_types/auth/config.d.ts +23 -0
- package/dist/_types/auth/guards.d.ts +1 -0
- package/dist/_types/auth/hooks.d.ts +11 -0
- package/dist/_types/auth/index.d.ts +8 -0
- package/dist/_types/auth/index.js +190 -0
- package/dist/_types/auth/index.js.map +1 -0
- package/dist/_types/auth/tenant.d.ts +3 -0
- package/dist/_types/types/auth.d.ts +62 -0
- package/dist/_types/types/department.d.ts +52 -0
- package/dist/_types/types/index.d.ts +5 -0
- package/dist/_types/types/index.js +14 -0
- package/dist/_types/types/index.js.map +1 -0
- package/dist/_types/types/platform.d.ts +347 -0
- package/dist/_types/types/response.d.ts +14 -0
- package/dist/_types/types/tenant.d.ts +243 -0
- package/dist/_types/ui/AppShell.d.ts +16 -0
- package/dist/_types/ui/EllipsisCell.d.ts +16 -0
- package/dist/_types/ui/IDCell.d.ts +14 -0
- package/dist/_types/ui/InitialPasswordModal.d.ts +18 -0
- package/dist/_types/ui/LoginPage.d.ts +6 -0
- package/dist/_types/ui/MainLayout.d.ts +14 -0
- package/dist/_types/ui/NameLink.d.ts +18 -0
- package/dist/_types/ui/PageContainer.d.ts +15 -0
- package/dist/_types/ui/ProfileCenter.d.ts +6 -0
- package/dist/_types/ui/RemoteSelect.d.ts +57 -0
- package/dist/_types/ui/RowActions.d.ts +36 -0
- package/dist/_types/ui/TenantSwitcher.d.ts +1 -0
- package/dist/_types/ui/TimeCell.d.ts +53 -0
- package/dist/_types/ui/columns.d.ts +116 -0
- package/dist/_types/ui/format.d.ts +20 -0
- package/dist/_types/ui/index.d.ts +25 -0
- package/dist/_types/ui/index.js +1233 -0
- package/dist/_types/ui/index.js.map +1 -0
- package/dist/_types/ui/status.d.ts +38 -0
- package/dist/_types/ui/theme.d.ts +49 -0
- package/dist/api.d.ts +1 -0
- package/dist/api.js +50 -0
- package/dist/api.js.map +1 -0
- package/dist/auth.d.ts +1 -0
- package/dist/auth.js +17 -0
- package/dist/auth.js.map +1 -0
- package/dist/index-BQuRl5A6.js +185 -0
- package/dist/index-BQuRl5A6.js.map +1 -0
- package/dist/index-D3uUqZ5c.js +190 -0
- package/dist/index-D3uUqZ5c.js.map +1 -0
- package/dist/index-DnhMUOxg.js +1233 -0
- package/dist/index-DnhMUOxg.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +109 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +1 -0
- package/dist/types.js +14 -0
- package/dist/types.js.map +1 -0
- package/dist/ui.d.ts +1 -0
- package/dist/ui.js +46 -0
- package/dist/ui.js.map +1 -0
- package/package.json +80 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/theme.ts","../src/TenantSwitcher.tsx","../src/IDCell.tsx","../src/EllipsisCell.tsx","../src/RowActions.tsx","../src/format.ts","../src/TimeCell.tsx","../src/ProfileCenter.tsx","../src/MainLayout.tsx","../src/LoginPage.tsx","../src/PageContainer.tsx","../src/InitialPasswordModal.tsx","../src/NameLink.tsx","../src/columns.tsx","../src/RemoteSelect.tsx","../src/AppShell.tsx","../src/status.tsx"],"sourcesContent":["import type { ThemeConfig } from 'antd'\n\n/**\n * Ark IAM 全局设计令牌(唯一事实源)\n *\n * 设计方向:「冷白工程台」收敛(受 Stripe / Vercel 工程控制台启发,见 DESIGN.md 参照锚点)。\n * 靛蓝只出现在主按钮 / 链接 / 选中态 / 品牌区;页面表面一律中性灰阶,\n * 卡片以 hairline 边框分层(无阴影);文字为三级 hex 灰阶。\n * 命名与 frontend/DESIGN.md 的 colors 段一一对应,改动需两处同步。\n */\nexport const tokens = {\n // 品牌 Brand:靛蓝 → 紫,仅用于主按钮 / 链接 / 选中态 / 登录与 Logo 品牌区\n primary: '#4f6ef7',\n primaryHover: '#6b86ff',\n primaryActive: '#3a55d6',\n gradient: 'linear-gradient(135deg, #4f6ef7 0%, #7a5af8 55%, #a855f7 100%)',\n gradientSoft: 'linear-gradient(135deg, #eef2ff 0%, #f5f0ff 100%)',\n purple: '#7a5af8', // 品牌紫:分类图标/点缀强调(极少量)\n selectedBg: 'rgba(79, 110, 247, 0.14)', // 深色导航选中项柔和底(非整块亮色)\n\n // 表面 Surface(中性灰阶,禁用靛蓝淡底 tint)\n bg: '#f6f7f9', // 页面布局底色(冷白)\n cardBg: '#ffffff',\n sidebarBg: '#0f172a',\n headerBg: '#ffffff',\n tableHeaderBg: '#f7f8fa',\n rowHoverBg: '#f3f4f6',\n softFill: '#f1f3f5', // 中性填充底(统计卡图标底、应用固定条等)\n codeBg: '#fafafa', // 代码/内容块底色\n\n // 边框 Border(冷调 hairline,卡片分层的主语言)\n border: '#e6e9ef',\n borderStrong: '#d3d8e0', // 更强的分割线(Header 内分割线等)\n\n // 文字 Text(三级 hex 灰阶)\n text: '#1f2430',\n textSecondary: '#64748d', // 借鉴 Stripe ink-mute\n textPlaceholder: '#94a3b8', // 空态/占位辅助文字\n\n // 语义色 Semantic(与 antd colorSuccess/Warning/Error 对齐,仅状态 Tag/告警使用)\n success: '#22c55e',\n warning: '#f59e0b',\n error: '#ef4444',\n warningBg: '#fffbe6', // 轻量告警底色\n warningBorder: '#ffe58f', // 轻量告警描边\n}\n\n/** 历史兼容:品牌相关令牌(主色/渐变/背景/文字)。新代码请引用 tokens。 */\nexport const brand = {\n primary: tokens.primary,\n primaryHover: tokens.primaryHover,\n primaryActive: tokens.primaryActive,\n gradient: tokens.gradient,\n gradientSoft: tokens.gradientSoft,\n bg: tokens.bg,\n sidebarBg: tokens.sidebarBg,\n text: tokens.text,\n textSecondary: tokens.textSecondary,\n}\n\nexport const themeConfig: ThemeConfig = {\n token: {\n colorPrimary: tokens.primary,\n colorInfo: tokens.primary,\n colorLink: tokens.primary,\n colorSuccess: tokens.success,\n colorWarning: tokens.warning,\n colorError: tokens.error,\n colorBgLayout: tokens.bg,\n colorBorderSecondary: tokens.border, // hairline 统一为冷调\n borderRadius: 8,\n borderRadiusLG: 12,\n colorText: tokens.text,\n colorTextSecondary: tokens.textSecondary,\n fontFamily:\n \"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif\",\n boxShadowSecondary: '0 6px 24px rgba(15, 23, 42, 0.08)', // 仅浮层/Modal 使用\n },\n components: {\n Layout: {\n headerBg: tokens.headerBg,\n headerHeight: 56,\n siderBg: tokens.sidebarBg,\n bodyBg: tokens.bg,\n },\n Menu: {\n darkItemBg: tokens.sidebarBg,\n darkItemSelectedBg: tokens.selectedBg,\n darkItemSelectedColor: '#ffffff',\n darkItemHoverBg: 'rgba(255,255,255,0.08)',\n itemBorderRadius: 8,\n itemHeight: 42,\n },\n Card: {\n headerFontSize: 15,\n },\n Table: {\n headerBg: tokens.tableHeaderBg,\n headerColor: tokens.textSecondary,\n rowHoverBg: tokens.rowHoverBg,\n },\n Modal: {\n borderRadiusLG: 14,\n },\n },\n}\n","import { Dropdown, Tag } from 'antd'\nimport { SwapOutlined } from '@ant-design/icons'\nimport { useTenantSwitching, getCurrentTenantId } from '@ark-iam/auth'\nimport { tokens } from './theme'\n\nexport function TenantSwitcher() {\n const { tenants, loadTenants, handleSwitchTenant } = useTenantSwitching()\n const currentId = getCurrentTenantId()\n const currentName = tenants.find((t) => String(t.tenantID) === currentId)?.name || '当前租户'\n\n return (\n <Dropdown\n menu={{\n items: tenants.map((t) => ({\n key: `tenant-${t.tenantID}`,\n label: (\n <span style={{ display: 'flex', alignItems: 'center', gap: 8 }}>\n {t.name}\n {String(t.tenantID) === currentId && <Tag color=\"blue\" style={{ marginInlineEnd: 0 }}>当前</Tag>}\n </span>\n ),\n disabled: String(t.tenantID) === currentId,\n onClick: () => handleSwitchTenant(t.tenantID),\n })),\n }}\n onOpenChange={(open) => {\n if (open) void loadTenants()\n }}\n >\n <span\n style={{\n color: tokens.text,\n cursor: 'pointer',\n fontSize: 13,\n lineHeight: 1,\n display: 'inline-flex',\n alignItems: 'center',\n height: 32,\n padding: '0 12px',\n boxSizing: 'border-box',\n borderRadius: 8,\n border: `1px solid ${tokens.borderStrong}`,\n background: tokens.tableHeaderBg,\n transition: 'all 0.2s',\n }}\n className=\"tenant-switcher\"\n >\n <SwapOutlined style={{ color: tokens.primary }} />\n <span style={{ fontWeight: 500, lineHeight: 1 }}>{currentName}</span>\n </span>\n </Dropdown>\n )\n}\n","import { Tooltip } from 'antd'\n\nexport interface IDCellProps {\n /** ID 值;空值展示为 - */\n value?: string | number | null\n /** 保留的前缀长度,默认 8 */\n prefix?: number\n /** 保留的后缀长度,默认 4 */\n suffix?: number\n}\n\n/**\n * 长 ID 单元格(UUID v7 等):\n * - 默认仅展示首尾片段,如 `0190e2a4…c3d4`\n * - 鼠标悬浮展示完整 ID(可拖选直接复制,无独立复制按钮)\n */\nexport function IDCell({ value, prefix = 8, suffix = 4 }: IDCellProps) {\n const text = value == null ? '' : String(value)\n if (!text) return <span>-</span>\n const short = text.length > prefix + suffix + 1 ? `${text.slice(0, prefix)}…${text.slice(-suffix)}` : text\n return (\n <Tooltip\n title={text}\n mouseEnterDelay={0.3}\n mouseLeaveDelay={0.6}\n styles={{ body: { userSelect: 'text' } }}\n >\n <span style={{ fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace', fontSize: 12 }}>{short}</span>\n </Tooltip>\n )\n}\n","import { Tooltip } from 'antd'\n\nexport interface EllipsisCellProps {\n /** 文本内容;空值展示为 placeholder */\n value?: string | number | null\n /** 展示前先截断到该字符数(仅影响展示,悬浮提示仍为完整内容) */\n limit?: number\n /** 使用等宽字体 */\n monospace?: boolean\n /** 空值占位文案,默认 `-` */\n placeholder?: string\n}\n\n/**\n * 可能展示不全的文本单元格:\n * - 超出单元格宽度即省略号截断\n * - 鼠标悬浮展示完整内容(可拖选直接复制)\n */\nexport function EllipsisCell({ value, limit, monospace = false, placeholder = '-' }: EllipsisCellProps) {\n const text = value == null ? '' : String(value)\n if (!text) return <span>{placeholder}</span>\n const display = limit && text.length > limit ? `${text.slice(0, limit)}…` : text\n return (\n <Tooltip\n title={text}\n mouseEnterDelay={0.3}\n mouseLeaveDelay={0.6}\n styles={{ body: { userSelect: 'text' } }}\n >\n <span\n style={{\n display: 'inline-block',\n maxWidth: '100%',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n verticalAlign: 'bottom',\n ...(monospace ? { fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace', fontSize: 12 } : {}),\n }}\n >\n {display}\n </span>\n </Tooltip>\n )\n}\n","import type { ReactNode } from 'react'\nimport { App, Button, Dropdown, Popconfirm, Space } from 'antd'\nimport type { MenuProps } from 'antd'\nimport { DownOutlined } from '@ant-design/icons'\n\n/** 表格操作列中的单个操作。 */\nexport interface RowAction {\n /** 操作唯一标识(React key / 菜单 key) */\n key: string\n /** 操作文案 */\n label: ReactNode\n /** 点击回调 */\n onClick?: () => void\n /** 危险操作:按钮/菜单项渲染为语义红 */\n danger?: boolean\n /** 禁用 */\n disabled?: boolean\n /** 二次确认文案;提供时点击后先确认再执行 onClick */\n confirm?: ReactNode\n /** 可选图标(下拉菜单项会展示) */\n icon?: ReactNode\n /** 运行时隐藏该操作(如已吊销的密钥不再展示「吊销」) */\n hidden?: boolean\n}\n\nexport interface RowActionsProps {\n /** 操作列表,按重要程度从高到低排列 */\n actions: RowAction[]\n /** 横排上限,超过则收起为「更多」下拉;默认 3 */\n max?: number\n}\n\n/**\n * 统一的表格「操作列」渲染器(列表页操作列规范,见 DESIGN.md §7.3):\n * - 操作数 ≤ max(默认 3):全部以 `Button type=\"link\" size=\"small\"` 横排;\n * - 操作数 > max:保留前 `max - 1` 个高频操作横排,其余收进「更多」下拉(菜单项纵向排列),\n * 避免操作列被撑宽、行内按钮挤成一团。\n *\n * 二次确认:横排操作用 Popconfirm 就地气泡确认;下拉菜单项用 Modal.confirm\n * (菜单点击会先关闭下拉,气泡无法稳定锚定)。\n */\nexport function RowActions({ actions, max = 3 }: RowActionsProps) {\n const { modal } = App.useApp()\n const visible = actions.filter((action) => !action.hidden)\n if (visible.length === 0) return null\n\n const renderInline = (action: RowAction) => {\n if (!action.confirm) {\n return (\n <Button\n key={action.key}\n type=\"link\"\n size=\"small\"\n danger={action.danger}\n disabled={action.disabled}\n icon={action.icon}\n onClick={action.onClick}\n >\n {action.label}\n </Button>\n )\n }\n return (\n <Popconfirm\n key={action.key}\n title={action.confirm}\n disabled={action.disabled}\n onConfirm={action.onClick}\n >\n <Button type=\"link\" size=\"small\" danger={action.danger} disabled={action.disabled} icon={action.icon}>\n {action.label}\n </Button>\n </Popconfirm>\n )\n }\n\n if (visible.length <= max) {\n return <Space size={4}>{visible.map(renderInline)}</Space>\n }\n\n const inline = visible.slice(0, Math.max(1, max - 1))\n const overflow = visible.slice(Math.max(1, max - 1))\n\n const items: MenuProps['items'] = overflow.map((action) => ({\n key: action.key,\n label: action.label,\n icon: action.icon,\n danger: action.danger,\n disabled: action.disabled,\n }))\n\n const handleMenuClick: MenuProps['onClick'] = ({ key }) => {\n const action = overflow.find((item) => item.key === key)\n if (!action) return\n if (action.confirm) {\n modal.confirm({\n title: action.confirm,\n okButtonProps: { danger: action.danger },\n onOk: () => action.onClick?.(),\n })\n return\n }\n action.onClick?.()\n }\n\n return (\n <Space size={4}>\n {inline.map(renderInline)}\n <Dropdown menu={{ items, onClick: handleMenuClick }} trigger={['click']}>\n <Button type=\"link\" size=\"small\">\n 更多 <DownOutlined style={{ fontSize: 10 }} />\n </Button>\n </Dropdown>\n </Space>\n )\n}\n","/**\n * 时间渲染:兼容秒级时间戳与字符串,统一为 `YYYY-MM-DD HH:mm:ss`。\n * 前后端时间交互约定为秒级 int64 时间戳(见 AGENTS.md),前端展示统一走本函数。\n */\nexport function fmtTime(value?: number | string | null): string {\n if (value == null || value === '' || value === 0) return '-'\n if (typeof value === 'number') {\n const ms = toMillis(value)\n const d = new Date(ms)\n if (Number.isNaN(d.getTime())) return String(value)\n const pad = (n: number) => String(n).padStart(2, '0')\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`\n }\n return value\n}\n\n/**\n * 时间戳归一化为毫秒:约定入参是秒级时间戳(AGENTS.md),\n * 同时兼容历史上传入的毫秒值(1e12 已远超秒级上限,可安全区分)。\n */\nexport function toMillis(value: number): number {\n return value < 1e12 ? value * 1000 : value\n}\n\n/** 相对时间分档阈值(秒) */\nconst REL_MINUTE = 60\nconst REL_HOUR = 60 * REL_MINUTE\nconst REL_DAY = 24 * REL_HOUR\nconst REL_MONTH = 30 * REL_DAY\nconst REL_YEAR = 365 * REL_DAY\n\n/**\n * 相对时间:`刚刚 / N 分钟前 / N 小时前 / N 天前 / N 个月前 / N 年前`。\n *\n * 只用于「最后使用 / 最近使用 / 登录时间」这类\"最近\"语义的次要时间字段\n * (列窄、扫描时只需粒度感,精确时间由 TimeCell 的 Tooltip 兜底)。\n * - 时间戳晚于当前时刻(时钟漂移等)不猜测为\"N 分钟后\",回退绝对时间;\n * - 空值返回空串,由 TimeCell 负责占位文案(如「从未使用」);\n * - `now` 仅用于测试注入。\n */\nexport function fmtRelativeTime(value?: number | string | null, now: number = Date.now()): string {\n if (value == null || value === '' || value === 0) return ''\n if (typeof value !== 'number') return String(value)\n const ms = toMillis(value)\n if (Number.isNaN(ms)) return String(value)\n const diff = Math.floor((now - ms) / 1000)\n if (diff < 0) return fmtTime(value)\n if (diff < REL_MINUTE) return '刚刚'\n if (diff < REL_HOUR) return `${Math.floor(diff / REL_MINUTE)} 分钟前`\n if (diff < REL_DAY) return `${Math.floor(diff / REL_HOUR)} 小时前`\n if (diff < REL_MONTH) return `${Math.floor(diff / REL_DAY)} 天前`\n if (diff < REL_YEAR) return `${Math.floor(diff / REL_MONTH)} 个月前`\n return `${Math.floor(diff / REL_YEAR)} 年前`\n}\n","import type { ColumnType } from 'antd/es/table'\nimport { Tooltip } from 'antd'\nimport { fmtRelativeTime, fmtTime } from './format'\nimport { tokens } from './theme'\n\n/**\n * 时间列标准宽度(px)。\n *\n * 依据:完整时间串 `2026-09-03 17:19:46` 在 antd 表格 14px 字号 + 全站 `tabular-nums`\n * 下实测 146.06px(macOS / Chrome / 系统字体栈,为常见平台里较宽的一种);\n * antd v5 单元格水平内边距为 `token.padding` × 2 = 32px,故单行显示至少需要 178.06px,\n * 取 180 留余量。低于该值的列宽会让时间恰好在唯一的空格处折行成「日期 / 时间」两行\n * (规范见 frontend/DESIGN.md §7.3)。\n */\nexport const TIME_COL_WIDTH = 180\n\n/**\n * 相对时间列宽度(px):如「3 天前」实测 40.47px、最长档「10 个月前」约 63px,\n * 加 32px 内边距后 120 有充足余量。\n */\nexport const TIME_COL_WIDTH_RELATIVE = 120\n\nexport interface TimeCellProps {\n /** 秒级时间戳(约定见 AGENTS.md),兼容字符串与毫秒值 */\n value?: number | string | null\n /** 空值占位文案(默认 '-'),如「永不过期」 */\n placeholder?: string\n /** 相对时间模式:展示「3 天前」,悬浮给出完整 `YYYY-MM-DD HH:mm:ss` */\n relative?: boolean\n}\n\n/**\n * 表格时间单元格:统一 `YYYY-MM-DD HH:mm:ss`,并强制单行不折行。\n *\n * 所有时间列都必须走本组件(或 `timeColumn` 工厂),禁止页面直接 `fmtTime` 且自定列宽 —— \n * 列宽与 `whiteSpace: nowrap` 是一对,缺任何一半都会出现\"折行\"或\"溢出串列\"。\n */\nexport function TimeCell({ value, placeholder = '-', relative = false }: TimeCellProps) {\n if (value == null || value === '' || value === 0) {\n return <span style={{ color: tokens.textPlaceholder }}>{placeholder}</span>\n }\n const absolute = fmtTime(value)\n if (!relative) return <span style={{ whiteSpace: 'nowrap' }}>{absolute}</span>\n const text = fmtRelativeTime(value)\n return (\n <Tooltip title={absolute} mouseEnterDelay={0.3}>\n <span style={{ whiteSpace: 'nowrap' }}>{text || absolute}</span>\n </Tooltip>\n )\n}\n\nexport interface TimeColumnConfig<T> {\n title: string\n /** 记录字段名;同时作为列的 key */\n dataIndex: keyof T & string\n /** 覆盖默认列宽(默认绝对时间 180 / 相对时间 120) */\n width?: number\n placeholder?: string\n /** 次要时间字段(最后使用 / 登录时间等)用相对时间 + Tooltip */\n relative?: boolean\n}\n\n/**\n * 时间列工厂:一次给出「标题 + 字段 + 标准列宽 + TimeCell 渲染」,\n * 避免各页面手写列宽(历史 bug 根因就是每页各写 150/160/170)。\n *\n * ```tsx\n * const columns: ColumnsType<TenantItem> = [\n * timeColumn<TenantItem>({ title: '创建时间', dataIndex: 'createdAt' }),\n * timeColumn<TenantUserLoginLogItem>({ title: '登录时间', dataIndex: 'loginTime', relative: true }),\n * ]\n * ```\n */\nexport function timeColumn<T>({\n title,\n dataIndex,\n width,\n placeholder,\n relative = false,\n}: TimeColumnConfig<T>): ColumnType<T> {\n return {\n title,\n dataIndex,\n key: dataIndex,\n width: width ?? (relative ? TIME_COL_WIDTH_RELATIVE : TIME_COL_WIDTH),\n render: (value: unknown) => (\n <TimeCell value={value as number | string | null | undefined} placeholder={placeholder} relative={relative} />\n ),\n }\n}\n","import { useCallback, useEffect, useState } from 'react'\nimport { Modal, Tabs, Descriptions, Form, Input, Button, Table, message, Space, Avatar, Tag } from 'antd'\nimport { getPersonDetail, updatePassword, getSessionList, revokeSession, revokeAllSessions } from '@ark-iam/api'\nimport type { PersonDetailResp, SessionResp } from '@ark-iam/types'\nimport { brand } from './theme'\nimport { IDCell } from './IDCell'\nimport { EllipsisCell } from './EllipsisCell'\nimport { RowActions } from './RowActions'\nimport { timeColumn } from './TimeCell'\n\ninterface Props {\n open: boolean\n onClose: () => void\n}\n\nexport function ProfileCenter({ open, onClose }: Props) {\n const [person, setPerson] = useState<PersonDetailResp | null>(null)\n const [sessions, setSessions] = useState<SessionResp[]>([])\n const [loading, setLoading] = useState(false)\n const [form] = Form.useForm()\n\n const loadPerson = useCallback(async () => {\n try {\n setPerson(await getPersonDetail())\n } catch {\n /* 拦截器已提示 */\n }\n }, [])\n\n // 会话接口默认 10 条/页,这里拉取前 5 页以便展示更多会话\n const loadSessions = useCallback(async () => {\n setLoading(true)\n try {\n const pages = await Promise.all(\n [1, 2, 3, 4, 5].map((p) => getSessionList({ page: p, pageSize: 10 }).catch(() => ({ list: [], total: 0 }))),\n )\n const seen = new Set<string>()\n const merged: SessionResp[] = []\n for (const resp of pages) {\n for (const s of resp.list || []) {\n if (!seen.has(s.id)) {\n seen.add(s.id)\n merged.push(s)\n }\n }\n }\n setSessions(merged)\n } catch {\n /* 拦截器已提示 */\n } finally {\n setLoading(false)\n }\n }, [])\n\n useEffect(() => {\n if (open) {\n void loadPerson()\n void loadSessions()\n }\n }, [open, loadPerson, loadSessions])\n\n const submitPassword = async () => {\n try {\n const values = await form.validateFields()\n if (values.newPassword !== values.confirmPassword) {\n message.warning('两次输入的新密码不一致')\n return\n }\n await updatePassword({ oldPassword: values.oldPassword, newPassword: values.newPassword })\n message.success('密码已修改')\n form.resetFields()\n } catch {\n // 校验或请求失败,错误已由拦截器提示\n }\n }\n\n const columns = [\n { title: '会话ID', dataIndex: 'sessionID', key: 'sessionID', width: 160, render: (v: string) => <IDCell value={v} /> },\n { title: '客户端', dataIndex: 'clientType', key: 'clientType', width: 110 },\n { title: 'IP', dataIndex: 'clientIP', key: 'clientIP', width: 130 },\n {\n title: '状态',\n dataIndex: 'isActive',\n key: 'isActive',\n width: 90,\n render: (v: boolean) => (v ? <Tag color=\"success\">活跃</Tag> : <Tag color=\"default\">已失效</Tag>),\n },\n {\n title: 'UserAgent',\n dataIndex: 'userAgent',\n key: 'userAgent',\n render: (v: string) => <EllipsisCell value={v} />,\n },\n timeColumn<SessionResp>({ title: '创建时间', dataIndex: 'createdAt' }),\n {\n title: '操作',\n key: 'action',\n width: 90,\n render: (_: unknown, record: SessionResp) => (\n <RowActions\n actions={[\n {\n key: 'revoke',\n label: '撤销',\n danger: true,\n confirm: '确认撤销该会话?',\n onClick: () => {\n void revokeSession(record.id)\n .then(() => {\n message.success('已撤销')\n void loadSessions()\n })\n .catch(() => message.error('撤销会话失败'))\n },\n },\n ]}\n />\n ),\n },\n ]\n\n return (\n <Modal title=\"个人中心\" open={open} onCancel={onClose} footer={null} width={760} styles={{ body: { paddingTop: 12 } }}>\n <Tabs\n items={[\n {\n key: 'info',\n label: '个人信息',\n children: (\n <div>\n <Space size={20} align=\"center\" style={{ marginBottom: 20 }}>\n <Avatar size={56} style={{ background: brand.gradient, fontSize: 22 }}>\n {person?.name?.charAt(0)?.toUpperCase() || 'U'}\n </Avatar>\n <div>\n <div style={{ fontSize: 18, fontWeight: 700 }}>\n {person?.name || '-'}\n {person?.status === 'suspended' && <Tag color=\"error\" style={{ marginLeft: 8 }}>已挂起</Tag>}\n </div>\n <div style={{ color: brand.textSecondary }}>@{person?.username || '-'}</div>\n </div>\n </Space>\n <Descriptions column={1} bordered size=\"small\">\n <Descriptions.Item label=\"账号\">{person?.username ?? '-'}</Descriptions.Item>\n <Descriptions.Item label=\"姓名\">{person?.name ?? '-'}</Descriptions.Item>\n <Descriptions.Item label=\"邮箱\">{person?.primaryEmail ?? '-'}</Descriptions.Item>\n <Descriptions.Item label=\"手机号\">{person?.primaryPhone ?? '-'}</Descriptions.Item>\n </Descriptions>\n </div>\n ),\n },\n {\n key: 'password',\n label: '修改密码',\n children: (\n <Form form={form} layout=\"vertical\" style={{ maxWidth: 420 }}>\n <Form.Item name=\"oldPassword\" label=\"原密码\" rules={[{ required: true, message: '请输入原密码' }]}>\n <Input.Password />\n </Form.Item>\n <Form.Item\n name=\"newPassword\"\n label=\"新密码\"\n rules={[\n { required: true, message: '请输入新密码' },\n { min: 8, message: '至少 8 位,需含大小写字母和数字' },\n ]}\n >\n <Input.Password />\n </Form.Item>\n <Form.Item\n name=\"confirmPassword\"\n label=\"确认新密码\"\n rules={[{ required: true, message: '请再次输入新密码' }]}\n >\n <Input.Password />\n </Form.Item>\n <Button type=\"primary\" onClick={() => void submitPassword()}>\n 确认修改\n </Button>\n </Form>\n ),\n },\n {\n key: 'session',\n label: '会话管理',\n children: (\n <>\n <Space style={{ marginBottom: 12 }}>\n <Button\n danger\n onClick={() =>\n void revokeAllSessions()\n .then(() => {\n message.success('已撤销全部会话')\n void loadSessions()\n })\n .catch(() => message.error('撤销全部会话失败'))\n }\n >\n 撤销全部会话\n </Button>\n <span style={{ color: brand.textSecondary, fontSize: 12 }}>共 {sessions.length} 条(含历史失效会话)</span>\n </Space>\n <Table<SessionResp>\n rowKey=\"id\"\n columns={columns}\n dataSource={sessions}\n loading={loading}\n pagination={{ pageSize: 10, showSizeChanger: false, showTotal: (t) => `共 ${t} 条` }}\n scroll={{ x: 820 }}\n />\n </>\n ),\n },\n ]}\n />\n </Modal>\n )\n}\n","import { forwardRef, useMemo, useState } from 'react'\nimport { Layout, Menu, Avatar, Dropdown, Tooltip, Badge, theme } from 'antd'\nimport type { MenuProps } from 'antd'\nimport {\n LogoutOutlined,\n MenuFoldOutlined,\n MenuUnfoldOutlined,\n SafetyCertificateOutlined,\n UserOutlined,\n UserSwitchOutlined,\n} from '@ant-design/icons'\nimport { Outlet, useLocation, useNavigate } from 'react-router-dom'\nimport { useAuthGuard, useLogout } from '@ark-iam/auth'\nimport { useAuth } from 'react-oidc-context'\nimport { TenantSwitcher } from './TenantSwitcher'\nimport { ProfileCenter } from './ProfileCenter'\nimport { brand, tokens } from './theme'\n\nconst { Header, Sider, Content } = Layout\n\nexport interface MainMenuItems {\n key: string\n icon?: React.ReactNode\n label: string\n children?: MainMenuItems[]\n}\n\ninterface Props {\n title: string\n subtitle?: string\n menuItems: MainMenuItems[]\n hasTenantSwitch?: boolean\n}\n\nexport function MainLayout({ title, subtitle, menuItems, hasTenantSwitch = true }: Props) {\n const [collapsed, setCollapsed] = useState(false)\n const [profileOpen, setProfileOpen] = useState(false)\n const navigate = useNavigate()\n const location = useLocation()\n const auth = useAuth()\n useAuthGuard()\n const logout = useLogout()\n const { token } = theme.useToken()\n\n const displayName = useMemo(() => {\n const profile = auth.user?.profile as Record<string, unknown> | undefined\n return (profile?.name as string) || (profile?.preferred_username as string) || 'IAM 用户'\n }, [auth.user])\n\n const userMenuItems = useMemo(\n () => [\n { key: 'profile', icon: <UserSwitchOutlined />, label: '个人中心', onClick: () => setProfileOpen(true) },\n { type: 'divider' as const },\n { key: 'logout', icon: <LogoutOutlined />, label: '退出登录', onClick: () => void logout() },\n ],\n [logout],\n )\n\n // 菜单选中态:匹配一级或二级路径\n const selectedKey = useMemo(() => {\n const parts = location.pathname.split('/')\n const level1 = parts[1] ? `/${parts[1]}` : '/'\n const level2 = parts.length > 2 ? `/${parts[1]}/${parts[2]}` : ''\n const flat = (items: MainMenuItems[]): string[] => items.flatMap((i) => [i.key, ...(i.children ? flat(i.children) : [])])\n const all = flat(menuItems)\n if (all.includes(level2)) return level2\n if (all.includes(level1)) return level1\n return '/'\n }, [location.pathname, menuItems])\n\n return (\n <Layout style={{ minHeight: '100vh' }}>\n <Sider\n trigger={null}\n collapsible\n collapsed={collapsed}\n width={232}\n theme=\"dark\"\n style={{ position: 'sticky', top: 0, height: '100vh' }}\n >\n <div\n style={{\n height: 64,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 10,\n background: brand.gradient,\n color: '#fff',\n overflow: 'hidden',\n }}\n >\n <SafetyCertificateOutlined style={{ fontSize: collapsed ? 20 : 24 }} />\n {!collapsed && (\n <div style={{ lineHeight: 1.1 }}>\n <div style={{ fontSize: 16, fontWeight: 700, letterSpacing: 0.5 }}>{title}</div>\n {subtitle && <div style={{ fontSize: 11, opacity: 0.8 }}>{subtitle}</div>}\n </div>\n )}\n </div>\n <Menu\n theme=\"dark\"\n mode=\"inline\"\n selectedKeys={[selectedKey]}\n defaultOpenKeys={[selectedKey]}\n items={menuItems as MenuProps['items']}\n onClick={({ key }) => {\n if (key !== location.pathname) navigate(key)\n }}\n style={{ padding: '8px 10px', borderInlineEnd: 'none' }}\n />\n </Sider>\n <Layout>\n <Header\n style={{\n padding: '0 20px',\n background: '#fff',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n borderBottom: `1px solid ${tokens.border}`,\n position: 'sticky',\n top: 0,\n zIndex: 10,\n lineHeight: 1,\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: 12, lineHeight: 'normal' }}>\n <Tooltip title={collapsed ? '展开菜单' : '收起菜单'}>\n <ButtonIcon collapsed={collapsed} onClick={() => setCollapsed(!collapsed)} />\n </Tooltip>\n {hasTenantSwitch && (\n <>\n <div style={{ width: 1, height: 22, background: tokens.borderStrong }} />\n <TenantSwitcher />\n </>\n )}\n </div>\n <div style={{ display: 'flex', alignItems: 'center', gap: 14, lineHeight: 'normal' }}>\n <Dropdown menu={{ items: userMenuItems }} placement=\"bottomRight\" trigger={['click']}>\n <div style={{ display: 'flex', alignItems: 'center', gap: 10, height: 42, padding: '0 8px', lineHeight: 1, borderRadius: 8, cursor: 'pointer' }} className=\"user-entry\">\n <Badge dot color={brand.primary} offset={[-2, 2]}>\n <Avatar\n size={34}\n style={{ background: brand.gradient, fontWeight: 600, fontSize: 14 }}\n icon={!displayName ? <UserOutlined /> : undefined}\n >\n {displayName.charAt(0).toUpperCase()}\n </Avatar>\n </Badge>\n <span style={{ fontSize: 14, color: token.colorText, fontWeight: 500, lineHeight: 1 }}>{displayName}</span>\n </div>\n </Dropdown>\n </div>\n </Header>\n <Content style={{ margin: 20 }}>\n <Outlet />\n </Content>\n </Layout>\n <ProfileCenter open={profileOpen} onClose={() => setProfileOpen(false)} />\n </Layout>\n )\n}\n\ninterface ButtonIconProps {\n collapsed: boolean\n onClick: () => void\n}\n\n// 必须转发 ref:antd 的 Tooltip 依赖 ref 定位气泡,\n// 普通函数组件不支持 ref 会触发 findDOMNode 弃用警告\nconst ButtonIcon = forwardRef<HTMLButtonElement, ButtonIconProps>(function ButtonIcon({ collapsed, onClick }, ref) {\n return (\n <button\n ref={ref}\n onClick={onClick}\n style={{\n width: 36,\n height: 36,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n border: 'none',\n borderRadius: 8,\n background: 'transparent',\n cursor: 'pointer',\n fontSize: 16,\n color: brand.textSecondary,\n }}\n >\n {collapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}\n </button>\n )\n})\n","import { Button, Typography } from 'antd'\nimport { ArrowRightOutlined, SafetyCertificateOutlined } from '@ant-design/icons'\nimport { useAuth } from 'react-oidc-context'\nimport { brand } from './theme'\n\ninterface Props {\n title: string\n subtitle?: string\n}\n\nexport function LoginPage({ title, subtitle }: Props) {\n const auth = useAuth()\n\n return (\n <div\n style={{\n minHeight: '100vh',\n display: 'flex',\n alignItems: 'stretch',\n background: brand.gradientSoft,\n }}\n >\n {/* 左侧品牌区 */}\n <div\n style={{\n flex: 1.2,\n display: 'flex',\n flexDirection: 'column',\n justifyContent: 'center',\n padding: '0 8vw',\n background: brand.gradient,\n color: '#fff',\n position: 'relative',\n overflow: 'hidden',\n }}\n >\n <div\n style={{\n position: 'absolute',\n width: 420,\n height: 420,\n borderRadius: '50%',\n background: 'rgba(255,255,255,0.08)',\n top: -120,\n right: -120,\n }}\n />\n <div\n style={{\n position: 'absolute',\n width: 260,\n height: 260,\n borderRadius: '50%',\n background: 'rgba(255,255,255,0.06)',\n bottom: -60,\n left: -60,\n }}\n />\n <div style={{ display: 'flex', alignItems: 'center', gap: 14, marginBottom: 28, position: 'relative' }}>\n <div\n style={{\n width: 52,\n height: 52,\n borderRadius: 14,\n background: 'rgba(255,255,255,0.18)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: 26,\n backdropFilter: 'blur(4px)',\n }}\n >\n <SafetyCertificateOutlined />\n </div>\n <div>\n <div style={{ fontSize: 22, fontWeight: 700 }}>{title}</div>\n {subtitle && <div style={{ fontSize: 13, opacity: 0.85 }}>{subtitle}</div>}\n </div>\n </div>\n <Typography.Title level={2} style={{ color: '#fff', marginBottom: 12, position: 'relative' }}>\n 统一身份认证平台\n </Typography.Title>\n <Typography.Paragraph style={{ color: 'rgba(255,255,255,0.82)', fontSize: 15, maxWidth: 480, position: 'relative' }}>\n 一个平台管理多应用的账号、权限与安全策略。基于标准 OIDC/OAuth2 协议,\n 支持单点登录、多租户切换与细粒度权限控制。\n </Typography.Paragraph>\n <div style={{ display: 'flex', gap: 24, marginTop: 28, position: 'relative' }}>\n {['单点登录 SSO', '多租户隔离', '细粒度授权'].map((f) => (\n <div\n key={f}\n style={{\n padding: '8px 16px',\n borderRadius: 20,\n background: 'rgba(255,255,255,0.14)',\n fontSize: 13,\n backdropFilter: 'blur(4px)',\n }}\n >\n {f}\n </div>\n ))}\n </div>\n </div>\n\n {/* 右侧登录区 */}\n <div style={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 40 }}>\n <div\n style={{\n width: 380,\n background: '#fff',\n borderRadius: 16,\n boxShadow: '0 20px 60px rgba(15,23,42,0.12)',\n padding: '40px 36px',\n }}\n >\n <div style={{ fontSize: 20, fontWeight: 700, marginBottom: 8 }}>欢迎回来</div>\n <div style={{ fontSize: 14, color: brand.textSecondary, marginBottom: 32 }}>\n 使用统一身份账号登录 {title}\n </div>\n <Button\n type=\"primary\"\n size=\"large\"\n block\n loading={auth.isLoading}\n onClick={() => void auth.signinRedirect()}\n style={{ height: 46, borderRadius: 10, fontWeight: 600, background: brand.gradient, border: 'none', boxShadow: '0 8px 20px rgba(79,110,247,0.35)' }}\n >\n IAM 账号登录 <ArrowRightOutlined />\n </Button>\n <div style={{ marginTop: 24, textAlign: 'center', fontSize: 12, color: brand.textSecondary }}>\n 登录即代表同意平台的安全与隐私策略\n </div>\n </div>\n </div>\n </div>\n )\n}\n","import type { ReactNode } from 'react'\nimport { Card, Space, Typography } from 'antd'\nimport { brand, tokens } from './theme'\n\ninterface Props {\n title: string\n description?: string\n extra?: ReactNode\n children: ReactNode\n loading?: boolean\n}\n\n/**\n * 统一页面容器:页面标题区(标题 + 描述 + 右侧操作按钮)+ 内容卡片。\n * 所有管理页共用,保证页面骨架一致。\n */\nexport function PageContainer({ title, description, extra, children, loading }: Props) {\n return (\n <div>\n <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: 16 }}>\n <div>\n <Typography.Title level={4} style={{ margin: 0, fontWeight: 700 }}>\n {title}\n </Typography.Title>\n {description && (\n <Typography.Text type=\"secondary\" style={{ fontSize: 13 }}>\n {description}\n </Typography.Text>\n )}\n </div>\n {extra && <Space>{extra}</Space>}\n </div>\n <Card\n loading={loading}\n styles={{\n body: { padding: 20 },\n }}\n style={{ borderRadius: 12, border: `1px solid ${tokens.border}` }}\n >\n {children}\n </Card>\n </div>\n )\n}\n\nexport function pageTitleStyle(): React.CSSProperties {\n return { color: brand.text }\n}\n","import type { CSSProperties } from 'react'\nimport { Alert, Button, Modal, Space, message } from 'antd'\nimport { CopyOutlined } from '@ant-design/icons'\nimport { tokens } from './theme'\n\nconst monospaceStyle: CSSProperties = { fontFamily: 'Consolas, Monaco, monospace' }\n\n// TODO(delivery): 本组件是\"一次性回显临时密码\"的前端出口(系统尚无邮件/短信通道);\n// 接入通道后临时密码改为直接下发给账号本人,本组件应改为\"已通过邮件/短信发送\"的提示,\n// 或整体下线。见 docs/design/system-design.md §5.8。\nexport interface InitialPasswordModalProps {\n /**\n * 一次性初始/临时密码明文。为空表示未生成(如复用了既有自然人,其密码未被改动),\n * 此时 Modal 不展示。\n */\n password: string\n /** 弹窗标题,默认「初始密码已生成」。 */\n title?: string\n /** 密码上方的补充说明(如「该成员首次登录必须修改密码」)。 */\n description?: string\n onClose: () => void\n}\n\n/**\n * 一次性初始密码展示 Modal:密码由服务端生成、仅在本次响应返回一次,关闭后不可再查。\n * 平台侧(建租户/重置内置管理员密码)与租户侧(建成员/重置成员密码)共用同一交互,\n * 保证两边\"密码相关交互一致\"(见 docs/design/system-design.md §5.8)。\n */\nexport function InitialPasswordModal({ password, title, description, onClose }: InitialPasswordModalProps) {\n const handleCopy = async () => {\n try {\n await navigator.clipboard.writeText(password)\n message.success('已复制')\n } catch {\n message.error('复制失败,请手动复制')\n }\n }\n return (\n <Modal\n title={title || '初始密码已生成'}\n open={!!password}\n onCancel={onClose}\n footer={\n <Button type=\"primary\" onClick={onClose}>\n 我已保存\n </Button>\n }\n destroyOnClose\n width={560}\n >\n <Alert\n type=\"warning\"\n showIcon\n message=\"请立即保存,关闭后不再显示\"\n description={\n <Space direction=\"vertical\" size={12} style={{ width: '100%' }}>\n {description && <div style={{ color: tokens.textSecondary }}>{description}</div>}\n <div\n style={{\n ...monospaceStyle,\n wordBreak: 'break-all',\n background: tokens.warningBg,\n border: `1px solid ${tokens.warningBorder}`,\n borderRadius: 8,\n padding: '10px 12px',\n }}\n >\n {password}\n </div>\n <Button size=\"small\" icon={<CopyOutlined />} onClick={() => void handleCopy()}>\n 复制\n </Button>\n </Space>\n }\n />\n </Modal>\n )\n}\n","import type { CSSProperties, ReactNode } from 'react'\nimport { Tooltip, Typography } from 'antd'\n\nexport interface NameLinkProps {\n /** 名称内容;空值展示为 - */\n value?: ReactNode\n /** 点击查看详情;未提供时退化为普通文本 */\n onClick?: () => void\n /** 悬浮提示;默认取 value 的字符串形式 */\n title?: string\n /** 使用等宽字体(日志键 / 编码类名称) */\n monospace?: boolean\n}\n\n/**\n * 名称单元格:列表行的「名称即详情入口」(列表页操作列规范,见 DESIGN.md §7.3)。\n *\n * 详情不再占用操作列,而是通过点击名称打开;因此名称渲染为主色链接\n * (hover 下划线 + 手型光标),让用户一眼看出可点击。名称过长时省略号截断并悬浮展示全称。\n */\nexport function NameLink({ value, onClick, title, monospace = false }: NameLinkProps) {\n const empty = value == null || value === ''\n const text: ReactNode = empty ? '-' : value\n const style: CSSProperties = {\n display: 'inline-block',\n fontWeight: 500,\n maxWidth: '100%',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n verticalAlign: 'bottom',\n ...(monospace ? { fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace', fontSize: 12 } : {}),\n }\n\n if (empty || !onClick) {\n return <span style={style}>{text}</span>\n }\n\n const tooltip =\n title ?? (typeof value === 'string' || typeof value === 'number' ? String(value) : undefined)\n\n return (\n <Tooltip title={tooltip} mouseEnterDelay={0.3}>\n <Typography.Link onClick={onClick} style={style}>\n {text}\n </Typography.Link>\n </Tooltip>\n )\n}\n","import type { ReactNode } from 'react'\nimport type { ColumnType } from 'antd/es/table'\nimport { EllipsisCell } from './EllipsisCell'\nimport { IDCell } from './IDCell'\nimport { NameLink } from './NameLink'\nimport { RowActions, type RowAction } from './RowActions'\n\n/**\n * 列表列宽标准(px)与列工厂(规范见 frontend/DESIGN.md §7.3)。\n *\n * 背景:历史 bug 是各页手写列宽 + 手写 `scroll.x`,列宽普遍偏大(ID 150、编码 180…)\n * 叠加后总宽轻松超过内容区,导致「一进列表就有横向滚动条、操作列要横滑很久才看得到」。\n * 这里把所有列宽收口成具名常量与工厂,页面不再出现魔法数字。\n *\n * 列宽 = 内容实测宽 + antd v5 单元格左右内边距(16 × 2 = 32)。\n */\n\n/** ID 列:`IDCell` 默认展示「首 8 + … + 尾 4」共 13 个 12px 等宽字符(≈93.6px)+ 内边距。 */\nexport const ID_COL_WIDTH = 130\n/** 名称列:约 10 个汉字;过长由 `NameLink` / `EllipsisCell` 省略号截断。 */\nexport const NAME_COL_WIDTH = 180\n/** 编码 / key / 域名等等宽短标识列。 */\nexport const CODE_COL_WIDTH = 150\n/** 分类 Tag 列(类型 / 可见性 / 来源等)。 */\nexport const TAG_COL_WIDTH = 110\n/** 状态 Tag 列(正常 / 挂起 / 启用 / 停用)。 */\nexport const STATUS_COL_WIDTH = 100\n/** 数字计数列(成员数、角色数、排序)。 */\nexport const COUNT_COL_WIDTH = 90\n/** 自由文本列(描述、备注等),一律省略号截断。 */\nexport const TEXT_COL_WIDTH = 200\n/** 长文本列(日志 payload、长描述):比 `TEXT_COL_WIDTH` 宽一档,仍省略号截断。 */\nexport const LONG_TEXT_COL_WIDTH = 320\n\n/** antd v5 单元格左右内边距合计(16 × 2)。 */\nconst CELL_PADDING = 32\n/** 操作列横排按钮宽度预算:约 3 个汉字(42px)+ link 按钮左右内边距(14px)。 */\nconst ACTION_BUTTON_BUDGET = 56\n/** `RowActions` 横排 `Space` 间隔。 */\nconst ACTION_GAP = 4\n\n/* ------------------------------------------------------------------ *\n * 列工厂\n * ------------------------------------------------------------------ */\n\nexport interface IDColumnConfig<T> {\n /** 记录中的 ID 字段 */\n dataIndex: keyof T & string\n /** 列标题,默认 `ID` */\n title?: string\n /** 覆盖默认列宽(默认 `ID_COL_WIDTH`) */\n width?: number\n}\n\n/**\n * ID 列:`IDCell`(等宽 + 首 8 尾 4 + Tooltip 可拖选复制)。\n *\n * 同一行已有对外可读业务键(编码 / 客户端编码 / key / 域名)时,内部 UUID 列通常是噪声,\n * 可按需省略;保留时一律用本工厂(默认 130,而非手写 150)。\n */\nexport function idColumn<T>({ dataIndex, title = 'ID', width }: IDColumnConfig<T>): ColumnType<T> {\n return {\n title,\n dataIndex,\n key: dataIndex,\n width: width ?? ID_COL_WIDTH,\n render: (value: unknown) => <IDCell value={value as string | number | null | undefined} />,\n }\n}\n\nexport interface TextColumnConfig<T> {\n title: ReactNode\n /** 记录字段名;同时作为列的 key */\n dataIndex: keyof T & string\n /** 列宽;不传时取 `TEXT_COL_WIDTH` */\n width?: number\n /** 空值占位文案,默认 `-` */\n placeholder?: string\n /** 等宽字体(编码 / key / 路径等) */\n monospace?: boolean\n}\n\n/**\n * 文本列:`EllipsisCell`(超出省略号截断 + 悬浮展示全文),列宽固定不随内容膨胀。\n */\nexport function textColumn<T>({\n title,\n dataIndex,\n width,\n placeholder,\n monospace,\n}: TextColumnConfig<T>): ColumnType<T> {\n return {\n title,\n dataIndex,\n key: dataIndex,\n width: width ?? TEXT_COL_WIDTH,\n render: (value: unknown) => (\n <EllipsisCell\n value={value as string | number | null | undefined}\n placeholder={placeholder}\n monospace={monospace}\n />\n ),\n }\n}\n\nexport interface NameColumnConfig<T> {\n title: ReactNode\n /** 记录字段名;同时作为列的 key */\n dataIndex: keyof T & string\n /** 列宽;不传时取 `NAME_COL_WIDTH` */\n width?: number\n /** 等宽字体(日志键 / 编码类名称) */\n monospace?: boolean\n /** 点击名称的回调(详情 / 下级入口);不传时退化为普通文本 */\n onClick?: (record: T) => void\n}\n\n/**\n * 名称列:`NameLink`(主色链接,详情入口;见 DESIGN.md §7.3 R2)。\n */\nexport function nameColumn<T>({\n title,\n dataIndex,\n width,\n monospace,\n onClick,\n}: NameColumnConfig<T>): ColumnType<T> {\n return {\n title,\n dataIndex,\n key: dataIndex,\n width: width ?? NAME_COL_WIDTH,\n render: (value: unknown, record: T) => (\n <NameLink\n value={value as ReactNode}\n monospace={monospace}\n onClick={onClick ? () => onClick(record) : undefined}\n />\n ),\n }\n}\n\nexport interface ActionColumnConfig<T> {\n /** 由记录生成操作列表,按重要程度从高到低排列 */\n actions: (record: T) => RowAction[]\n /** 横排上限,超过则收起为「更多」下拉;默认 3 */\n max?: number\n /** 覆盖自动计算的列宽 */\n width?: number\n}\n\n/**\n * 操作列工厂(列表页操作列规范,DESIGN.md §7.3 R1):\n * - 统一 `RowActions` 渲染(≤ max 横排,> max 收「更多」);\n * - **永远 `fixed: 'right'`**:即使表格出现横向滚动,操作列也钉在右侧可见,\n * 不会再出现「横向滑动很久才看到操作」;\n * - 列宽由 `actionColumnWidth(max)` 统一给出,页面禁止再手写 120/200/240。\n */\nexport function actionColumn<T>({ actions, max = 3, width }: ActionColumnConfig<T>): ColumnType<T> {\n return {\n title: '操作',\n key: 'action',\n fixed: 'right',\n width: width ?? actionColumnWidth(max),\n render: (_, record) => <RowActions actions={actions(record)} max={max} />,\n }\n}\n\n/**\n * 操作列宽度估算(px):`单元格内边距 32 + 横排数 × 56 + 间距 4`,向上取整到 10。\n *\n * 56 = 约 3 个汉字(42px)+ link 按钮左右内边距(14px)。**横排按钮文案应保持简短\n * (≤ 4 个汉字)**;文案更长时请降低 `max` 把它收进「更多」下拉,或显式传入 `width`。\n */\nexport function actionColumnWidth(max: number): number {\n const inline = Math.max(1, max)\n const raw = CELL_PADDING + inline * ACTION_BUTTON_BUDGET + (inline - 1) * ACTION_GAP\n return Math.ceil(raw / 10) * 10\n}\n\n/* ------------------------------------------------------------------ *\n * 横向滚动\n * ------------------------------------------------------------------ */\n\ntype WidthableColumn<T> = ColumnType<T> & { children?: WidthableColumn<T>[] }\n\n/**\n * 由列定义计算表格 `scroll.x`:所有列宽之和。\n *\n * 取代各页手写的 `scroll={{ x: 1490 }}`——手写值会随列增删漂移(历史上 apiKey 页\n * 实际列宽合计已到 1580 却仍写 1520),且写大了会让本可放下的表格也强制出现横滚条。\n *\n * 配合 `tableLayout=\"fixed\"`:列宽严格生效(`EllipsisCell` / `TimeCell` 才能正确截断),\n * 总宽小于容器时表格按 `min-width: 100%` 铺满,不会留白也不会出现滚动条。\n *\n * ```tsx\n * <Table columns={columns} scroll={tableScrollX(columns)} tableLayout=\"fixed\" />\n * ```\n */\nexport function tableScrollX<T>(columns: readonly WidthableColumn<T>[]): { x: number } {\n let total = 0\n const walk = (list: readonly WidthableColumn<T>[]) => {\n for (const column of list) {\n if (column.children?.length) {\n walk(column.children)\n continue\n }\n total += typeof column.width === 'number' ? column.width : 0\n }\n }\n walk(columns)\n return { x: total }\n}\n","import { useCallback, useEffect, useRef, useState, type CSSProperties } from 'react'\nimport { Select, Spin } from 'antd'\n\nexport interface RemoteSelectOption {\n value: string\n label: string\n}\n\ninterface RemoteOptionsProps {\n /** 远程取数:关键字为空表示取默认首页;返回值直接作为下拉选项 */\n fetchOptions: (keyword: string) => Promise<RemoteSelectOption[]>\n /** 搜索去抖毫秒数,默认 300 */\n debounceMs?: number\n /** 可选的外部名称缓存(`Map<值, 名称>`):多个下拉共享已知名称,如筛选区选过的服务账号在弹窗表单里直接显示名称 */\n labelCache?: Map<string, string>\n}\n\n/**\n * 远程选项 + 「值 → 名称」缓存的共用逻辑(单选 / 多选只差渲染与回调形态)。\n *\n * 三条不变量:\n * 1. `filterOption={false}`:本地过滤关闭,过滤交给服务端(否则只能搜到已加载的那一页);\n * 2. 过期响应丢弃(序号比对):快速输入时旧关键字的结果不会覆盖新结果;\n * 3. 已选值始终有名称:`labelCache`(含外部缓存)与历史搜索结果累积,新搜索结果替换选项后\n * 当前选中项仍然显示名称而不是裸 ID。\n */\nfunction useRemoteOptions({ fetchOptions, debounceMs = 300, labelCache }: RemoteOptionsProps) {\n const [options, setOptions] = useState<RemoteSelectOption[]>([])\n const [loading, setLoading] = useState(false)\n const internalLabelsRef = useRef(new Map<string, string>())\n const labels = labelCache ?? internalLabelsRef.current\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n const seqRef = useRef(0)\n\n const search = useCallback(\n async (keyword: string) => {\n const seq = ++seqRef.current\n setLoading(true)\n try {\n const list = await fetchOptions(keyword)\n if (seq !== seqRef.current) return // 过期响应:丢弃,避免旧结果覆盖新关键字\n for (const item of list) labels.set(item.value, item.label)\n setOptions(list)\n } catch {\n /* 请求错误由 axios 拦截器统一提示 */\n } finally {\n if (seq === seqRef.current) setLoading(false)\n }\n },\n [fetchOptions, labels],\n )\n\n useEffect(\n () => () => {\n if (timerRef.current) clearTimeout(timerRef.current)\n },\n [],\n )\n\n const handleSearch = useCallback(\n (keyword: string) => {\n if (timerRef.current) clearTimeout(timerRef.current)\n timerRef.current = setTimeout(() => void search(keyword), debounceMs)\n },\n [search, debounceMs],\n )\n\n // 只读取名:名称缓存 → 当前选项 → 兜底显示值本身\n const labelOf = useCallback(\n (v: string) => labels.get(v) ?? options.find((o) => o.value === v)?.label ?? v,\n [labels, options],\n )\n\n // 已选值不在当前选项里时补上前缀项,保证选中项显示名称而不是 ID\n const withSelected = useCallback(\n (values: string[]) => {\n const missing = values.filter((v) => !options.some((o) => o.value === v))\n return missing.length ? [...missing.map((v) => ({ value: v, label: labelOf(v) })), ...options] : options\n },\n [labelOf, options],\n )\n\n // 写入名称缓存,并把选中项返回给调用方(onChange 第二参)\n const remember = useCallback(\n (values: string[]) =>\n values.map((v) => {\n const label = labelOf(v)\n labels.set(v, label)\n return { value: v, label }\n }),\n [labelOf, labels],\n )\n\n return { loading, search, handleSearch, withSelected, remember, labels }\n}\n\nexport interface RemoteSelectProps extends RemoteOptionsProps {\n /** 受控值(`Form.Item` 自动注入) */\n value?: string\n /** 选中回调;第二参为选中项,便于调用方保存名称(平台端列表经常要回显名称) */\n onChange?: (value?: string, option?: RemoteSelectOption) => void\n placeholder?: string\n disabled?: boolean\n allowClear?: boolean\n /** 固定宽度(筛选区用);表单内不传则由容器撑满 */\n width?: number\n /** 额外样式(如 `{ width: '100%' }` 撑满表单) */\n style?: CSSProperties\n /** 已知当前值对应的名称:编辑态回显,避免选项未加载时显示裸 ID */\n initialLabel?: string\n id?: string\n}\n\n/**\n * 远程搜索下拉(单选):选项由 `fetchOptions` 按关键字从服务端取,不在前端一次性全量加载。\n *\n * 解决「下拉只取前 N 条 → 数据量上百后选不到目标」的问题(租户/应用/服务账号等可增长资源)。\n * 不变量见 `useRemoteOptions`。\n */\nexport function RemoteSelect({\n value,\n onChange,\n initialLabel,\n placeholder,\n disabled,\n allowClear,\n width,\n style,\n id,\n ...rest\n}: RemoteSelectProps) {\n const remote = useRemoteOptions(rest)\n\n useEffect(() => {\n if (value && initialLabel) remote.labels.set(value, initialLabel)\n }, [value, initialLabel, remote.labels])\n\n // 首屏取默认首页:不展开下拉也能看到候选项\n useEffect(() => {\n if (disabled) return\n void remote.search('')\n }, [remote.search, disabled])\n\n const handleChange = (next?: string) => {\n onChange?.(next, next ? remote.remember([next])[0] : undefined)\n }\n\n return (\n <Select\n id={id}\n showSearch\n filterOption={false}\n allowClear={allowClear}\n placeholder={placeholder}\n disabled={disabled}\n loading={remote.loading}\n style={width ? { width, ...style } : style}\n value={value}\n onChange={handleChange}\n onSearch={remote.handleSearch}\n options={remote.withSelected(value ? [value] : [])}\n notFoundContent={remote.loading ? <Spin size=\"small\" /> : null}\n />\n )\n}\n\nexport interface RemoteMultiSelectProps extends RemoteOptionsProps {\n /** 受控值(多选,`Form.Item` 自动注入) */\n value?: string[]\n onChange?: (value?: string[], option?: RemoteSelectOption[]) => void\n /** 已知已选值的名称(如主体当前已分配的角色):避免搜索结果未命中时显示裸 ID */\n initialLabels?: Record<string, string>\n placeholder?: string\n disabled?: boolean\n allowClear?: boolean\n /** 固定宽度(筛选区用);表单内不传则由容器撑满 */\n width?: number\n /** 额外样式(如 `{ width: '100%' }` 撑满表单) */\n style?: CSSProperties\n id?: string\n}\n\n/**\n * 远程搜索下拉(多选):与 `RemoteSelect` 共用同一套「服务端搜索 + 过期响应丢弃 + 已选值名称兜底」,\n * 用于角色授权这类「候选集可增长 + 已选项必须回显名称」的多值场景。\n */\nexport function RemoteMultiSelect({\n value,\n onChange,\n initialLabels,\n placeholder,\n disabled,\n allowClear,\n width,\n style,\n id,\n ...rest\n}: RemoteMultiSelectProps) {\n const remote = useRemoteOptions(rest)\n const values = value ?? []\n\n useEffect(() => {\n if (!initialLabels) return\n Object.entries(initialLabels).forEach(([v, label]) => {\n if (v && label) remote.labels.set(v, label)\n })\n }, [initialLabels, remote.labels])\n\n useEffect(() => {\n if (disabled) return\n void remote.search('')\n }, [remote.search, disabled])\n\n const handleChange = (next?: string[]) => {\n const nextValues = next ?? []\n onChange?.(nextValues, nextValues.length ? remote.remember(nextValues) : [])\n }\n\n return (\n <Select\n id={id}\n mode=\"multiple\"\n showSearch\n filterOption={false}\n allowClear={allowClear}\n placeholder={placeholder}\n disabled={disabled}\n loading={remote.loading}\n style={width ? { width, ...style } : style}\n value={values}\n onChange={handleChange}\n onSearch={remote.handleSearch}\n options={remote.withSelected(values)}\n notFoundContent={remote.loading ? <Spin size=\"small\" /> : null}\n />\n )\n}\n","import type { ReactNode } from 'react'\nimport { ConfigProvider, App as AntdApp } from 'antd'\nimport zhCN from 'antd/locale/zh_CN'\nimport dayjs from 'dayjs'\nimport 'dayjs/locale/zh-cn'\nimport { themeConfig } from './theme'\n\ndayjs.locale('zh-cn')\n\ninterface Props {\n children: ReactNode\n}\n\n/**\n * 应用外壳:注入 Ant Design 全局主题(中文语言包 + 设计令牌)。\n * 每个前端 app 的 main.tsx 用 <AppShell> 包裹。\n * 根容器开启 tabular-nums,让 ID/时间/数字等宽对齐(Stripe 数据细节,见 DESIGN.md)。\n *\n * 全局 antd「结构级」微修正也集中在此:AppShell 是各 app 唯一公共挂载点,\n * 而这类修正针对 antd 内部 DOM / portal 渲染的下拉等,无法用组件 inline style 表达\n * (约定与清单见 DESIGN.md §7.1)。禁止各 app 新增 css 文件或在页面散落重复 <style>。\n */\nexport function AppShell({ children }: Props) {\n return (\n <div style={{ fontVariantNumeric: 'tabular-nums' }}>\n {/* TreeSelect 下拉树:去掉顶层节点的左侧空白。antd 树即使对最顶层节点也会渲染\n 固定的“展开/收起箭头列” .ant-select-tree-switcher(默认宽 24px),把宽度归 0、\n 隐藏溢出后顶层节点即与下拉框左对齐;子级缩进由 .ant-select-tree-indent-unit\n (每个 24px)独立控制,不受影响。 */}\n <style>{`\n .ant-select-dropdown .ant-select-tree .ant-select-tree-switcher {\n width: 0;\n overflow: hidden;\n }\n `}</style>\n <ConfigProvider locale={zhCN} theme={themeConfig}>\n <AntdApp>{children}</AntdApp>\n </ConfigProvider>\n </div>\n )\n}\n","import { Tag } from 'antd'\n\n/**\n * 状态标签规范(详见 frontend/DESIGN.md「Components → 状态 Tag」)\n *\n * 两类字典严格区分:\n * - 语义状态(enable/disable/挂起/验证)→ 语义色 success/default/error/warning;\n * - 分类标识(类型/来源等)→ 固定分类色,不做状态语义。\n * 禁止在页面内联用 green/red/orange 等传统色名表示状态,避免跨 app 配色漂移。\n */\n\nexport type StatusValue = string | number | null | undefined\n\n/** 启用/停用状态:enable → 启用(success);disable → 停用(default);其余原样回显 */\nexport function EnableTag({ value }: { value?: string }) {\n if (value === 'enable') {\n return <Tag color=\"success\">启用</Tag>\n }\n if (value === 'disable') {\n return <Tag color=\"default\">停用</Tag>\n }\n return <Tag>{value || '-'}</Tag>\n}\n\n/**\n * 挂起状态:只认 status 枚举(后端 model.UserStatus / PersonStatus),\n * 'suspended' → 挂起(error);'active' → 正常(success)。\n *\n * **不再兼容 isSuspended 的 1/true/0/false**:P3 起 user/person 状态统一为 status 枚举,\n * 保留对布尔/数字的兼容会掩盖「读了已下线字段」的缺陷(值恒为 undefined → 恒显示「正常」)。\n */\nexport function SuspendedTag({ value }: { value?: StatusValue | boolean }) {\n return value === 'suspended' ? <Tag color=\"error\">挂起</Tag> : <Tag color=\"success\">正常</Tag>\n}\n\n/**\n * 验证状态(后端具名类型 model.DomainVerificationStatus):只认 'verified' → 已验证(success);\n * 'unverified' 及其它取值 → 未验证(warning)。不再兼容 isVerified 的 1/0。\n */\nexport function VerifiedTag({ value }: { value?: StatusValue }) {\n return value === 'verified' ? <Tag color=\"success\">已验证</Tag> : <Tag color=\"warning\">未验证</Tag>\n}\n\n/** 类型标识(分类色,非状态语义):租户类型 platform→geekblue、customer→cyan;其余原样回显 */\nconst TYPE_META: Record<string, { label: string; color: string }> = {\n platform: { label: '平台', color: 'geekblue' },\n customer: { label: '客户', color: 'cyan' },\n}\n\n/** 应用/租户类型标识(分类色,非状态语义) */\nexport function TypeTag({ value }: { value?: string }) {\n const meta = TYPE_META[value ?? '']\n return meta ? <Tag color={meta.color}>{meta.label}</Tag> : <Tag>{value || '-'}</Tag>\n}\n\n/**\n * 来源标识(分类色,非状态语义),一套映射覆盖两种来源字典:\n * - 应用 / OAuth 客户端 `source`(`model.AppSource`):builtin→内置(gold)、first_party→第一方(blue)、third_party→第三方(orange);\n * - 角色 `source`(`model.RoleSource`):builtin→内置(gold)、custom→自定义(blue)。\n */\nconst SOURCE_META: Record<string, { label: string; color: string }> = {\n builtin: { label: '内置', color: 'gold' },\n first_party: { label: '第一方', color: 'blue' },\n third_party: { label: '第三方', color: 'orange' },\n custom: { label: '自定义', color: 'blue' },\n}\n\n/** 来源标识:应用/客户端 source 与角色 source 共用 */\nexport function SourceTag({ value }: { value?: string }) {\n const meta = SOURCE_META[value ?? '']\n return meta ? <Tag color={meta.color}>{meta.label}</Tag> : <Tag>{value || '-'}</Tag>\n}\n"],"names":["_a","ButtonIcon","AntdApp"],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 状态标签规范(详见 frontend/DESIGN.md「Components → 状态 Tag」)
|
|
3
|
+
*
|
|
4
|
+
* 两类字典严格区分:
|
|
5
|
+
* - 语义状态(enable/disable/挂起/验证)→ 语义色 success/default/error/warning;
|
|
6
|
+
* - 分类标识(类型/来源等)→ 固定分类色,不做状态语义。
|
|
7
|
+
* 禁止在页面内联用 green/red/orange 等传统色名表示状态,避免跨 app 配色漂移。
|
|
8
|
+
*/
|
|
9
|
+
export type StatusValue = string | number | null | undefined;
|
|
10
|
+
/** 启用/停用状态:enable → 启用(success);disable → 停用(default);其余原样回显 */
|
|
11
|
+
export declare function EnableTag({ value }: {
|
|
12
|
+
value?: string;
|
|
13
|
+
}): import("react").JSX.Element;
|
|
14
|
+
/**
|
|
15
|
+
* 挂起状态:只认 status 枚举(后端 model.UserStatus / PersonStatus),
|
|
16
|
+
* 'suspended' → 挂起(error);'active' → 正常(success)。
|
|
17
|
+
*
|
|
18
|
+
* **不再兼容 isSuspended 的 1/true/0/false**:P3 起 user/person 状态统一为 status 枚举,
|
|
19
|
+
* 保留对布尔/数字的兼容会掩盖「读了已下线字段」的缺陷(值恒为 undefined → 恒显示「正常」)。
|
|
20
|
+
*/
|
|
21
|
+
export declare function SuspendedTag({ value }: {
|
|
22
|
+
value?: StatusValue | boolean;
|
|
23
|
+
}): import("react").JSX.Element;
|
|
24
|
+
/**
|
|
25
|
+
* 验证状态(后端具名类型 model.DomainVerificationStatus):只认 'verified' → 已验证(success);
|
|
26
|
+
* 'unverified' 及其它取值 → 未验证(warning)。不再兼容 isVerified 的 1/0。
|
|
27
|
+
*/
|
|
28
|
+
export declare function VerifiedTag({ value }: {
|
|
29
|
+
value?: StatusValue;
|
|
30
|
+
}): import("react").JSX.Element;
|
|
31
|
+
/** 应用/租户类型标识(分类色,非状态语义) */
|
|
32
|
+
export declare function TypeTag({ value }: {
|
|
33
|
+
value?: string;
|
|
34
|
+
}): import("react").JSX.Element;
|
|
35
|
+
/** 来源标识:应用/客户端 source 与角色 source 共用 */
|
|
36
|
+
export declare function SourceTag({ value }: {
|
|
37
|
+
value?: string;
|
|
38
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { ThemeConfig } from 'antd';
|
|
2
|
+
/**
|
|
3
|
+
* Ark IAM 全局设计令牌(唯一事实源)
|
|
4
|
+
*
|
|
5
|
+
* 设计方向:「冷白工程台」收敛(受 Stripe / Vercel 工程控制台启发,见 DESIGN.md 参照锚点)。
|
|
6
|
+
* 靛蓝只出现在主按钮 / 链接 / 选中态 / 品牌区;页面表面一律中性灰阶,
|
|
7
|
+
* 卡片以 hairline 边框分层(无阴影);文字为三级 hex 灰阶。
|
|
8
|
+
* 命名与 frontend/DESIGN.md 的 colors 段一一对应,改动需两处同步。
|
|
9
|
+
*/
|
|
10
|
+
export declare const tokens: {
|
|
11
|
+
primary: string;
|
|
12
|
+
primaryHover: string;
|
|
13
|
+
primaryActive: string;
|
|
14
|
+
gradient: string;
|
|
15
|
+
gradientSoft: string;
|
|
16
|
+
purple: string;
|
|
17
|
+
selectedBg: string;
|
|
18
|
+
bg: string;
|
|
19
|
+
cardBg: string;
|
|
20
|
+
sidebarBg: string;
|
|
21
|
+
headerBg: string;
|
|
22
|
+
tableHeaderBg: string;
|
|
23
|
+
rowHoverBg: string;
|
|
24
|
+
softFill: string;
|
|
25
|
+
codeBg: string;
|
|
26
|
+
border: string;
|
|
27
|
+
borderStrong: string;
|
|
28
|
+
text: string;
|
|
29
|
+
textSecondary: string;
|
|
30
|
+
textPlaceholder: string;
|
|
31
|
+
success: string;
|
|
32
|
+
warning: string;
|
|
33
|
+
error: string;
|
|
34
|
+
warningBg: string;
|
|
35
|
+
warningBorder: string;
|
|
36
|
+
};
|
|
37
|
+
/** 历史兼容:品牌相关令牌(主色/渐变/背景/文字)。新代码请引用 tokens。 */
|
|
38
|
+
export declare const brand: {
|
|
39
|
+
primary: string;
|
|
40
|
+
primaryHover: string;
|
|
41
|
+
primaryActive: string;
|
|
42
|
+
gradient: string;
|
|
43
|
+
gradientSoft: string;
|
|
44
|
+
bg: string;
|
|
45
|
+
sidebarBg: string;
|
|
46
|
+
text: string;
|
|
47
|
+
textSecondary: string;
|
|
48
|
+
};
|
|
49
|
+
export declare const themeConfig: ThemeConfig;
|
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './_types/api/index';
|
package/dist/api.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { c, a, b, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T } from "./index-BQuRl5A6.js";
|
|
2
|
+
export {
|
|
3
|
+
c as createApiClient,
|
|
4
|
+
a as createApplication,
|
|
5
|
+
b as createDomain,
|
|
6
|
+
d as createMenu,
|
|
7
|
+
e as createOAuthClient,
|
|
8
|
+
f as createOAuthSecret,
|
|
9
|
+
g as createTenant,
|
|
10
|
+
h as createTenantApplication,
|
|
11
|
+
i as deleteApplication,
|
|
12
|
+
j as deleteDomain,
|
|
13
|
+
k as deleteMenu,
|
|
14
|
+
l as deleteOAuthClient,
|
|
15
|
+
m as deleteOAuthSecret,
|
|
16
|
+
n as deleteTenant,
|
|
17
|
+
o as deleteTenantApplication,
|
|
18
|
+
p as getApplicationDetail,
|
|
19
|
+
q as getApplicationPageList,
|
|
20
|
+
r as getDomainDetail,
|
|
21
|
+
s as getDomainPageList,
|
|
22
|
+
t as getMenuTree,
|
|
23
|
+
u as getMyMenuTree,
|
|
24
|
+
v as getMyTenants,
|
|
25
|
+
w as getOAuthClientDetail,
|
|
26
|
+
x as getOAuthClientPageList,
|
|
27
|
+
y as getPersonDetail,
|
|
28
|
+
z as getSessionList,
|
|
29
|
+
A as getTenantApplicationPageList,
|
|
30
|
+
B as getTenantPageList,
|
|
31
|
+
C as getUserinfo,
|
|
32
|
+
D as listOAuthSecrets,
|
|
33
|
+
E as logoutAPI,
|
|
34
|
+
F as logoutAllAPI,
|
|
35
|
+
G as request,
|
|
36
|
+
H as resetTenantAdminPassword,
|
|
37
|
+
I as revokeAllSessions,
|
|
38
|
+
J as revokeSession,
|
|
39
|
+
K as setSessionExpiredHandler,
|
|
40
|
+
L as setUserProvider,
|
|
41
|
+
M as updateApplication,
|
|
42
|
+
N as updateDomain,
|
|
43
|
+
O as updateMenu,
|
|
44
|
+
P as updateOAuthClient,
|
|
45
|
+
Q as updatePassword,
|
|
46
|
+
R as updateTenant,
|
|
47
|
+
S as updateTenantApplication,
|
|
48
|
+
T as useSSOSessionProbe
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=api.js.map
|
package/dist/api.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './_types/auth/index';
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { F, c, d, a, b, e, f, g, o, s, u, h, i } from "./index-D3uUqZ5c.js";
|
|
2
|
+
export {
|
|
3
|
+
F as FullPageSpinner,
|
|
4
|
+
c as createAuthProvider,
|
|
5
|
+
d as defaultIssuer,
|
|
6
|
+
a as defaultPostLogoutRedirectPath,
|
|
7
|
+
b as defaultRedirectPath,
|
|
8
|
+
e as defaultScope,
|
|
9
|
+
f as fetchRuntimeConfig,
|
|
10
|
+
g as getCurrentTenantId,
|
|
11
|
+
o as oidcExtraQueryParams,
|
|
12
|
+
s as setCurrentTenantId,
|
|
13
|
+
u as useAuthGuard,
|
|
14
|
+
h as useLogout,
|
|
15
|
+
i as useTenantSwitching
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import { message } from "antd";
|
|
3
|
+
import { BizCode } from "./types.js";
|
|
4
|
+
import { useEffect } from "react";
|
|
5
|
+
let userProvider = null;
|
|
6
|
+
let sessionExpiredHandler = null;
|
|
7
|
+
function setUserProvider(provider) {
|
|
8
|
+
userProvider = provider;
|
|
9
|
+
}
|
|
10
|
+
function setSessionExpiredHandler(handler) {
|
|
11
|
+
sessionExpiredHandler = handler;
|
|
12
|
+
}
|
|
13
|
+
function attachInterceptors(instance) {
|
|
14
|
+
instance.interceptors.request.use((config) => {
|
|
15
|
+
const user = userProvider == null ? void 0 : userProvider();
|
|
16
|
+
if ((user == null ? void 0 : user.access_token) && config.headers) {
|
|
17
|
+
config.headers.Authorization = `Bearer ${user.access_token}`;
|
|
18
|
+
}
|
|
19
|
+
return config;
|
|
20
|
+
});
|
|
21
|
+
instance.interceptors.response.use(
|
|
22
|
+
(response) => {
|
|
23
|
+
var _a;
|
|
24
|
+
const { code, msg } = response.data;
|
|
25
|
+
if (code === BizCode.Success) return response.data.data;
|
|
26
|
+
const isLogoutRequest = (_a = response.config.url) == null ? void 0 : _a.includes("/auth/logout");
|
|
27
|
+
if (code === BizCode.TokenExpired || code === BizCode.TokenInvalid || code === BizCode.Unauthorized) {
|
|
28
|
+
if (isLogoutRequest) return Promise.reject(new Error(msg || "session expired"));
|
|
29
|
+
handleSessionExpired();
|
|
30
|
+
return Promise.reject(new Error(msg || "未认证"));
|
|
31
|
+
}
|
|
32
|
+
if (code === BizCode.Forbidden || code === BizCode.PermissionDenied) {
|
|
33
|
+
if (!response.config.silent) message.warning("暂无权限访问");
|
|
34
|
+
return Promise.reject(new Error(msg || "暂无权限"));
|
|
35
|
+
}
|
|
36
|
+
if (!response.config.silent) message.error(msg || "请求失败");
|
|
37
|
+
return Promise.reject(new Error(msg || "请求失败"));
|
|
38
|
+
},
|
|
39
|
+
async (error) => {
|
|
40
|
+
var _a, _b, _c;
|
|
41
|
+
if (((_a = error.response) == null ? void 0 : _a.status) === 401) {
|
|
42
|
+
handleSessionExpired();
|
|
43
|
+
return Promise.reject(error);
|
|
44
|
+
}
|
|
45
|
+
const data = (_b = error.response) == null ? void 0 : _b.data;
|
|
46
|
+
if (!((_c = error.config) == null ? void 0 : _c.silent)) message.error((data == null ? void 0 : data.msg) || "请求失败");
|
|
47
|
+
return Promise.reject(error);
|
|
48
|
+
}
|
|
49
|
+
);
|
|
50
|
+
return instance;
|
|
51
|
+
}
|
|
52
|
+
function handleSessionExpired() {
|
|
53
|
+
sessionExpiredHandler == null ? void 0 : sessionExpiredHandler();
|
|
54
|
+
window.location.href = "/";
|
|
55
|
+
}
|
|
56
|
+
function createApiClient(opts = {}) {
|
|
57
|
+
const instance = axios.create({
|
|
58
|
+
baseURL: opts.baseURL ?? "/v1",
|
|
59
|
+
timeout: opts.timeout ?? 3e4,
|
|
60
|
+
headers: opts.headers
|
|
61
|
+
});
|
|
62
|
+
return attachInterceptors(instance);
|
|
63
|
+
}
|
|
64
|
+
const request = createApiClient();
|
|
65
|
+
function useSSOSessionProbe(auth) {
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
var _a;
|
|
68
|
+
if (!((_a = auth.events) == null ? void 0 : _a.addSilentRenewError)) return;
|
|
69
|
+
const unsub = auth.events.addSilentRenewError(() => {
|
|
70
|
+
void auth.removeUser();
|
|
71
|
+
});
|
|
72
|
+
return unsub;
|
|
73
|
+
}, [auth.events]);
|
|
74
|
+
}
|
|
75
|
+
const getUserinfo = () => request.get("/auth/userinfo");
|
|
76
|
+
const getMyTenants = () => request.get("/auth/me/tenants");
|
|
77
|
+
const logoutAPI = (refreshToken) => request.post("/auth/logout", { refreshToken });
|
|
78
|
+
const logoutAllAPI = (refreshToken) => request.post("/auth/logoutAll", { refreshToken });
|
|
79
|
+
const getPersonDetail = () => request.get("/auth/me");
|
|
80
|
+
const updatePassword = (req) => request.post("/auth/me/changePassword", req);
|
|
81
|
+
const getSessionList = (params) => request.get("/auth/me/sessions", { params });
|
|
82
|
+
const revokeSession = (sessionID) => request.delete(`/auth/me/sessions/${sessionID}`);
|
|
83
|
+
const revokeAllSessions = () => request.delete("/auth/me/sessions");
|
|
84
|
+
const getApplicationPageList = (data) => request.get("/platform/applications", { params: data });
|
|
85
|
+
const getApplicationDetail = (appID, config) => request.get(`/platform/applications/${appID}`, config);
|
|
86
|
+
const createApplication = (data) => request.post("/platform/applications", data);
|
|
87
|
+
const updateApplication = (data) => {
|
|
88
|
+
const { appID, ...body } = data;
|
|
89
|
+
return request.put(`/platform/applications/${appID}`, body);
|
|
90
|
+
};
|
|
91
|
+
const deleteApplication = (appID) => request.delete(`/platform/applications/${appID}`);
|
|
92
|
+
const getOAuthClientPageList = (data) => request.get("/platform/application-clients", { params: data });
|
|
93
|
+
const getOAuthClientDetail = (applicationClientID) => request.get(`/platform/application-clients/${applicationClientID}`);
|
|
94
|
+
const createOAuthClient = (data) => request.post("/platform/application-clients", data);
|
|
95
|
+
const updateOAuthClient = (data) => {
|
|
96
|
+
const { applicationClientID, ...body } = data;
|
|
97
|
+
return request.put(`/platform/application-clients/${applicationClientID}`, body);
|
|
98
|
+
};
|
|
99
|
+
const deleteOAuthClient = (applicationClientID) => request.delete(`/platform/application-clients/${applicationClientID}`);
|
|
100
|
+
const listOAuthSecrets = (applicationClientID) => request.get(`/platform/application-clients/${applicationClientID}/secrets`);
|
|
101
|
+
const createOAuthSecret = (data) => {
|
|
102
|
+
const { applicationClientID, ...body } = data;
|
|
103
|
+
return request.post(`/platform/application-clients/${applicationClientID}/secrets`, body);
|
|
104
|
+
};
|
|
105
|
+
const deleteOAuthSecret = (applicationClientID, secretID) => request.delete(`/platform/application-clients/${applicationClientID}/secrets/${secretID}`);
|
|
106
|
+
const getTenantPageList = (data) => request.get("/platform/tenants", { params: data });
|
|
107
|
+
const createTenant = (data) => request.post("/platform/tenants", data);
|
|
108
|
+
const resetTenantAdminPassword = (tenantID) => request.post(`/platform/tenants/${tenantID}/builtin-admin/reset-password`);
|
|
109
|
+
const updateTenant = (data) => {
|
|
110
|
+
const { tenantID, ...body } = data;
|
|
111
|
+
return request.put(`/platform/tenants/${tenantID}`, body);
|
|
112
|
+
};
|
|
113
|
+
const deleteTenant = (tenantID) => request.delete(`/platform/tenants/${tenantID}`);
|
|
114
|
+
const getTenantApplicationPageList = (data) => request.get("/platform/tenant-applications", { params: data });
|
|
115
|
+
const createTenantApplication = (data) => request.post("/platform/tenant-applications", data);
|
|
116
|
+
const updateTenantApplication = (data) => {
|
|
117
|
+
const { tenantAppID, ...body } = data;
|
|
118
|
+
return request.put(`/platform/tenant-applications/${tenantAppID}`, body);
|
|
119
|
+
};
|
|
120
|
+
const deleteTenantApplication = (tenantAppID) => request.delete(`/platform/tenant-applications/${tenantAppID}`);
|
|
121
|
+
const getMenuTree = (appID) => request.get("/platform/menus/tree", { params: { appID } });
|
|
122
|
+
const getMyMenuTree = () => request.get("/platform/menus/my");
|
|
123
|
+
const createMenu = (data) => request.post("/platform/menus", data);
|
|
124
|
+
const updateMenu = (data) => {
|
|
125
|
+
const { menuID, ...body } = data;
|
|
126
|
+
return request.put(`/platform/menus/${menuID}`, body);
|
|
127
|
+
};
|
|
128
|
+
const deleteMenu = (menuID) => request.delete(`/platform/menus/${menuID}`);
|
|
129
|
+
const getDomainPageList = (data) => request.get("/platform/domains", { params: data });
|
|
130
|
+
const getDomainDetail = (id) => request.get(`/platform/domains/${id}`);
|
|
131
|
+
const createDomain = (domain) => request.post("/platform/domains", { domain });
|
|
132
|
+
const updateDomain = (data) => {
|
|
133
|
+
const { id, ...body } = data;
|
|
134
|
+
return request.put(`/platform/domains/${id}`, body);
|
|
135
|
+
};
|
|
136
|
+
const deleteDomain = (id) => request.delete(`/platform/domains/${id}`);
|
|
137
|
+
export {
|
|
138
|
+
getTenantApplicationPageList as A,
|
|
139
|
+
getTenantPageList as B,
|
|
140
|
+
getUserinfo as C,
|
|
141
|
+
listOAuthSecrets as D,
|
|
142
|
+
logoutAPI as E,
|
|
143
|
+
logoutAllAPI as F,
|
|
144
|
+
request as G,
|
|
145
|
+
resetTenantAdminPassword as H,
|
|
146
|
+
revokeAllSessions as I,
|
|
147
|
+
revokeSession as J,
|
|
148
|
+
setSessionExpiredHandler as K,
|
|
149
|
+
setUserProvider as L,
|
|
150
|
+
updateApplication as M,
|
|
151
|
+
updateDomain as N,
|
|
152
|
+
updateMenu as O,
|
|
153
|
+
updateOAuthClient as P,
|
|
154
|
+
updatePassword as Q,
|
|
155
|
+
updateTenant as R,
|
|
156
|
+
updateTenantApplication as S,
|
|
157
|
+
useSSOSessionProbe as T,
|
|
158
|
+
createApplication as a,
|
|
159
|
+
createDomain as b,
|
|
160
|
+
createApiClient as c,
|
|
161
|
+
createMenu as d,
|
|
162
|
+
createOAuthClient as e,
|
|
163
|
+
createOAuthSecret as f,
|
|
164
|
+
createTenant as g,
|
|
165
|
+
createTenantApplication as h,
|
|
166
|
+
deleteApplication as i,
|
|
167
|
+
deleteDomain as j,
|
|
168
|
+
deleteMenu as k,
|
|
169
|
+
deleteOAuthClient as l,
|
|
170
|
+
deleteOAuthSecret as m,
|
|
171
|
+
deleteTenant as n,
|
|
172
|
+
deleteTenantApplication as o,
|
|
173
|
+
getApplicationDetail as p,
|
|
174
|
+
getApplicationPageList as q,
|
|
175
|
+
getDomainDetail as r,
|
|
176
|
+
getDomainPageList as s,
|
|
177
|
+
getMenuTree as t,
|
|
178
|
+
getMyMenuTree as u,
|
|
179
|
+
getMyTenants as v,
|
|
180
|
+
getOAuthClientDetail as w,
|
|
181
|
+
getOAuthClientPageList as x,
|
|
182
|
+
getPersonDetail as y,
|
|
183
|
+
getSessionList as z
|
|
184
|
+
};
|
|
185
|
+
//# sourceMappingURL=index-BQuRl5A6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-BQuRl5A6.js","sources":["../../api/dist/index.js"],"sourcesContent":["import axios from \"axios\";\nimport { message } from \"antd\";\nimport { BizCode } from \"@ark-iam/types\";\nimport { useEffect } from \"react\";\nlet userProvider = null;\nlet sessionExpiredHandler = null;\nfunction setUserProvider(provider) {\n userProvider = provider;\n}\nfunction setSessionExpiredHandler(handler) {\n sessionExpiredHandler = handler;\n}\nfunction attachInterceptors(instance) {\n instance.interceptors.request.use((config) => {\n const user = userProvider == null ? void 0 : userProvider();\n if ((user == null ? void 0 : user.access_token) && config.headers) {\n config.headers.Authorization = `Bearer ${user.access_token}`;\n }\n return config;\n });\n instance.interceptors.response.use(\n (response) => {\n var _a;\n const { code, msg } = response.data;\n if (code === BizCode.Success) return response.data.data;\n const isLogoutRequest = (_a = response.config.url) == null ? void 0 : _a.includes(\"/auth/logout\");\n if (code === BizCode.TokenExpired || code === BizCode.TokenInvalid || code === BizCode.Unauthorized) {\n if (isLogoutRequest) return Promise.reject(new Error(msg || \"session expired\"));\n handleSessionExpired();\n return Promise.reject(new Error(msg || \"未认证\"));\n }\n if (code === BizCode.Forbidden || code === BizCode.PermissionDenied) {\n if (!response.config.silent) message.warning(\"暂无权限访问\");\n return Promise.reject(new Error(msg || \"暂无权限\"));\n }\n if (!response.config.silent) message.error(msg || \"请求失败\");\n return Promise.reject(new Error(msg || \"请求失败\"));\n },\n async (error) => {\n var _a, _b, _c;\n if (((_a = error.response) == null ? void 0 : _a.status) === 401) {\n handleSessionExpired();\n return Promise.reject(error);\n }\n const data = (_b = error.response) == null ? void 0 : _b.data;\n if (!((_c = error.config) == null ? void 0 : _c.silent)) message.error((data == null ? void 0 : data.msg) || \"请求失败\");\n return Promise.reject(error);\n }\n );\n return instance;\n}\nfunction handleSessionExpired() {\n sessionExpiredHandler == null ? void 0 : sessionExpiredHandler();\n window.location.href = \"/\";\n}\nfunction createApiClient(opts = {}) {\n const instance = axios.create({\n baseURL: opts.baseURL ?? \"/v1\",\n timeout: opts.timeout ?? 3e4,\n headers: opts.headers\n });\n return attachInterceptors(instance);\n}\nconst request = createApiClient();\nfunction useSSOSessionProbe(auth) {\n useEffect(() => {\n var _a;\n if (!((_a = auth.events) == null ? void 0 : _a.addSilentRenewError)) return;\n const unsub = auth.events.addSilentRenewError(() => {\n void auth.removeUser();\n });\n return unsub;\n }, [auth.events]);\n}\nconst getUserinfo = () => request.get(\"/auth/userinfo\");\nconst getMyTenants = () => request.get(\"/auth/me/tenants\");\nconst logoutAPI = (refreshToken) => request.post(\"/auth/logout\", { refreshToken });\nconst logoutAllAPI = (refreshToken) => request.post(\"/auth/logoutAll\", { refreshToken });\nconst getPersonDetail = () => request.get(\"/auth/me\");\nconst updatePassword = (req) => request.post(\"/auth/me/changePassword\", req);\nconst getSessionList = (params) => request.get(\"/auth/me/sessions\", { params });\nconst revokeSession = (sessionID) => request.delete(`/auth/me/sessions/${sessionID}`);\nconst revokeAllSessions = () => request.delete(\"/auth/me/sessions\");\nconst getApplicationPageList = (data) => request.get(\"/platform/applications\", { params: data });\nconst getApplicationDetail = (appID, config) => request.get(`/platform/applications/${appID}`, config);\nconst createApplication = (data) => request.post(\"/platform/applications\", data);\nconst updateApplication = (data) => {\n const { appID, ...body } = data;\n return request.put(`/platform/applications/${appID}`, body);\n};\nconst deleteApplication = (appID) => request.delete(`/platform/applications/${appID}`);\nconst getOAuthClientPageList = (data) => request.get(\"/platform/application-clients\", { params: data });\nconst getOAuthClientDetail = (applicationClientID) => request.get(`/platform/application-clients/${applicationClientID}`);\nconst createOAuthClient = (data) => request.post(\"/platform/application-clients\", data);\nconst updateOAuthClient = (data) => {\n const { applicationClientID, ...body } = data;\n return request.put(`/platform/application-clients/${applicationClientID}`, body);\n};\nconst deleteOAuthClient = (applicationClientID) => request.delete(`/platform/application-clients/${applicationClientID}`);\nconst listOAuthSecrets = (applicationClientID) => request.get(`/platform/application-clients/${applicationClientID}/secrets`);\nconst createOAuthSecret = (data) => {\n const { applicationClientID, ...body } = data;\n return request.post(`/platform/application-clients/${applicationClientID}/secrets`, body);\n};\nconst deleteOAuthSecret = (applicationClientID, secretID) => request.delete(`/platform/application-clients/${applicationClientID}/secrets/${secretID}`);\nconst getTenantPageList = (data) => request.get(\"/platform/tenants\", { params: data });\nconst createTenant = (data) => request.post(\"/platform/tenants\", data);\nconst resetTenantAdminPassword = (tenantID) => request.post(`/platform/tenants/${tenantID}/builtin-admin/reset-password`);\nconst updateTenant = (data) => {\n const { tenantID, ...body } = data;\n return request.put(`/platform/tenants/${tenantID}`, body);\n};\nconst deleteTenant = (tenantID) => request.delete(`/platform/tenants/${tenantID}`);\nconst getTenantApplicationPageList = (data) => request.get(\"/platform/tenant-applications\", { params: data });\nconst createTenantApplication = (data) => request.post(\"/platform/tenant-applications\", data);\nconst updateTenantApplication = (data) => {\n const { tenantAppID, ...body } = data;\n return request.put(`/platform/tenant-applications/${tenantAppID}`, body);\n};\nconst deleteTenantApplication = (tenantAppID) => request.delete(`/platform/tenant-applications/${tenantAppID}`);\nconst getMenuTree = (appID) => request.get(\"/platform/menus/tree\", { params: { appID } });\nconst getMyMenuTree = () => request.get(\"/platform/menus/my\");\nconst createMenu = (data) => request.post(\"/platform/menus\", data);\nconst updateMenu = (data) => {\n const { menuID, ...body } = data;\n return request.put(`/platform/menus/${menuID}`, body);\n};\nconst deleteMenu = (menuID) => request.delete(`/platform/menus/${menuID}`);\nconst getDomainPageList = (data) => request.get(\"/platform/domains\", { params: data });\nconst getDomainDetail = (id) => request.get(`/platform/domains/${id}`);\nconst createDomain = (domain) => request.post(\"/platform/domains\", { domain });\nconst updateDomain = (data) => {\n const { id, ...body } = data;\n return request.put(`/platform/domains/${id}`, body);\n};\nconst deleteDomain = (id) => request.delete(`/platform/domains/${id}`);\nexport {\n createApiClient,\n createApplication,\n createDomain,\n createMenu,\n createOAuthClient,\n createOAuthSecret,\n createTenant,\n createTenantApplication,\n deleteApplication,\n deleteDomain,\n deleteMenu,\n deleteOAuthClient,\n deleteOAuthSecret,\n deleteTenant,\n deleteTenantApplication,\n getApplicationDetail,\n getApplicationPageList,\n getDomainDetail,\n getDomainPageList,\n getMenuTree,\n getMyMenuTree,\n getMyTenants,\n getOAuthClientDetail,\n getOAuthClientPageList,\n getPersonDetail,\n getSessionList,\n getTenantApplicationPageList,\n getTenantPageList,\n getUserinfo,\n listOAuthSecrets,\n logoutAPI,\n logoutAllAPI,\n request,\n resetTenantAdminPassword,\n revokeAllSessions,\n revokeSession,\n setSessionExpiredHandler,\n setUserProvider,\n updateApplication,\n updateDomain,\n updateMenu,\n updateOAuthClient,\n updatePassword,\n updateTenant,\n updateTenantApplication,\n useSSOSessionProbe\n};\n//# sourceMappingURL=index.js.map\n"],"names":[],"mappings":"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"}
|