{"version":3,"sources":["../src/utils/api-error.ts","../src/utils/auth.ts","../src/utils/clipboard.ts","../src/utils/formatters/business.ts","../src/utils/formatters/constants.ts","../src/utils/formatters/date.ts","../src/utils/formatters/number.ts","../src/utils/formatters/text.ts","../src/utils/navigation.ts","../src/utils/performance.ts","../src/utils/permission.ts","../src/utils/region.ts","../src/utils/sanitize.ts","../src/utils/storage.ts","../src/utils/theme.ts","../src/utils/tree.ts","../src/utils/url.ts","../src/utils/validators.ts","../src/utils/value-enum.ts","../src/utils/watermark.ts"],"names":["dayjs","relativeTime","children"],"mappings":"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","file":"chunk-BPVQEWGS.cjs","sourcesContent":["/**\n * API 错误处理增强工具\n *\n * 在请求层 error-handler 的基础上，提供业务层的错误处理包装。\n * 包含 ProTable 请求包装器、统一错误处理器等。\n *\n */\n\nimport { ErrorShowType } from '../constants/ui';\nimport type { ProTableResponse } from '../types/api';\n\n/**\n * API 错误处理配置\n */\nexport interface ApiErrorHandlerConfig {\n  /** message 展示函数 */\n  showMessage?: (\n    content: string,\n    type: 'success' | 'error' | 'warning' | 'info',\n  ) => void;\n  /** notification 展示函数 */\n  showNotification?: (options: {\n    message: string;\n    description?: string;\n  }) => void;\n  /** 重定向函数 */\n  redirect?: (path: string) => void;\n  /** 登录过期回调 */\n  onUnauthorized?: () => void;\n  /** 登录过期的状态码 */\n  unauthorizedCodes?: (string | number)[];\n  /** notification 标题，默认 'Request Error' */\n  notificationTitle?: string;\n  /** 重定向路径，默认 '/error' */\n  redirectPath?: string;\n}\n\n/**\n * 创建项目级 API 错误处理器\n *\n * @param config - 错误处理配置\n * @returns 错误处理函数\n *\n * @example\n * ```ts\n * const handleApiError = createApiErrorHandler({\n *   showMessage: (content, type) => message[type](content),\n *   showNotification: ({ message: msg, description }) => notification.error({ message: msg, description }),\n *   onUnauthorized: () => emitLoginRequired(),\n *   unauthorizedCodes: [401, 10014],\n *   notificationTitle: '请求错误',\n * });\n *\n * // 在请求拦截器中使用\n * handleApiError(error, ErrorShowType.ERROR_MESSAGE);\n * ```\n */\nexport function createApiErrorHandler(config: ApiErrorHandlerConfig) {\n  const {\n    showMessage,\n    showNotification,\n    redirect,\n    onUnauthorized,\n    unauthorizedCodes = [401, 10014],\n    notificationTitle = 'Request Error',\n    redirectPath = '/error',\n  } = config;\n\n  return function handleApiError(\n    error: unknown,\n    showType: ErrorShowType = ErrorShowType.ERROR_MESSAGE,\n  ): void {\n    const errorMessage = extractErrorMessage(error);\n    const errorCode = extractErrorCode(error);\n\n    // 检查登录过期\n    if (\n      errorCode !== undefined &&\n      unauthorizedCodes.some((c) => String(c) === String(errorCode))\n    ) {\n      onUnauthorized?.();\n      return;\n    }\n\n    switch (showType) {\n      case ErrorShowType.SILENT:\n        break;\n      case ErrorShowType.WARN_MESSAGE:\n        showMessage?.(errorMessage, 'warning');\n        break;\n      case ErrorShowType.ERROR_MESSAGE:\n        showMessage?.(errorMessage, 'error');\n        break;\n      case ErrorShowType.NOTIFICATION:\n        showNotification?.({\n          message: notificationTitle,\n          description: errorMessage,\n        });\n        break;\n      case ErrorShowType.REDIRECT:\n        redirect?.(redirectPath);\n        break;\n    }\n  };\n}\n\n/**\n * 从错误对象中提取错误消息\n *\n * @param error - 错误对象\n * @param defaultMessage - 默认错误消息，默认 'Unknown error'\n * @returns 错误消息字符串\n */\nexport function extractErrorMessage(\n  error: unknown,\n  defaultMessage = 'Unknown error',\n): string {\n  if (!error) return defaultMessage;\n\n  // Error 实例\n  if (error instanceof Error) return error.message;\n\n  // API 响应格式 { msg: '...' } 或 { message: '...' }\n  if (typeof error === 'object') {\n    const obj = error as Record<string, unknown>;\n    if (typeof obj.msg === 'string') return obj.msg;\n    if (typeof obj.message === 'string') return obj.message;\n    if (typeof obj.errorMessage === 'string') return obj.errorMessage;\n  }\n\n  // 字符串\n  if (typeof error === 'string') return error;\n\n  return defaultMessage;\n}\n\n/**\n * 从错误对象中提取错误码\n *\n * @param error - 错误对象\n * @returns 错误码\n */\nexport function extractErrorCode(error: unknown): string | number | undefined {\n  if (!error || typeof error !== 'object') return undefined;\n  const obj = error as Record<string, unknown>;\n  if (obj.code !== undefined) return obj.code as string | number;\n  if (obj.status !== undefined) return obj.status as string | number;\n  if (obj.statusCode !== undefined) return obj.statusCode as string | number;\n  return undefined;\n}\n\n/**\n * 包装 ProTable 的 request 函数，自动处理错误并返回标准格式\n *\n * 确保即使 API 调用失败，ProTable 也不会崩溃，始终返回合法的空数据。\n *\n * @param requestFn - 原始请求函数\n * @param options - 配置选项\n * @returns 包装后的请求函数\n *\n * @example\n * ```ts\n * const safeRequest = wrapProTableRequest(\n *   async (params) => {\n *     const res = await getUserList(params);\n *     return { data: res.data.list, total: res.data.total, success: true };\n *   },\n *   { onError: (err) => message.error(err.message) }\n * );\n *\n * <ProTable request={safeRequest} />\n * ```\n */\nexport function wrapProTableRequest<T, P = Record<string, unknown>>(\n  requestFn: (params: P) => Promise<ProTableResponse<T>>,\n  options?: {\n    /** 错误回调 */\n    onError?: (error: Error) => void;\n  },\n): (params: P) => Promise<ProTableResponse<T>> {\n  return async (params: P): Promise<ProTableResponse<T>> => {\n    try {\n      return await requestFn(params);\n    } catch (error) {\n      const err =\n        error instanceof Error ? error : new Error(extractErrorMessage(error));\n      options?.onError?.(err);\n      return { data: [], success: false, total: 0 };\n    }\n  };\n}\n","/**\n * 认证工具函数工厂\n *\n *\n * 通过配置适配不同的认证方式。\n */\n\n/**\n * AuthManager 配置\n */\nexport interface AuthManagerConfig {\n  /** token/session 在 localStorage 中的 key */\n  tokenKey: string;\n  /** 过期时间存储 key (可选，用于 session 有效期管理) */\n  expireKey?: string;\n  /** 会话有效期 (毫秒)，不设置则不自动过期 */\n  ttlMs?: number;\n  /** 需要在 clearAuth 时额外清除的 localStorage key 列表 */\n  extraStorageKeys?: string[];\n  /** 登出后的回调 (如跳转登录页) */\n  onUnauthorized?: () => void;\n}\n\n/**\n * AuthManager 实例\n */\nexport interface AuthManager {\n  /** 获取 token (自动检查过期) */\n  getToken: () => string | null;\n  /** 设置 token (自动写入过期时间) */\n  setToken: (token: string) => void;\n  /** 清除所有认证信息 */\n  clearAuth: () => void;\n  /** 处理未授权状态 (清除认证 + 执行 onUnauthorized 回调) */\n  handleUnauthorized: () => void;\n  /** 检查是否已认证 */\n  isAuthenticated: () => boolean;\n}\n\n/**\n * 创建认证管理器\n *\n * @param config - 认证配置\n * @returns AuthManager 实例\n *\n * @example\n * ```ts\n * // mc-guide 风格 (session + 过期时间)\n * const auth = createAuthManager({\n *   tokenKey: 'sessionId',\n *   expireKey: 'sessionExpireAt',\n *   ttlMs: 30 * 24 * 60 * 60 * 1000, // 30天\n *   extraStorageKeys: ['isAdmin'],\n *   onUnauthorized: () => history.push('/user/login'),\n * });\n *\n * // ruiying 风格 (token + 额外数据)\n * const auth = createAuthManager({\n *   tokenKey: 'token',\n *   extraStorageKeys: ['userButtons', 'userMenus', 'userRoles', 'userId', 'userName'],\n *   onUnauthorized: () => emitLoginRequired(),\n * });\n *\n * // keel-cloud 风格 (Bearer token)\n * const auth = createAuthManager({\n *   tokenKey: 'kc_auth_token',\n *   onUnauthorized: () => history.push('/login'),\n * });\n *\n * // 使用\n * auth.setToken('abc123');\n * const token = auth.getToken(); // 'abc123'\n * auth.clearAuth(); // 清除所有\n * ```\n */\n/** 安全获取 localStorage（SSR 环境返回 null） */\nfunction safeStorage() {\n  try {\n    return typeof window !== 'undefined' ? window.localStorage : null;\n  } catch {\n    return null;\n  }\n}\n\nexport function createAuthManager(config: AuthManagerConfig): AuthManager {\n  const {\n    tokenKey,\n    expireKey,\n    ttlMs,\n    extraStorageKeys = [],\n    onUnauthorized,\n  } = config;\n\n  function getToken(): string | null {\n    const storage = safeStorage();\n    if (!storage) return null;\n    const token = storage.getItem(tokenKey);\n    if (!token) return null;\n\n    // 检查过期\n    if (expireKey && ttlMs) {\n      const expireAt = safeStorage()?.getItem(expireKey) ?? null;\n      if (expireAt) {\n        const expireTime = Number.parseInt(expireAt, 10);\n        if (!Number.isNaN(expireTime) && Date.now() > expireTime) {\n          clearAuth();\n          return null;\n        }\n      }\n    }\n\n    return token;\n  }\n\n  function setToken(token: string): void {\n    if (!token) return;\n    const storage = safeStorage();\n    if (!storage) return;\n    storage.setItem(tokenKey, token);\n\n    // 写入过期时间\n    if (expireKey && ttlMs) {\n      const expireAt = Date.now() + ttlMs;\n      storage.setItem(expireKey, String(expireAt));\n    }\n  }\n\n  function clearAuth(): void {\n    const storage = safeStorage();\n    if (!storage) return;\n    storage.removeItem(tokenKey);\n    if (expireKey) {\n      storage.removeItem(expireKey);\n    }\n    // 清除额外存储\n    for (const key of extraStorageKeys) {\n      storage.removeItem(key);\n    }\n  }\n\n  function handleUnauthorized(): void {\n    clearAuth();\n    onUnauthorized?.();\n  }\n\n  function isAuthenticated(): boolean {\n    return getToken() !== null;\n  }\n\n  return {\n    getToken,\n    setToken,\n    clearAuth,\n    handleUnauthorized,\n    isAuthenticated,\n  };\n}\n\n/**\n * 登录事件常量 (用于跨组件通信触发登录模态框)\n */\nexport const LOGIN_REQUIRED_EVENT = 'auth:login-required';\n\n/**\n * 触发登录请求事件\n *\n * @example\n * ```ts\n * // 在 request interceptor 中\n * emitLoginRequired();\n *\n * // 在组件中监听\n * window.addEventListener('auth:login-required', () => setLoginVisible(true));\n * ```\n */\nexport function emitLoginRequired(): void {\n  if (typeof window === 'undefined') return;\n  window.dispatchEvent(new CustomEvent(LOGIN_REQUIRED_EVENT));\n}\n","/**\n * 剪贴板工具函数\n *\n * 使用 Clipboard API (所有现代浏览器均支持)\n */\n\n/**\n * 复制文本到剪贴板\n *\n * @param text - 要复制的文本\n * @returns 是否复制成功\n *\n * @example\n * ```ts\n * const success = await copyToClipboard('Hello World');\n * if (success) {\n *   message.success('已复制到剪贴板');\n * }\n * ```\n */\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  try {\n    await navigator.clipboard.writeText(text);\n    return true;\n  } catch {\n    // Clipboard API 不可用或权限被拒绝\n    return false;\n  }\n}\n","/**\n * 业务辅助格式化工具\n *\n * 包含特定业务场景逻辑（如中文面议、Java 后端数据格式）。\n */\n\n/**\n * 格式化价格显示（支持面议状态）\n *\n * @category Business Helpers\n * @param price - 价格值\n * @param options - 配置选项\n * @returns 格式化后的价格字符串\n */\nexport function formatPrice(\n  price: number | string | undefined | null,\n  options?: { prefix?: string; suffix?: string; negotiableText?: string },\n): string {\n  const { prefix = '', suffix = '', negotiableText = '-' } = options || {};\n\n  if (price === undefined || price === null || price === '')\n    return negotiableText;\n\n  const priceNum = Number(price);\n  if (Number.isNaN(priceNum) || priceNum < 0) {\n    return negotiableText;\n  }\n\n  return `${prefix}${priceNum}${suffix}`;\n}\n\n/**\n * 判断价格是否为面议\n *\n * 统一的价格面议判断逻辑，支持 undefined / null / 空字符串 / NaN / 负数。\n *\n * @category Business Helpers\n * @param price - 价格值\n * @returns 是否面议\n */\nexport function isNegotiablePrice(\n  price: number | string | undefined | null,\n): boolean {\n  if (price === undefined || price === null || price === '') return true;\n  const priceNum = Number(price);\n  return Number.isNaN(priceNum) || priceNum < 0;\n}\n\n/**\n * 格式化地址显示\n *\n * 将逗号分隔的地址字符串替换为指定分隔符（默认空格）。\n *\n * @category Business Helpers\n * @param location - 地址字符串\n * @param separator - 分隔符，默认 ' '\n * @returns 格式化后的地址\n */\nexport function formatLocation(\n  location: string | undefined | null,\n  separator: string = ' ',\n): string {\n  if (!location) return '';\n  return location.replace(/,/g, separator).trim();\n}\n\n/** 布尔标志类型：支持数字、字符串、布尔值 */\ntype BooleanFlag = number | string | boolean | undefined | null;\n\n/**\n * 检查布尔标志是否为真值\n *\n * 支持后端返回的多种布尔表示形式（数字 1、字符串 \"1\"、布尔值等）。\n *\n * @category Business Helpers\n * @param flag - 布尔标志值\n * @param trueLabels - 额外的真值标签列表\n * @returns 是否为真\n */\nexport function checkBooleanFlag(\n  flag: BooleanFlag,\n  trueLabels: string[] = [],\n): boolean {\n  if (flag === undefined || flag === null) return false;\n  const strValue = String(flag);\n  return (\n    flag === 1 ||\n    flag === true ||\n    ['1', 'true', 'yes', ...trueLabels].includes(strValue.toLowerCase())\n  );\n}\n\n/** Java 字符串数组输入类型：字符串或字符串数组 */\ntype JavaStringArrayInput = string | string[] | undefined | null;\n\n/**\n * 解析 Java String 数组格式\n *\n * 支持 JSON 数组字符串 `[\"a\",\"b\"]` 和普通字符串，自动过滤空值。\n * 用于对接 Java 后端返回的字符串数组字段。\n *\n * @category Business Helpers\n * @param val - 输入值\n * @returns 解析后的字符串数组\n */\nexport function parseJavaStringArray(val: JavaStringArrayInput): string[] {\n  if (!val) return [];\n\n  if (Array.isArray(val)) {\n    return val.filter((v) => v && typeof v === 'string' && v.trim() !== '');\n  }\n\n  const trimmed = val.trim();\n  if (!trimmed) return [];\n\n  // 优先尝试 JSON.parse\n  if (trimmed.startsWith('[')) {\n    try {\n      const parsed: unknown = JSON.parse(trimmed);\n      if (Array.isArray(parsed)) {\n        return parsed\n          .map((item) => String(item).trim())\n          .filter((item) => item !== '');\n      }\n    } catch {\n      // JSON 解析失败，当作单值\n    }\n  }\n\n  return [trimmed];\n}\n","/**\n * 格式化相关常量\n */\n\n/** 空值占位符 */\nexport const EMPTY_PLACEHOLDER = '--';\n","/**\n * 日期时间格式化工具\n */\n\nimport dayjs from 'dayjs';\nimport relativeTime from 'dayjs/plugin/relativeTime';\nimport { EMPTY_PLACEHOLDER } from './constants';\n\n/** 标记 relativeTime 插件是否已加载 */\nlet pluginInitialized = false;\n\n/** 默认日期格式 */\nexport const DEFAULT_DATE_FORMAT = 'YYYY-MM-DD';\n\n/** 默认日期时间格式 */\nexport const DEFAULT_DATETIME_FORMAT = 'YYYY-MM-DD HH:mm:ss';\n\n/**\n * 确保 dayjs 插件已加载（惰性初始化，避免模块级副作用）\n */\nfunction ensurePlugins(): void {\n  if (!pluginInitialized) {\n    dayjs.extend(relativeTime);\n    pluginInitialized = true;\n  }\n}\n\n/**\n * 初始化格式化工具的 locale 设置\n *\n * 在应用启动时调用一次，设置 dayjs 的全局 locale。\n * 如果不调用，dayjs 将使用默认的 'en' locale。\n *\n * @param locale - dayjs locale 名称，如 'zh-cn'\n */\nexport function initFormatters(locale: string): void {\n  ensurePlugins();\n  dayjs.locale(locale);\n}\n\n/**\n * 格式化日期\n *\n * @param date - 日期值 (字符串/数字/Date/dayjs)\n * @param format - 格式模板，默认 'YYYY-MM-DD'\n * @returns 格式化后的日期字符串，无效日期返回 '--'\n */\nexport function formatDate(\n  date: string | number | Date | dayjs.Dayjs | null | undefined,\n  format: string = DEFAULT_DATE_FORMAT,\n): string {\n  if (!date) return EMPTY_PLACEHOLDER;\n  const d = dayjs(date);\n  return d.isValid() ? d.format(format) : EMPTY_PLACEHOLDER;\n}\n\n/**\n * 格式化日期时间\n *\n * @param date - 日期值\n * @param format - 格式模板，默认 'YYYY-MM-DD HH:mm:ss'\n * @returns 格式化后的日期时间字符串\n */\nexport function formatDateTime(\n  date: string | number | Date | dayjs.Dayjs | null | undefined,\n  format: string = DEFAULT_DATETIME_FORMAT,\n): string {\n  return formatDate(date, format);\n}\n\n/**\n * 格式化为相对时间 (如 \"5分钟前\"、\"3天前\")\n *\n * 30天以内显示相对时间，超过30天显示具体日期。\n *\n * @param date - 日期值\n * @param thresholdDays - 超过此天数显示具体日期，默认 30\n * @returns 相对时间字符串\n */\nexport function formatRelativeTime(\n  date: string | number | Date | dayjs.Dayjs | null | undefined,\n  thresholdDays: number = 30,\n): string {\n  if (!date) return EMPTY_PLACEHOLDER;\n  ensurePlugins();\n  const d = dayjs(date);\n  if (!d.isValid()) return EMPTY_PLACEHOLDER;\n\n  const diffDays = dayjs().diff(d, 'day');\n  if (diffDays < thresholdDays) {\n    return d.fromNow();\n  }\n  return d.format(DEFAULT_DATE_FORMAT);\n}\n","/**\n * 数字格式化工具\n */\n\nimport { EMPTY_PLACEHOLDER } from './constants';\n\n/**\n * 格式化数字 (千分位分隔)\n *\n * 使用 `Intl.NumberFormat` 实现，支持多语言 locale、性能更优。\n *\n * @param num - 数字\n * @param precision - 小数位数，默认不处理\n * @param locale - BCP 47 语言标签，如 'zh-CN'、'en-US'，默认使用浏览器 locale\n * @returns 格式化后的字符串\n */\nexport function formatNumber(\n  num: number | string | null | undefined,\n  precision?: number,\n  locale?: string,\n): string {\n  if (num === null || num === undefined || num === '') return EMPTY_PLACEHOLDER;\n  const n = typeof num === 'string' ? Number.parseFloat(num) : num;\n  if (Number.isNaN(n)) return EMPTY_PLACEHOLDER;\n\n  const options: Intl.NumberFormatOptions = {};\n  if (precision !== undefined) {\n    options.minimumFractionDigits = precision;\n    options.maximumFractionDigits = precision;\n  }\n\n  return new Intl.NumberFormat(locale, options).format(n);\n}\n\n/**\n * 格式化货币\n *\n * 使用 `Intl.NumberFormat` 实现，支持多语言 locale。\n * 默认使用前缀符号模式（`¥1,234.50`），与原有行为一致。\n *\n * @param amount - 金额\n * @param currency - 货币符号，默认 '¥'\n * @param precision - 小数位数，默认 2\n * @param locale - BCP 47 语言标签，默认使用浏览器 locale\n * @returns 格式化后的货币字符串\n */\nexport function formatCurrency(\n  amount: number | string | null | undefined,\n  currency: string = '¥',\n  precision: number = 2,\n  locale?: string,\n): string {\n  if (amount === null || amount === undefined || amount === '')\n    return EMPTY_PLACEHOLDER;\n  const n = typeof amount === 'string' ? Number.parseFloat(amount) : amount;\n  if (Number.isNaN(n)) return EMPTY_PLACEHOLDER;\n  return `${currency}${formatNumber(n, precision, locale)}`;\n}\n\n/**\n * 格式化百分比\n *\n * @param value - 数值 (0-1 或 0-100)\n * @param decimals - 小数位数，默认 2\n * @param isRatio - 是否为比率 (0-1)，默认 false\n * @returns 格式化后的百分比字符串\n */\nexport function formatPercentage(\n  value: number | null | undefined,\n  decimals: number = 2,\n  isRatio: boolean = false,\n): string {\n  if (value === null || value === undefined) return EMPTY_PLACEHOLDER;\n  const pct = isRatio ? value * 100 : value;\n  return `${pct.toFixed(decimals)}%`;\n}\n\n/**\n * 格式化文件大小\n *\n * @param bytes - 字节数\n * @param decimals - 小数位数，默认 2\n * @returns 格式化后的文件大小字符串\n */\nexport function formatBytes(\n  bytes: number | null | undefined,\n  decimals: number = 2,\n): string {\n  if (bytes === null || bytes === undefined) return EMPTY_PLACEHOLDER;\n  if (bytes === 0) return '0 B';\n\n  const k = 1024;\n  const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];\n  const i = Math.floor(Math.log(Math.abs(bytes)) / Math.log(k));\n  const size = bytes / k ** i;\n\n  return `${size.toFixed(decimals)} ${sizes[i]}`;\n}\n","/**\n * 文本格式化工具\n */\n\nimport { EMPTY_PLACEHOLDER } from './constants';\n\n/**\n * 格式化手机号 (脱敏)\n *\n * @param phone - 手机号\n * @param mask - 掩码字符，默认 '*'\n * @returns 脱敏后的手机号\n */\nexport function formatPhone(\n  phone: string | null | undefined,\n  mask: string = '*',\n): string {\n  if (!phone) return EMPTY_PLACEHOLDER;\n  const str = String(phone).trim();\n  if (str.length < 7) return str;\n  return `${str.slice(0, 3)}${mask.repeat(4)}${str.slice(-4)}`;\n}\n\n/**\n * 格式化文本 (截断 + 省略号)\n *\n * @param text - 原始文本\n * @param maxLength - 最大长度，默认 50\n * @param suffix - 省略后缀，默认 '...'\n * @returns 截断后的文本\n */\nexport function formatText(\n  text: string | null | undefined,\n  maxLength: number = 50,\n  suffix: string = '...',\n): string {\n  if (!text) return EMPTY_PLACEHOLDER;\n  if (text.length <= maxLength) return text;\n  return `${text.slice(0, maxLength)}${suffix}`;\n}\n","/**\n * 导航 / 面包屑工具函数\n *\n * 提供面包屑生成、菜单数据构建等通用导航功能。\n */\n\nimport type React from 'react';\n\n/**\n * 面包屑项\n */\nexport interface BreadcrumbItem {\n  /** 显示文本 */\n  title: string;\n  /** 链接路径 */\n  path?: string;\n  /** 图标 */\n  icon?: React.ReactNode;\n}\n\n/**\n * 路由配置项（简化版）\n */\nexport interface RouteItem {\n  /** 路径 */\n  path: string;\n  /** 名称 */\n  name?: string;\n  /** 图标 */\n  icon?: React.ReactNode;\n  /** 子路由 */\n  routes?: RouteItem[];\n  /** 是否隐藏 */\n  hideInMenu?: boolean;\n  /** 是否隐藏面包屑 */\n  hideInBreadcrumb?: boolean;\n  /** 额外数据 */\n  [key: string]: unknown;\n}\n\n/**\n * 菜单项\n */\nexport interface MenuItem {\n  /** 唯一标识 */\n  key: string;\n  /** 显示文本 */\n  label: string;\n  /** 链接路径 */\n  path?: string;\n  /** 图标 */\n  icon?: React.ReactNode;\n  /** 子菜单 */\n  children?: MenuItem[];\n  /** 是否禁用 */\n  disabled?: boolean;\n}\n\nfunction joinRoutePath(parentPath: string, routePath: string): string {\n  return routePath.startsWith('/')\n    ? routePath\n    : `${parentPath}/${routePath}`.replace(/\\/+/g, '/');\n}\n\nfunction isDynamicIdentifierSegment(segment: string): boolean {\n  return (\n    /^\\d+$/.test(segment) ||\n    /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(\n      segment,\n    )\n  );\n}\n\n/**\n * 将路径段转换为可读标题\n *\n * @param segment - 路径段\n * @returns 可读标题\n *\n * @example\n * ```ts\n * pathSegmentToTitle('user-management') // '用户管理' (需要路由配置) 或 'User Management'\n * pathSegmentToTitle('userList')        // 'User List'\n * ```\n */\nexport function pathSegmentToTitle(segment: string): string {\n  if (!segment) return '';\n  // 处理 kebab-case 和 camelCase\n  return segment\n    .replace(/[-_]/g, ' ')\n    .replace(/([a-z])([A-Z])/g, '$1 $2')\n    .replace(/\\b\\w/g, (c) => c.toUpperCase())\n    .trim();\n}\n\n/**\n * 根据当前路径和路由配置生成面包屑\n *\n * @param pathname - 当前路径\n * @param routes - 路由配置\n * @param homeTitle - 首页标题，默认 'Home'\n * @returns 面包屑项数组\n *\n * @example\n * ```ts\n * const breadcrumbs = generateBreadcrumbItems('/system/user/edit/1', routes);\n * // => [{ title: '首页', path: '/' }, { title: '系统管理', path: '/system' }, { title: '用户管理', path: '/system/user' }, { title: '编辑' }]\n * ```\n */\nexport function generateBreadcrumbItems(\n  pathname: string,\n  routes: RouteItem[],\n  homeTitle: string = 'Home',\n): BreadcrumbItem[] {\n  const items: BreadcrumbItem[] = [{ title: homeTitle, path: '/' }];\n\n  // 构建路径到路由名称的映射\n  const routeMap = new Map<string, RouteItem>();\n  function buildMap(routeList: RouteItem[], parentPath: string = '') {\n    for (const route of routeList) {\n      const fullPath = joinRoutePath(parentPath, route.path);\n      routeMap.set(fullPath, route);\n      if (route.routes) {\n        buildMap(route.routes, fullPath);\n      }\n    }\n  }\n  buildMap(routes);\n\n  // 按路径段逐级生成面包屑\n  const segments = pathname.split('/').filter(Boolean);\n  let currentPath = '';\n\n  for (const segment of segments) {\n    currentPath += `/${segment}`;\n    const route = routeMap.get(currentPath);\n\n    if (route && !route.hideInBreadcrumb) {\n      items.push({\n        title: route.name ?? pathSegmentToTitle(segment),\n        path: currentPath,\n        icon: route.icon,\n      });\n    } else if (!route) {\n      // 可能是动态参数（如 /edit/123），跳过或显示为标题\n      // 检测是否为 ID（纯数字或标准 UUID）\n      if (isDynamicIdentifierSegment(segment)) {\n        continue; // 跳过 ID 段\n      }\n      items.push({\n        title: pathSegmentToTitle(segment),\n        path: currentPath,\n      });\n    }\n  }\n\n  // 最后一项不需要链接\n  if (items.length > 1) {\n    const last = items[items.length - 1];\n    items[items.length - 1] = { ...last, path: undefined };\n  }\n\n  return items;\n}\n\n/**\n * 根据路由配置和权限生成菜单数据\n *\n * @param routes - 路由配置\n * @param permissions - 用户权限列表（可选，不传则不做权限过滤）\n * @param options - 配置选项\n * @returns 菜单数据\n *\n * @example\n * ```ts\n * const menuData = generateMenuData(routes, userPermissions);\n * ```\n */\nexport function generateMenuData(\n  routes: RouteItem[],\n  permissions?: string[],\n  options?: {\n    /** 权限字段名，默认 'access' */\n    accessKey?: string;\n    /** 父路径前缀 */\n    parentPath?: string;\n  },\n): MenuItem[] {\n  const { accessKey = 'access', parentPath = '' } = options ?? {};\n  const permissionSet = permissions ? new Set(permissions) : null;\n  const result: MenuItem[] = [];\n\n  for (const route of routes) {\n    // 隐藏菜单项跳过\n    if (route.hideInMenu) continue;\n\n    // 没有名称跳过\n    if (!route.name) continue;\n\n    // 权限检查\n    const access = route[accessKey] as string | undefined;\n    if (access && permissionSet && !permissionSet.has(access)) continue;\n\n    const fullPath = joinRoutePath(parentPath, route.path);\n\n    const menuItem: MenuItem = {\n      key: fullPath,\n      label: route.name,\n      path: fullPath,\n      icon: route.icon,\n    };\n\n    // 递归处理子路由\n    if (route.routes && route.routes.length > 0) {\n      const children = generateMenuData(route.routes, permissions, {\n        accessKey,\n        parentPath: fullPath,\n      });\n      if (children.length > 0) {\n        menuItem.children = children;\n      }\n    }\n\n    result.push(menuItem);\n  }\n\n  return result;\n}\n\n/**\n * 在菜单数据中查找匹配路径的菜单项\n *\n * @param menuItems - 菜单数据\n * @param path - 要查找的路径\n * @returns 匹配的菜单项，未找到返回 null\n */\nexport function findMenuItemByPath(\n  menuItems: MenuItem[],\n  path: string,\n): MenuItem | null {\n  for (const item of menuItems) {\n    if (item.path === path) return item;\n    if (item.children) {\n      const found = findMenuItemByPath(item.children, path);\n      if (found) return found;\n    }\n  }\n  return null;\n}\n","/**\n * Web Vitals 性能监控工具\n *\n * 提供 Core Web Vitals 性能指标的采集和报告功能。\n * 默认仅在开发模式下输出到控制台，也支持自定义上报。\n *\n */\n\n/**\n * 性能指标数据\n */\nexport interface PerformanceMetric {\n  /** 指标名称 */\n  name: string;\n  /** 指标值 */\n  value: number;\n  /** 评级 (good / needs-improvement / poor) */\n  rating?: string;\n  /** 导航类型 */\n  navigationType?: string;\n}\n\n/**\n * 性能监控配置\n */\nexport interface PerformanceMonitoringOptions {\n  /** 是否启用，默认 false（消费方根据自身环境判断后显式开启） */\n  enabled?: boolean;\n  /** 指标上报回调 */\n  onMetric?: (metric: PerformanceMetric) => void;\n  /** 是否在控制台输出，默认 true */\n  consoleOutput?: boolean;\n}\n\n/**\n * 初始化性能监控\n *\n * 采集 Core Web Vitals 指标：\n * - LCP (Largest Contentful Paint): 最大内容绘制时间\n * - INP (Interaction to Next Paint): 交互到下一次绘制延迟（2024 年 3 月起取代 FID）\n * - CLS (Cumulative Layout Shift): 累积布局偏移\n * - FCP (First Contentful Paint): 首次内容绘制\n * - TTFB (Time to First Byte): 首字节到达时间\n *\n * @param options - 配置选项\n *\n * @example\n * ```ts\n * // 开发模式：显式启用并输出到控制台\n * initPerformanceMonitoring({ enabled: import.meta.env.DEV });\n *\n * // 生产模式：上报到分析服务\n * initPerformanceMonitoring({\n *   enabled: true,\n *   consoleOutput: false,\n *   onMetric: (metric) => {\n *     analytics.track('web_vital', metric);\n *   },\n * });\n * ```\n */\n/**\n * 清理函数类型，调用后断开所有观察器\n */\nexport type PerformanceCleanup = () => void;\n\nexport function initPerformanceMonitoring(\n  options?: PerformanceMonitoringOptions,\n): PerformanceCleanup {\n  const { enabled = false, onMetric, consoleOutput = true } = options ?? {};\n\n  const noop = () => {};\n\n  if (!enabled) return noop;\n  if (\n    typeof window === 'undefined' ||\n    typeof PerformanceObserver === 'undefined'\n  )\n    return noop;\n\n  // 收集所有 observer 以便清理\n  const observers: PerformanceObserver[] = [];\n\n  const reportMetric = (metric: PerformanceMetric) => {\n    if (consoleOutput) {\n      const color = getMetricColor(metric.name, metric.value);\n      console.info(\n        `%c[WebVitals] ${metric.name}: ${metric.value.toFixed(2)}${metric.rating ? ` (${metric.rating})` : ''}`,\n        `color: ${color}; font-weight: bold;`,\n      );\n    }\n    onMetric?.(metric);\n  };\n\n  // LCP - Largest Contentful Paint\n  try {\n    const lcpObserver = new PerformanceObserver((entryList) => {\n      const entries = entryList.getEntries();\n      const lastEntry = entries[entries.length - 1];\n      if (lastEntry) {\n        reportMetric({\n          name: 'LCP',\n          value: lastEntry.startTime,\n          rating:\n            lastEntry.startTime <= 2500\n              ? 'good'\n              : lastEntry.startTime <= 4000\n                ? 'needs-improvement'\n                : 'poor',\n        });\n      }\n    });\n    lcpObserver.observe({ type: 'largest-contentful-paint', buffered: true });\n    observers.push(lcpObserver);\n  } catch {\n    // LCP observer not supported\n  }\n\n  // INP - Interaction to Next Paint (取代 FID，2024-03 起成为 Core Web Vital)\n  try {\n    let maxInp = 0;\n    const inpObserver = new PerformanceObserver((entryList) => {\n      for (const entry of entryList.getEntries()) {\n        const evt = entry as PerformanceEventTiming & {\n          interactionId?: number;\n        };\n        // 仅统计有 interactionId 的事件（排除非用户交互事件）\n        if (evt.interactionId && evt.interactionId > 0) {\n          const duration = evt.duration;\n          if (duration > maxInp) {\n            maxInp = duration;\n            reportMetric({\n              name: 'INP',\n              value: duration,\n              rating:\n                duration <= 200\n                  ? 'good'\n                  : duration <= 500\n                    ? 'needs-improvement'\n                    : 'poor',\n            });\n          }\n        }\n      }\n    });\n    inpObserver.observe({\n      type: 'event',\n      buffered: true,\n      durationThreshold: 16,\n    } as PerformanceObserverInit);\n    observers.push(inpObserver);\n  } catch {\n    // INP observer not supported\n  }\n\n  // CLS - Cumulative Layout Shift\n  try {\n    let clsValue = 0;\n    const clsObserver = new PerformanceObserver((entryList) => {\n      for (const entry of entryList.getEntries()) {\n        if (\n          !(entry as PerformanceEntry & { hadRecentInput?: boolean })\n            .hadRecentInput\n        ) {\n          clsValue +=\n            (entry as PerformanceEntry & { value?: number }).value ?? 0;\n        }\n      }\n      reportMetric({\n        name: 'CLS',\n        value: clsValue,\n        rating:\n          clsValue <= 0.1\n            ? 'good'\n            : clsValue <= 0.25\n              ? 'needs-improvement'\n              : 'poor',\n      });\n    });\n    clsObserver.observe({ type: 'layout-shift', buffered: true });\n    observers.push(clsObserver);\n  } catch {\n    // CLS observer not supported\n  }\n\n  // FCP - First Contentful Paint\n  try {\n    const fcpObserver = new PerformanceObserver((entryList) => {\n      const entries = entryList.getEntries();\n      const fcpEntry = entries.find((e) => e.name === 'first-contentful-paint');\n      if (fcpEntry) {\n        reportMetric({\n          name: 'FCP',\n          value: fcpEntry.startTime,\n          rating:\n            fcpEntry.startTime <= 1800\n              ? 'good'\n              : fcpEntry.startTime <= 3000\n                ? 'needs-improvement'\n                : 'poor',\n        });\n      }\n    });\n    fcpObserver.observe({ type: 'paint', buffered: true });\n    observers.push(fcpObserver);\n  } catch {\n    // FCP observer not supported\n  }\n\n  // TTFB - Time to First Byte\n  try {\n    const navEntries = performance.getEntriesByType('navigation');\n    if (navEntries.length > 0) {\n      const nav = navEntries[0] as PerformanceNavigationTiming;\n      const ttfb = nav.responseStart - nav.requestStart;\n      if (ttfb >= 0) {\n        reportMetric({\n          name: 'TTFB',\n          value: ttfb,\n          rating:\n            ttfb <= 800 ? 'good' : ttfb <= 1800 ? 'needs-improvement' : 'poor',\n        });\n      }\n    }\n  } catch {\n    // Navigation timing not supported\n  }\n\n  // 返回清理函数，断开所有 observer 防止内存泄漏\n  return () => {\n    for (const observer of observers) {\n      observer.disconnect();\n    }\n    observers.length = 0;\n  };\n}\n\n/**\n * 获取指标对应的颜色（控制台输出用）\n */\nfunction getMetricColor(name: string, value: number): string {\n  const thresholds: Record<string, [number, number]> = {\n    LCP: [2500, 4000],\n    INP: [200, 500],\n    CLS: [0.1, 0.25],\n    FCP: [1800, 3000],\n    TTFB: [800, 1800],\n  };\n\n  const [good, poor] = thresholds[name] ?? [Infinity, Infinity];\n  if (value <= good) return '#0cce6b'; // green\n  if (value <= poor) return '#ffa400'; // orange\n  return '#ff4e42'; // red\n}\n","/**\n * 权限检查工具函数\n */\n\n/** 超级管理员通配符 — 匹配所有权限 */\nconst SUPER_ADMIN_WILDCARD = '*';\n\n/**\n * 检查菜单权限\n *\n * 编码使用冒号分隔层级（与 SDK PermissionConfigCompiler 一致）:\n * - `*` 匹配所有权限\n * - `admin:*` 匹配 admin 下的所有子权限\n * - `admin:topic` 精确匹配\n *\n * @param userMenus - 用户拥有的菜单权限列表\n * @param code - 要检查的权限 code\n * @returns 是否有权限\n *\n * @example\n * ```ts\n * const menus = ['admin:system:user', 'admin:system:role', 'dashboard'];\n * checkMenuPermission(menus, 'admin:system:user') // true\n * checkMenuPermission(menus, 'admin:*') // true (有 admin 下的子权限)\n * checkMenuPermission(menus, 'settings') // false\n * ```\n */\nexport function checkMenuPermission(\n  userMenus: string[] | undefined | null,\n  code: string,\n): boolean {\n  if (!userMenus?.length || !code) return false;\n\n  // 精确匹配\n  if (userMenus.includes(code)) return true;\n\n  // 通配符匹配: 检查 code 是否为 'xxx:*' 模式\n  if (code.endsWith(':*')) {\n    const prefix = code.slice(0, -2); // 去掉 ':*'\n    return userMenus.some(\n      (menu) => menu === prefix || menu.startsWith(`${prefix}:`),\n    );\n  }\n\n  // 检查用户菜单中是否有通配符覆盖当前 code\n  return userMenus.some((menu) => {\n    if (menu === SUPER_ADMIN_WILDCARD) return true;\n    if (menu.endsWith(':*')) {\n      const prefix = menu.slice(0, -2);\n      return code === prefix || code.startsWith(`${prefix}:`);\n    }\n    return false;\n  });\n}\n\n/**\n * 检查按钮权限\n *\n * @param userButtons - 用户拥有的按钮权限列表\n * @param code - 要检查的按钮权限 code\n * @returns 是否有权限\n *\n * @example\n * ```ts\n * const buttons = ['user:create', 'user:edit', 'role:view'];\n * checkButtonPermission(buttons, 'user:create') // true\n * checkButtonPermission(buttons, 'user:delete') // false\n * ```\n */\nexport function checkButtonPermission(\n  userButtons: string[] | undefined | null,\n  code: string,\n): boolean {\n  if (!userButtons?.length || !code) return false;\n  if (userButtons.includes(SUPER_ADMIN_WILDCARD)) return true;\n  return userButtons.includes(code);\n}\n\n/**\n * 批量检查多个权限 (全部满足)\n *\n * @param userPermissions - 用户权限列表\n * @param codes - 要检查的权限列表\n * @returns 是否全部有权限\n */\nexport function checkAllPermissions(\n  userPermissions: string[] | undefined | null,\n  codes: string[],\n): boolean {\n  if (!codes.length) return true;\n  return codes.every((code) => checkMenuPermission(userPermissions, code));\n}\n\n/**\n * 批量检查多个权限 (任一满足)\n *\n * @param userPermissions - 用户权限列表\n * @param codes - 要检查的权限列表\n * @returns 是否有任一权限\n */\nexport function checkAnyPermission(\n  userPermissions: string[] | undefined | null,\n  codes: string[],\n): boolean {\n  if (!codes.length) return true;\n  return codes.some((code) => checkMenuPermission(userPermissions, code));\n}\n","/**\n * 中国行政区划数据工具\n *\n * 将行政区划数据转换为 Ant Design Cascader 组件所需的格式。\n * 使用 china-division 包 (optional peer dependency) 或自定义数据源。\n *\n * **注意**: 该模块专为中国行政区划设计 (China-specific)。\n * 数据源通过 `setRegionDataSource()` 注入，不直接依赖具体数据包。\n */\n\n// ===== 类型定义 =====\n\n/**\n * 级联选项\n */\nexport interface CascaderOption {\n  /** 显示文本 */\n  label: string;\n  /** 值 */\n  value: string;\n  /** 子选项 */\n  children?: CascaderOption[];\n}\n\n/**\n * 省/自治区/直辖市\n */\ninterface ProvinceItem {\n  code: string;\n  name: string;\n}\n\n/**\n * 城市\n */\ninterface CityItem {\n  code: string;\n  name: string;\n  provinceCode: string;\n}\n\n/**\n * 区/县\n */\ninterface AreaItem {\n  code: string;\n  name: string;\n  cityCode: string;\n  provinceCode: string;\n}\n\n/**\n * 原始地区数据\n */\nexport interface RegionDataSource {\n  provinces: ProvinceItem[];\n  cities: CityItem[];\n  areas: AreaItem[];\n}\n\n/**\n * 地区数据配置\n */\nexport interface RegionConfig {\n  /**\n   * Cascader option 的 value 使用哪个字段\n   * - 'code': 使用行政区划编码 (默认, 如 '110000')\n   * - 'name': 使用名称 (如 '北京市')\n   */\n  valueField?: 'code' | 'name';\n}\n\n// ===== 缓存 =====\n\nlet cachedRegionData: CascaderOption[] | null = null;\nlet cachedCityData: CascaderOption[] | null = null;\nlet cachedDataSource: RegionDataSource | null = null;\nlet cachedValueField: 'code' | 'name' = 'code';\n/** code -> name 的 Map 缓存，用于 O(1) 名称查找 */\nlet cachedNameMap: Map<string, string> | null = null;\n\n/**\n * 重置缓存 (测试用)\n */\nexport function resetRegionCache(): void {\n  cachedRegionData = null;\n  cachedCityData = null;\n  cachedDataSource = null;\n  cachedNameMap = null;\n}\n\n// ===== 核心函数 =====\n\n/**\n * 设置数据源\n *\n * 如果使用 china-division 包, 需要在应用初始化时调用此方法设置数据源。\n *\n * @example\n * ```ts\n * import provinces from 'china-division/dist/provinces.json';\n * import cities from 'china-division/dist/cities.json';\n * import areas from 'china-division/dist/areas.json';\n *\n * setRegionDataSource({ provinces, cities, areas });\n * ```\n */\nexport function setRegionDataSource(\n  data: RegionDataSource,\n  config?: RegionConfig,\n): void {\n  cachedDataSource = data;\n  cachedValueField = config?.valueField ?? 'code';\n  // 清除缓存，下次获取时重新构建\n  cachedRegionData = null;\n  cachedCityData = null;\n  cachedNameMap = null;\n}\n\n/**\n * 获取省市区三级级联数据\n *\n * @returns Ant Design Cascader 格式的省市区数据\n *\n * @example\n * ```tsx\n * import { getRegionData } from '@aspect/shared/utils';\n *\n * <Cascader options={getRegionData()} placeholder=\"请选择地区\" />\n * ```\n */\nexport function getRegionData(): CascaderOption[] {\n  if (cachedRegionData) return cachedRegionData;\n  if (!cachedDataSource) {\n    return [];\n  }\n\n  const { provinces, cities, areas } = cachedDataSource;\n\n  const vf = cachedValueField;\n\n  // 构建区 -> 城市映射\n  const areasByCity = new Map<string, CascaderOption[]>();\n  for (const area of areas) {\n    const list = areasByCity.get(area.cityCode) ?? [];\n    list.push({ label: area.name, value: area[vf] });\n    areasByCity.set(area.cityCode, list);\n  }\n\n  // 构建城市 -> 省映射\n  const citiesByProvince = new Map<string, CascaderOption[]>();\n  for (const city of cities) {\n    const list = citiesByProvince.get(city.provinceCode) ?? [];\n    list.push({\n      label: city.name,\n      value: city[vf],\n      children: areasByCity.get(city.code),\n    });\n    citiesByProvince.set(city.provinceCode, list);\n  }\n\n  // 构建省级\n  cachedRegionData = provinces.map((province) => ({\n    label: province.name,\n    value: province[vf],\n    children: citiesByProvince.get(province.code),\n  }));\n\n  return cachedRegionData;\n}\n\n/**\n * 获取省市二级级联数据 (不含区/县)\n *\n * @returns Ant Design Cascader 格式的省市数据\n *\n * @example\n * ```tsx\n * <Cascader options={getCityData()} placeholder=\"请选择城市\" />\n * ```\n */\nexport function getCityData(): CascaderOption[] {\n  if (cachedCityData) return cachedCityData;\n  if (!cachedDataSource) {\n    return [];\n  }\n\n  const { provinces, cities } = cachedDataSource;\n\n  const vf = cachedValueField;\n\n  const citiesByProvince = new Map<string, CascaderOption[]>();\n  for (const city of cities) {\n    const list = citiesByProvince.get(city.provinceCode) ?? [];\n    list.push({ label: city.name, value: city[vf] });\n    citiesByProvince.set(city.provinceCode, list);\n  }\n\n  cachedCityData = provinces.map((province) => ({\n    label: province.name,\n    value: province[vf],\n    children: citiesByProvince.get(province.code),\n  }));\n\n  return cachedCityData;\n}\n\n/**\n * 根据地区编码获取名称\n *\n * @param code - 行政区划编码\n * @returns 地区名称, 未找到返回 code 本身\n *\n * @example\n * ```ts\n * getRegionName('110000'); // => '北京市'\n * getRegionName('110100'); // => '北京市' (市辖区)\n * getRegionName('110101'); // => '东城区'\n * ```\n */\nexport function getRegionName(code: string): string {\n  if (!cachedDataSource) return code;\n\n  // 惰性构建 name 查找 Map (O(1) 查找，替代三次线性搜索)\n  if (!cachedNameMap) {\n    cachedNameMap = new Map();\n    for (const p of cachedDataSource.provinces)\n      cachedNameMap.set(p.code, p.name);\n    for (const c of cachedDataSource.cities) cachedNameMap.set(c.code, c.name);\n    for (const a of cachedDataSource.areas) cachedNameMap.set(a.code, a.name);\n  }\n\n  return cachedNameMap.get(code) ?? code;\n}\n\n/**\n * 根据编码数组获取完整地址文本\n *\n * @param codes - [省编码, 市编码?, 区编码?]\n * @param separator - 分隔符, 默认 ' '\n * @returns 完整地址文本\n *\n * @example\n * ```ts\n * getRegionFullText(['110000', '110100', '110101']);\n * // => '北京市 北京市 东城区'\n *\n * getRegionFullText(['110000', '110100', '110101'], '/');\n * // => '北京市/北京市/东城区'\n * ```\n */\nexport function getRegionFullText(codes: string[], separator = ' '): string {\n  return codes.filter(Boolean).map(getRegionName).join(separator);\n}\n","/**\n * HTML 净化工具函数\n *\n * dompurify 作为可选 peerDependency，使用参数注入模式避免硬依赖。\n */\n\n/** DOMPurify sanitize 函数签名 */\ntype SanitizeFn = (html: string, options?: Record<string, unknown>) => string;\n\n/** 缓存 sanitize 函数引用 */\nlet cachedSanitize: SanitizeFn | null = null;\n\n/**\n * 初始化 HTML 净化器\n *\n * 在应用启动时调用一次，传入 DOMPurify 实例。\n *\n * @param purify - DOMPurify 实例 (import DOMPurify from 'dompurify')\n *\n * @example\n * ```ts\n * // 在 app.tsx 中初始化\n * import DOMPurify from 'dompurify';\n * import { initSanitizer } from '@aspect/shared/utils';\n * initSanitizer(DOMPurify);\n * ```\n */\nexport function initSanitizer(purify: { sanitize: SanitizeFn }): void {\n  cachedSanitize = purify.sanitize.bind(purify);\n}\n\n/**\n * 净化 HTML 字符串，防止 XSS 攻击\n *\n * 需先通过 `initSanitizer` 初始化 DOMPurify。\n *\n * @param html - 待净化的 HTML 字符串\n * @param options - DOMPurify 选项\n * @returns 净化后的安全 HTML 字符串\n *\n * @example\n * ```ts\n * const safeHtml = sanitizeHtml('<script>alert(\"xss\")</script><p>Hello</p>');\n * // '<p>Hello</p>'\n * ```\n */\nexport function sanitizeHtml(\n  html: string,\n  options?: Record<string, unknown>,\n): string {\n  if (!html) return '';\n\n  if (cachedSanitize) {\n    return cachedSanitize(html, options);\n  }\n\n  throw new Error(\n    '[sanitizeHtml] DOMPurify is not initialized. Call initSanitizer(DOMPurify) at app startup.',\n  );\n}\n\n/**\n * 移除所有 HTML 标签，只保留纯文本\n *\n * @param html - HTML 字符串\n * @returns 纯文本\n */\nexport function stripHtmlTags(html: string): string {\n  if (!html) return '';\n  return html.replace(/<[^>]*>/g, '').trim();\n}\n","/**\n * localStorage/sessionStorage 安全封装 + TTL + 内存缓存\n */\n\n/** 存储类型 */\nexport type StorageType = 'local' | 'session';\n\n/** 存储选项 */\nexport interface StorageOptions {\n  /** 存储类型，默认 'local' */\n  storageType?: StorageType;\n  /** 过期时间 (毫秒)，不设置则永不过期 */\n  ttl?: number;\n}\n\n/** 存储条目元数据 */\ninterface StorageEntry<T> {\n  value: T;\n  /** 过期时间戳 */\n  expiresAt?: number;\n  /** 写入时间戳 */\n  createdAt: number;\n}\n\n/**\n * 获取存储实例\n */\nfunction getStorage(type: StorageType = 'local'): Storage | null {\n  try {\n    return type === 'session' ? sessionStorage : localStorage;\n  } catch {\n    // 无痕模式或 SSR 环境下 Storage 不可用\n    return null;\n  }\n}\n\n/**\n * 安全读取存储数据\n *\n * @param key - 存储 key\n * @param storageType - 存储类型，默认 'local'\n * @returns 解析后的数据或 null\n *\n * @example\n * ```ts\n * const user = safeGetStorage<User>('currentUser');\n * const token = safeGetStorage<string>('token');\n * ```\n */\nexport function safeGetStorage<T = unknown>(\n  key: string,\n  storageType: StorageType = 'local',\n): T | null {\n  const storage = getStorage(storageType);\n  if (!storage) return null;\n\n  try {\n    const raw = storage.getItem(key);\n    if (raw === null) return null;\n\n    // 尝试解析为 JSON\n    const parsed = JSON.parse(raw);\n\n    // 检查是否为 StorageEntry 包装格式（双重验证 value + createdAt，避免误匹配普通对象）\n    if (\n      parsed &&\n      typeof parsed === 'object' &&\n      'value' in parsed &&\n      'createdAt' in parsed\n    ) {\n      const entry = parsed as StorageEntry<T>;\n      // 检查 TTL 过期\n      if (entry.expiresAt && Date.now() > entry.expiresAt) {\n        storage.removeItem(key);\n        return null;\n      }\n      return entry.value;\n    }\n\n    // 支持非包装格式 (直接存储的 JSON 值)\n    return parsed as T;\n  } catch {\n    // JSON 解析失败: 原始值不是有效 JSON，无法安全转换为 T\n    return null;\n  }\n}\n\n/**\n * 安全写入存储数据\n *\n * @param key - 存储 key\n * @param value - 要存储的数据\n * @param options - 存储选项 (TTL 等)\n * @returns 是否写入成功\n *\n * @example\n * ```ts\n * safeSetStorage('user', { id: 1, name: 'test' });\n * safeSetStorage('token', 'abc123', { ttl: 7 * 24 * 60 * 60 * 1000 }); // 7天过期\n * safeSetStorage('cache', data, { storageType: 'session' });\n * ```\n */\nexport function safeSetStorage(\n  key: string,\n  value: unknown,\n  options?: StorageOptions,\n): boolean {\n  const storage = getStorage(options?.storageType);\n  if (!storage) return false;\n\n  try {\n    const entry: StorageEntry<unknown> = {\n      value,\n      createdAt: Date.now(),\n    };\n\n    if (options?.ttl && options.ttl > 0) {\n      entry.expiresAt = Date.now() + options.ttl;\n    }\n\n    storage.setItem(key, JSON.stringify(entry));\n    return true;\n  } catch {\n    // 存储空间已满等错误，静默失败\n    return false;\n  }\n}\n\n/**\n * 安全删除存储数据\n *\n * @param key - 存储 key\n * @param storageType - 存储类型，默认 'local'\n */\nexport function safeRemoveStorage(\n  key: string,\n  storageType: StorageType = 'local',\n): void {\n  const storage = getStorage(storageType);\n  if (!storage) return;\n\n  try {\n    storage.removeItem(key);\n  } catch {\n    // Storage 操作偶发失败（无痕模式等），静默处理\n  }\n}\n\n/**\n * 清空指定类型的存储\n *\n * @param storageType - 存储类型，默认 'local'\n */\nexport function clearStorage(storageType: StorageType = 'local'): void {\n  const storage = getStorage(storageType);\n  if (!storage) return;\n\n  try {\n    storage.clear();\n  } catch {\n    // Storage 操作偶发失败（无痕模式等），静默处理\n  }\n}\n\n/**\n * 检查存储项是否已过期\n *\n * @param key - 存储 key\n * @param storageType - 存储类型，默认 'local'\n * @returns 是否已过期 (不存在也返回 true)\n */\nexport function isStorageExpired(\n  key: string,\n  storageType: StorageType = 'local',\n): boolean {\n  const storage = getStorage(storageType);\n  if (!storage) return true;\n\n  try {\n    const raw = storage.getItem(key);\n    if (raw === null) return true;\n\n    const parsed = JSON.parse(raw) as StorageEntry<unknown>;\n\n    // 检查是否受管: 需要有 value 且 createdAt\n    if (\n      parsed &&\n      typeof parsed === 'object' &&\n      'value' in parsed &&\n      'createdAt' in parsed\n    ) {\n      if ('expiresAt' in parsed && parsed.expiresAt != null) {\n        return Date.now() > parsed.expiresAt;\n      }\n      return false; // 受管但无过期设置则不过期\n    }\n    return false; // 非受管格式，不过期\n  } catch {\n    // JSON 解析失败说明非受管格式，不过期\n    return false;\n  }\n}\n\n/**\n * 清理所有已过期的存储项\n *\n * @param storageType - 存储类型，默认 'local'\n * @returns 清理的条数\n */\nexport function cleanExpiredStorage(\n  storageType: StorageType = 'local',\n): number {\n  const storage = getStorage(storageType);\n  if (!storage) return 0;\n\n  let cleaned = 0;\n  try {\n    const keysToRemove: string[] = [];\n    for (let i = 0; i < storage.length; i++) {\n      const key = storage.key(i);\n      if (key && isStorageExpired(key, storageType)) {\n        keysToRemove.push(key);\n      }\n    }\n    for (const key of keysToRemove) {\n      storage.removeItem(key);\n      cleaned++;\n    }\n  } catch {\n    // Storage 遍历或删除偶发失败，返回已清理数量\n  }\n  return cleaned;\n}\n\n/**\n * 获取存储空间大小 (估算，单位字节)\n *\n * @param storageType - 存储类型，默认 'local'\n * @returns 估算大小 (字节)\n */\nexport function getStorageSize(storageType: StorageType = 'local'): number {\n  const storage = getStorage(storageType);\n  if (!storage) return 0;\n\n  let size = 0;\n  try {\n    for (let i = 0; i < storage.length; i++) {\n      const key = storage.key(i);\n      if (key) {\n        const value = storage.getItem(key);\n        size += key.length + (value?.length ?? 0);\n      }\n    }\n  } catch {\n    // Storage 遍历偶发失败，返回已累积的大小\n  }\n  // UTF-16 编码，每个字符 2 字节\n  return size * 2;\n}\n\n// ==================== 内存缓存 ====================\n\n/**\n * 内存缓存配置\n */\nexport interface MemoryCacheOptions {\n  /** 最大缓存条数，默认 100 */\n  maxSize?: number;\n  /** 默认过期时间 (毫秒)，默认不过期 */\n  defaultTtl?: number;\n}\n\n/**\n * 内存缓存实例\n */\nexport interface MemoryCache {\n  /** 获取缓存值 */\n  get<T = unknown>(key: string): T | undefined;\n  /** 设置缓存值 */\n  set(key: string, value: unknown, ttl?: number): void;\n  /** 删除缓存值 */\n  delete(key: string): boolean;\n  /** 检查 key 是否存在 (且未过期) */\n  has(key: string): boolean;\n  /** 清空所有缓存 */\n  clear(): void;\n  /** 获取当前缓存大小 */\n  readonly size: number;\n}\n\n/**\n * 创建内存缓存实例\n *\n * @param options - 缓存配置\n * @returns 缓存实例\n *\n * @example\n * ```ts\n * const cache = createMemoryCache({ maxSize: 50, defaultTtl: 60000 });\n * cache.set('key', { data: 'value' });\n * const value = cache.get<{ data: string }>('key');\n * ```\n */\nexport function createMemoryCache(options?: MemoryCacheOptions): MemoryCache {\n  const maxSize = options?.maxSize ?? 100;\n  const defaultTtl = options?.defaultTtl;\n  const store = new Map<string, { value: unknown; expiresAt?: number }>();\n\n  function evict() {\n    while (store.size > maxSize) {\n      const firstKey = store.keys().next().value;\n      if (firstKey === undefined) break;\n      store.delete(firstKey);\n    }\n  }\n\n  return {\n    /**\n     * 获取缓存值\n     */\n    get<T = unknown>(key: string): T | undefined {\n      const entry = store.get(key);\n      if (!entry) return undefined;\n      if (entry.expiresAt && Date.now() > entry.expiresAt) {\n        store.delete(key);\n        return undefined;\n      }\n      return entry.value as T;\n    },\n\n    /**\n     * 设置缓存值\n     */\n    set(key: string, value: unknown, ttl?: number): void {\n      const effectiveTtl = ttl ?? defaultTtl;\n      const expiresAt =\n        effectiveTtl != null && effectiveTtl > 0\n          ? Date.now() + effectiveTtl\n          : undefined;\n      store.set(key, { value, expiresAt });\n      evict();\n    },\n\n    /**\n     * 删除缓存值\n     */\n    delete(key: string): boolean {\n      return store.delete(key);\n    },\n\n    /**\n     * 检查 key 是否存在 (且未过期)\n     */\n    has(key: string): boolean {\n      const entry = store.get(key);\n      if (!entry) return false;\n      if (entry.expiresAt && Date.now() > entry.expiresAt) {\n        store.delete(key);\n        return false;\n      }\n      return true;\n    },\n\n    /**\n     * 清空所有缓存\n     */\n    clear(): void {\n      store.clear();\n    },\n\n    /**\n     * 获取当前缓存大小\n     */\n    get size(): number {\n      return store.size;\n    },\n  };\n}\n","/**\n * 主题管理工具\n *\n * 提供主题管理的核心逻辑：主题切换、持久化、DOM 更新、系统偏好检测等。\n *\n */\n\n/**\n * 主题定义\n */\nexport interface ThemeDefinition {\n  /** 主题 ID */\n  id: string;\n  /** 主题名称 */\n  name: string;\n  /** 是否为暗色主题 */\n  isDark: boolean;\n  /** 主色调 */\n  primaryColor?: string;\n  /** 自定义 CSS 变量 */\n  cssVars?: Record<string, string>;\n  /** antd 主题 token */\n  token?: Record<string, unknown>;\n}\n\n/**\n * 主题管理器配置\n */\nexport interface ThemeManagerOptions {\n  /** 可用的主题列表 */\n  themes: ThemeDefinition[];\n  /** 默认主题 ID */\n  defaultThemeId?: string;\n  /** 存储 key，默认 'app-theme' */\n  storageKey?: string;\n  /** 是否跟随系统暗色偏好，默认 false */\n  followSystem?: boolean;\n}\n\n/**\n * 主题管理器\n */\nexport interface ThemeManager {\n  /** 获取当前主题 */\n  getCurrentTheme: () => ThemeDefinition;\n  /** 获取当前主题 ID */\n  getCurrentThemeId: () => string;\n  /** 切换主题 */\n  setTheme: (themeId: string) => void;\n  /** 获取所有可用主题 */\n  getThemes: () => ThemeDefinition[];\n  /** 判断当前是否为暗色主题 */\n  isDark: () => boolean;\n  /** 切换明暗模式 */\n  toggleDarkMode: () => void;\n}\n\n/**\n * 创建主题管理器\n *\n * @param options - 主题管理器配置\n * @returns 主题管理器实例\n *\n * @example\n * ```ts\n * const themeManager = createThemeManager({\n *   themes: [\n *     { id: 'light', name: '明亮', isDark: false, primaryColor: '#1677ff' },\n *     { id: 'dark', name: '暗色', isDark: true, primaryColor: '#1668dc' },\n *   ],\n *   defaultThemeId: 'light',\n *   followSystem: true,\n * });\n *\n * // 切换主题\n * themeManager.setTheme('dark');\n * // 获取当前主题\n * const theme = themeManager.getCurrentTheme();\n * ```\n */\nexport function createThemeManager(options: ThemeManagerOptions): ThemeManager {\n  const {\n    themes,\n    defaultThemeId,\n    storageKey = 'app-theme',\n    followSystem = false,\n  } = options;\n\n  function getInitialThemeId(): string {\n    // 1. 从存储中读取\n    try {\n      const saved = localStorage.getItem(storageKey);\n      if (saved && themes.some((t) => t.id === saved)) {\n        return saved;\n      }\n    } catch {\n      // localStorage 不可用\n    }\n\n    // 2. 跟随系统偏好\n    if (followSystem && getSystemPrefersDark()) {\n      const darkTheme = themes.find((t) => t.isDark);\n      if (darkTheme) return darkTheme.id;\n    }\n\n    // 3. 使用默认值\n    return defaultThemeId ?? themes[0]?.id ?? 'light';\n  }\n\n  let currentThemeId = getInitialThemeId();\n\n  function findTheme(id: string): ThemeDefinition {\n    return themes.find((t) => t.id === id) ?? themes[0];\n  }\n\n  function persistThemeId(id: string) {\n    try {\n      localStorage.setItem(storageKey, id);\n    } catch {\n      // localStorage 不可用\n    }\n  }\n\n  return {\n    getCurrentTheme: () => findTheme(currentThemeId),\n    getCurrentThemeId: () => currentThemeId,\n    setTheme: (themeId: string) => {\n      if (!themes.some((t) => t.id === themeId)) return;\n      currentThemeId = themeId;\n      persistThemeId(themeId);\n      const theme = findTheme(themeId);\n      applyThemeToDom(theme);\n    },\n    getThemes: () => [...themes],\n    isDark: () => findTheme(currentThemeId).isDark,\n    toggleDarkMode: () => {\n      const current = findTheme(currentThemeId);\n      const target = themes.find((t) => t.isDark !== current.isDark);\n      if (target) {\n        currentThemeId = target.id;\n        persistThemeId(target.id);\n        applyThemeToDom(target);\n      }\n    },\n  };\n}\n\n/**\n * 将主题应用到 DOM\n *\n * - 设置 `<html>` 的 `data-theme` 属性\n * - 设置 `<html>` 的 `class` （dark/light）\n * - 设置 CSS 变量\n *\n * @param theme - 主题定义\n */\nexport function applyThemeToDom(theme: ThemeDefinition): void {\n  if (typeof document === 'undefined') return;\n\n  const root = document.documentElement;\n\n  // 设置 data-theme 属性\n  root.setAttribute('data-theme', theme.id);\n\n  // 设置 dark/light class\n  if (theme.isDark) {\n    root.classList.add('dark');\n    root.classList.remove('light');\n  } else {\n    root.classList.add('light');\n    root.classList.remove('dark');\n  }\n\n  // 设置 CSS 变量\n  if (theme.cssVars) {\n    for (const [key, value] of Object.entries(theme.cssVars)) {\n      const varName = key.startsWith('--') ? key : `--${key}`;\n      root.style.setProperty(varName, value);\n    }\n  }\n\n  // 设置 color-scheme\n  root.style.colorScheme = theme.isDark ? 'dark' : 'light';\n}\n\n/**\n * 检测系统是否偏好暗色模式\n *\n * @returns 系统是否偏好暗色模式\n */\nexport function getSystemPrefersDark(): boolean {\n  if (typeof window === 'undefined') return false;\n  return window.matchMedia?.('(prefers-color-scheme: dark)')?.matches ?? false;\n}\n\n/**\n * 判断主题 ID 是否对应暗色主题\n *\n * @param themeId - 主题 ID\n * @param themes - 主题列表\n * @returns 是否为暗色主题\n */\nexport function isDarkTheme(\n  themeId: string,\n  themes: ThemeDefinition[],\n): boolean {\n  return themes.find((t) => t.id === themeId)?.isDark ?? false;\n}\n\n/**\n * 监听系统暗色模式变化\n *\n * @param callback - 变化回调\n * @returns 取消监听的函数\n *\n * @example\n * ```ts\n * const unwatch = watchSystemDarkMode((isDark) => {\n *   themeManager.setTheme(isDark ? 'dark' : 'light');\n * });\n *\n * // 清理\n * unwatch();\n * ```\n */\nexport function watchSystemDarkMode(\n  callback: (isDark: boolean) => void,\n): () => void {\n  if (typeof window === 'undefined') return () => {};\n\n  const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');\n  const handler = (e: MediaQueryListEvent) => callback(e.matches);\n  mediaQuery.addEventListener('change', handler);\n\n  return () => mediaQuery.removeEventListener('change', handler);\n}\n","/**\n * 通用树操作工具函数\n *\n * 提供对树形结构数据的常用操作：扁平化、查找、过滤、映射、构建等。\n * 适用于菜单树、分类树、组织树、权限树等各种树形场景。\n *\n */\n\n/** 默认子节点字段名 */\nconst DEFAULT_CHILDREN_KEY = 'children';\n\n/**\n * 将树形结构扁平化为一维数组\n *\n * @param tree - 树节点数组\n * @param childrenKey - 子节点字段名，默认 'children'\n * @returns 扁平化后的节点数组（不含 children 属性）\n *\n * @example\n * ```ts\n * const tree = [\n *   { id: 1, name: 'A', children: [{ id: 2, name: 'B' }] },\n *   { id: 3, name: 'C' },\n * ];\n * flattenTree(tree);\n * // => [{ id: 1, name: 'A' }, { id: 2, name: 'B' }, { id: 3, name: 'C' }]\n * ```\n */\nexport function flattenTree<T extends Record<string, unknown>>(\n  tree: T[],\n  childrenKey: string = DEFAULT_CHILDREN_KEY,\n): T[] {\n  const result: T[] = [];\n\n  function walk(nodes: T[]) {\n    for (const node of nodes) {\n      const { [childrenKey]: children, ...rest } = node;\n      result.push(rest as T);\n      if (Array.isArray(children) && children.length > 0) {\n        walk(children as T[]);\n      }\n    }\n  }\n\n  walk(tree);\n  return result;\n}\n\n/**\n * 在树中查找满足条件的第一个节点\n *\n * @param tree - 树节点数组\n * @param predicate - 匹配函数\n * @param childrenKey - 子节点字段名，默认 'children'\n * @returns 匹配的节点，未找到返回 null\n *\n * @example\n * ```ts\n * const node = findNodeInTree(tree, (n) => n.id === 5);\n * ```\n */\nexport function findNodeInTree<T extends Record<string, unknown>>(\n  tree: T[],\n  predicate: (node: T) => boolean,\n  childrenKey: string = DEFAULT_CHILDREN_KEY,\n): T | null {\n  for (const node of tree) {\n    if (predicate(node)) return node;\n    const children = node[childrenKey];\n    if (Array.isArray(children) && children.length > 0) {\n      const found = findNodeInTree(children as T[], predicate, childrenKey);\n      if (found) return found;\n    }\n  }\n  return null;\n}\n\n/**\n * 在树中查找目标节点的父节点\n *\n * @param tree - 树节点数组\n * @param predicate - 目标节点匹配函数\n * @param childrenKey - 子节点字段名，默认 'children'\n * @returns 父节点，未找到或目标在根层级时返回 null\n *\n * @example\n * ```ts\n * const parent = findParentNode(tree, (n) => n.id === 5);\n * ```\n */\nexport function findParentNode<T extends Record<string, unknown>>(\n  tree: T[],\n  predicate: (node: T) => boolean,\n  childrenKey: string = DEFAULT_CHILDREN_KEY,\n): T | null {\n  for (const node of tree) {\n    const children = node[childrenKey];\n    if (Array.isArray(children)) {\n      for (const child of children as T[]) {\n        if (predicate(child)) return node;\n      }\n      const found = findParentNode(children as T[], predicate, childrenKey);\n      if (found) return found;\n    }\n  }\n  return null;\n}\n\n/**\n * 过滤树节点，保留匹配节点及其祖先路径\n *\n * 如果子节点匹配，其所有祖先节点也会被保留（即使祖先节点本身不匹配）。\n *\n * @param tree - 树节点数组\n * @param predicate - 匹配函数\n * @param childrenKey - 子节点字段名，默认 'children'\n * @returns 过滤后的新树\n *\n * @example\n * ```ts\n * const filtered = filterTree(menuTree, (n) => n.visible !== false);\n * ```\n */\nexport function filterTree<T extends Record<string, unknown>>(\n  tree: T[],\n  predicate: (node: T) => boolean,\n  childrenKey: string = DEFAULT_CHILDREN_KEY,\n): T[] {\n  const result: T[] = [];\n\n  for (const node of tree) {\n    const children = node[childrenKey];\n    const filteredChildren = Array.isArray(children)\n      ? filterTree(children as T[], predicate, childrenKey)\n      : [];\n\n    // 保留：节点本身匹配 或 有匹配的子节点\n    if (predicate(node) || filteredChildren.length > 0) {\n      result.push({\n        ...node,\n        [childrenKey]:\n          filteredChildren.length > 0 ? filteredChildren : undefined,\n      });\n    }\n  }\n\n  return result;\n}\n\n/**\n * 从扁平列表构建树形结构\n *\n * @param list - 扁平节点列表\n * @param options - 配置选项\n * @returns 树形结构数组\n *\n * @example\n * ```ts\n * const list = [\n *   { id: 1, parentId: 0, name: 'Root' },\n *   { id: 2, parentId: 1, name: 'Child 1' },\n *   { id: 3, parentId: 1, name: 'Child 2' },\n * ];\n * const tree = buildTreeFromFlat(list, { rootParentId: 0 });\n * ```\n */\nexport function buildTreeFromFlat<T extends Record<string, unknown>>(\n  list: T[],\n  options?: {\n    /** ID 字段名，默认 'id' */\n    idKey?: string;\n    /** 父 ID 字段名，默认 'parentId' */\n    parentIdKey?: string;\n    /** 子节点字段名，默认 'children' */\n    childrenKey?: string;\n    /** 根节点的 parentId 值，默认 null/undefined/0/'' */\n    rootParentId?: string | number | null;\n  },\n): T[] {\n  const {\n    idKey = 'id',\n    parentIdKey = 'parentId',\n    childrenKey = DEFAULT_CHILDREN_KEY,\n    rootParentId,\n  } = options ?? {};\n\n  const nodeMap = new Map<string | number, T & { [key: string]: unknown }>();\n  const roots: T[] = [];\n\n  // 第一遍：建立 id -> node 映射\n  for (const item of list) {\n    const id = item[idKey] as string | number;\n    nodeMap.set(id, { ...item, [childrenKey]: [] });\n  }\n\n  // 第二遍：挂载子节点\n  for (const item of list) {\n    const id = item[idKey] as string | number;\n    const parentId = item[parentIdKey] as string | number | null | undefined;\n    const node = nodeMap.get(id);\n    if (!node) {\n      continue;\n    }\n\n    const isRoot =\n      rootParentId !== undefined\n        ? parentId === rootParentId\n        : parentId === null ||\n          parentId === undefined ||\n          parentId === 0 ||\n          parentId === '';\n\n    if (isRoot) {\n      roots.push(node as T);\n    } else if (parentId !== null && parentId !== undefined) {\n      const parent = nodeMap.get(parentId);\n      if (parent) {\n        (parent[childrenKey] as T[]).push(node as T);\n      } else {\n        // 父节点不存在时当作根节点\n        roots.push(node as T);\n      }\n    }\n  }\n\n  // 清理空 children 数组\n  function cleanEmptyChildren(nodes: T[]) {\n    for (const node of nodes) {\n      const children = (node as Record<string, unknown>)[childrenKey] as T[];\n      if (Array.isArray(children)) {\n        if (children.length === 0) {\n          delete (node as Record<string, unknown>)[childrenKey];\n        } else {\n          cleanEmptyChildren(children);\n        }\n      }\n    }\n  }\n\n  cleanEmptyChildren(roots);\n  return roots;\n}\n\n/**\n * 映射树的每个节点，生成新树\n *\n * @param tree - 原始树\n * @param mapper - 映射函数\n * @param childrenKey - 子节点字段名，默认 'children'\n * @returns 映射后的新树\n *\n * @example\n * ```ts\n * const options = mapTree(categories, (node) => ({\n *   label: node.name,\n *   value: node.id,\n * }));\n * ```\n */\nexport function mapTree<\n  T extends Record<string, unknown>,\n  R extends Record<string, unknown>,\n>(\n  tree: T[],\n  mapper: (node: T, depth: number) => R,\n  childrenKey: string = DEFAULT_CHILDREN_KEY,\n): R[] {\n  function walk(nodes: T[], depth: number): R[] {\n    return nodes.map((node) => {\n      const mapped = mapper(node, depth);\n      const children = node[childrenKey];\n      if (Array.isArray(children) && children.length > 0) {\n        return { ...mapped, [childrenKey]: walk(children as T[], depth + 1) };\n      }\n      return mapped;\n    });\n  }\n\n  return walk(tree, 0);\n}\n\n/**\n * 判断一个节点是否是另一个节点的后代\n *\n * 单次遍历实现：找到祖先节点后立即在其子树中搜索目标，避免两次全树遍历。\n *\n * @param tree - 树节点数组\n * @param ancestorId - 祖先节点 ID\n * @param targetId - 目标节点 ID\n * @param idKey - ID 字段名，默认 'id'\n * @param childrenKey - 子节点字段名，默认 'children'\n * @returns 是否为后代关系\n *\n * @example\n * ```ts\n * isDescendant(tree, 1, 5) // true: 节点 5 是节点 1 的后代\n * ```\n */\nexport function isDescendant<T extends Record<string, unknown>>(\n  tree: T[],\n  ancestorId: string | number,\n  targetId: string | number,\n  idKey: string = 'id',\n  childrenKey: string = DEFAULT_CHILDREN_KEY,\n): boolean {\n  // 单次递归：遍历到祖先节点后，仅在其子树中搜索目标\n  function searchInSubtree(nodes: T[]): boolean {\n    for (const node of nodes) {\n      if (node[idKey] === ancestorId) {\n        // 找到祖先，仅在其子树中搜索目标\n        const children = node[childrenKey];\n        if (!Array.isArray(children)) return false;\n        return (\n          findNodeInTree(\n            children as T[],\n            (n) => n[idKey] === targetId,\n            childrenKey,\n          ) !== null\n        );\n      }\n      // 继续深搜祖先节点\n      const children = node[childrenKey];\n      if (Array.isArray(children) && children.length > 0) {\n        const found = searchInSubtree(children as T[]);\n        if (found) return true;\n      }\n    }\n    return false;\n  }\n\n  return searchInSubtree(tree);\n}\n\n/**\n * 获取从根到目标节点的路径\n *\n * @param tree - 树节点数组\n * @param predicate - 目标节点匹配函数\n * @param childrenKey - 子节点字段名，默认 'children'\n * @returns 路径数组（从根到目标），未找到返回空数组\n *\n * @example\n * ```ts\n * const path = getNodePath(tree, (n) => n.id === 5);\n * // => [rootNode, parentNode, targetNode]\n * ```\n */\nexport function getNodePath<T extends Record<string, unknown>>(\n  tree: T[],\n  predicate: (node: T) => boolean,\n  childrenKey: string = DEFAULT_CHILDREN_KEY,\n): T[] {\n  function walk(nodes: T[], path: T[]): T[] | null {\n    for (const node of nodes) {\n      const currentPath = [...path, node];\n      if (predicate(node)) return currentPath;\n      const children = node[childrenKey];\n      if (Array.isArray(children) && children.length > 0) {\n        const found = walk(children as T[], currentPath);\n        if (found) return found;\n      }\n    }\n    return null;\n  }\n\n  return walk(tree, []) ?? [];\n}\n\n/**\n * 递归排序树的每一层节点\n *\n * @param tree - 树节点数组\n * @param compareFn - 比较函数，同 Array.sort\n * @param childrenKey - 子节点字段名，默认 'children'\n * @returns 排序后的新树\n *\n * @example\n * ```ts\n * const sorted = sortTree(menuTree, (a, b) => a.orderSeq - b.orderSeq);\n * ```\n */\nexport function sortTree<T extends Record<string, unknown>>(\n  tree: T[],\n  compareFn: (a: T, b: T) => number,\n  childrenKey: string = DEFAULT_CHILDREN_KEY,\n): T[] {\n  return [...tree].sort(compareFn).map((node) => {\n    const children = node[childrenKey];\n    if (Array.isArray(children) && children.length > 0) {\n      return {\n        ...node,\n        [childrenKey]: sortTree(children as T[], compareFn, childrenKey),\n      };\n    }\n    return node;\n  });\n}\n\n/**\n * 遍历树的每个节点（深度优先）\n *\n * @param tree - 树节点数组\n * @param callback - 回调函数，返回 false 可中止遍历\n * @param childrenKey - 子节点字段名，默认 'children'\n *\n * @example\n * ```ts\n * walkTree(menuTree, (node, depth) => {\n *   console.log('  '.repeat(depth) + node.name);\n * });\n * ```\n */\nexport function walkTree<T extends Record<string, unknown>>(\n  tree: T[],\n  callback: (node: T, depth: number, parent: T | null) => undefined | false,\n  childrenKey: string = DEFAULT_CHILDREN_KEY,\n): void {\n  function walk(nodes: T[], depth: number, parent: T | null): boolean {\n    for (const node of nodes) {\n      const result = callback(node, depth, parent);\n      if (result === false) return false;\n      const children = node[childrenKey];\n      if (Array.isArray(children) && children.length > 0) {\n        const shouldContinue = walk(children as T[], depth + 1, node);\n        if (!shouldContinue) return false;\n      }\n    }\n    return true;\n  }\n\n  walk(tree, 0, null);\n}\n","/**\n * URL / 路由工具函数\n *\n * 提供安全的 URL 操作、外部链接处理、查询字符串解析等通用功能。\n *\n */\n\nfunction isAbsoluteOrProtocolRelativeUrl(path: string): boolean {\n  if (isExternalUrl(path)) return true;\n  return /^[a-z][a-z0-9+.-]*:/i.test(path);\n}\n\n/**\n * 安全地在新标签页中打开 URL\n *\n * 自动添加 `noopener,noreferrer` 安全属性，防止新窗口通过 window.opener 访问原页面。\n * 出于安全考虑，拒绝 `javascript:` / `data:` / `vbscript:` / `file:` 协议。\n *\n * @param url - 要打开的 URL\n * @param features - 窗口特性字符串（可选）\n * @returns 新窗口的引用，打开失败返回 null\n *\n * @example\n * ```ts\n * openInNewTab('https://example.com');\n * openInNewTab('/detail/123'); // 相对路径也支持\n * ```\n */\nexport function openInNewTab(url: string, features?: string): Window | null {\n  if (!url || typeof window === 'undefined') return null;\n\n  const trimmedUrl = url.trim();\n  if (/^(javascript|data|vbscript|file):/i.test(trimmedUrl)) {\n    return null;\n  }\n\n  const finalFeatures = features\n    ? `noopener,noreferrer,${features}`\n    : 'noopener,noreferrer';\n  return window.open(trimmedUrl, '_blank', finalFeatures);\n}\n\n/**\n * 标准化外部 URL\n *\n * 自动为缺少协议的 URL 补充 `https://` 前缀。\n *\n * @param url - 原始 URL\n * @returns 标准化后的 URL\n *\n * @example\n * ```ts\n * normalizeExternalUrl('example.com')           // 'https://example.com'\n * normalizeExternalUrl('http://example.com')     // 'http://example.com'\n * normalizeExternalUrl('https://example.com')    // 'https://example.com'\n * normalizeExternalUrl('//cdn.example.com/a.js') // '//cdn.example.com/a.js'\n * ```\n */\nexport function normalizeExternalUrl(url: string): string {\n  if (!url) return '';\n  const trimmed = url.trim();\n  if (\n    trimmed.startsWith('http://') ||\n    trimmed.startsWith('https://') ||\n    trimmed.startsWith('//')\n  ) {\n    return trimmed;\n  }\n  return `https://${trimmed}`;\n}\n\n/**\n * 判断是否为外部链接\n *\n * @param url - URL 字符串\n * @returns 是否为外部链接\n *\n * @example\n * ```ts\n * isExternalUrl('https://example.com')  // true\n * isExternalUrl('http://example.com')   // true\n * isExternalUrl('//cdn.example.com')    // true\n * isExternalUrl('/dashboard')           // false\n * isExternalUrl('about')               // false\n * ```\n */\nexport function isExternalUrl(url: string): boolean {\n  if (!url) return false;\n  return /^(https?:)?\\/\\//.test(url.trim());\n}\n\n/**\n * 拼接公共资源路径\n *\n * @param path - 资源相对路径\n * @param baseUrl - 基础 URL，默认为空（使用相对路径）\n * @returns 完整的资源 URL\n *\n * @example\n * ```ts\n * getPublicUrl('/images/logo.png', 'https://cdn.example.com')\n * // => 'https://cdn.example.com/images/logo.png'\n *\n * getPublicUrl('images/logo.png')\n * // => '/images/logo.png'\n * ```\n */\nexport function getPublicUrl(path: string, baseUrl?: string): string {\n  if (!path) return '';\n\n  // 已经是完整 URL\n  if (isExternalUrl(path)) return path;\n\n  // 拼接 baseUrl\n  if (baseUrl) {\n    const normalizedBase = baseUrl.endsWith('/')\n      ? baseUrl.slice(0, -1)\n      : baseUrl;\n    const normalizedPath = path.startsWith('/') ? path : `/${path}`;\n    return `${normalizedBase}${normalizedPath}`;\n  }\n\n  // 确保以 / 开头\n  return path.startsWith('/') ? path : `/${path}`;\n}\n\n/**\n * 构建查询字符串\n *\n * 自动过滤 null、undefined 和空字符串值。\n *\n * @param params - 参数对象\n * @returns 查询字符串（不含 '?'）\n *\n * @example\n * ```ts\n * buildQueryString({ page: 1, keyword: 'test', status: null })\n * // => 'page=1&keyword=test'\n *\n * buildQueryString({ tags: ['a', 'b'] })\n * // => 'tags=a&tags=b'\n * ```\n */\nexport function buildQueryString(\n  params: Record<\n    string,\n    string | number | boolean | string[] | null | undefined\n  >,\n): string {\n  const searchParams = new URLSearchParams();\n\n  for (const [key, value] of Object.entries(params)) {\n    if (value === null || value === undefined || value === '') continue;\n\n    if (Array.isArray(value)) {\n      for (const item of value) {\n        if (item !== null && item !== undefined && item !== '') {\n          searchParams.append(key, String(item));\n        }\n      }\n    } else {\n      searchParams.append(key, String(value));\n    }\n  }\n\n  return searchParams.toString();\n}\n\n/**\n * 解析查询字符串为对象\n *\n * @param search - 查询字符串（可以带或不带 '?'）\n * @returns 参数对象\n *\n * @example\n * ```ts\n * parseQueryString('?page=1&keyword=test')\n * // => { page: '1', keyword: 'test' }\n *\n * parseQueryString('tags=a&tags=b')\n * // => { tags: ['a', 'b'] }\n * ```\n */\nexport function parseQueryString(\n  search: string,\n): Record<string, string | string[]> {\n  const params = new URLSearchParams(\n    search.startsWith('?') ? search.slice(1) : search,\n  );\n  const result: Record<string, string | string[]> = {};\n\n  for (const key of new Set(params.keys())) {\n    const values = params.getAll(key);\n    result[key] = values.length === 1 ? values[0] : values;\n  }\n\n  return result;\n}\n\n/**\n * 安全地打开外部链接（标准化 + 新标签页）\n *\n * @param url - 外部 URL\n * @returns 新窗口的引用\n *\n * @example\n * ```ts\n * openExternalUrl('example.com') // 自动补 https:// 并在新标签页打开\n * ```\n */\nexport function openExternalUrl(url: string): Window | null {\n  return openInNewTab(normalizeExternalUrl(url));\n}\n\n/**\n * 获取资源 URL\n *\n * 处理资源路径，支持绝对 URL、data URI 和相对路径。\n * 绝对 URL 和 data URI 直接返回，其他路径通过 getPublicUrl 拼接。\n *\n * @param path - 资源路径\n * @param baseUrl - 基础 URL（可选），用于拼接相对路径\n * @returns 完整的资源 URL 或 undefined\n *\n * @example\n * ```ts\n * getResourceUrl('https://cdn.example.com/avatar.png')  // 直接返回\n * getResourceUrl('data:image/png;base64,...')            // 直接返回\n * getResourceUrl('/uploads/avatar.png', '/api')          // '/api/uploads/avatar.png'\n * getResourceUrl(null)                                   // undefined\n * ```\n */\nexport function getResourceUrl(\n  path?: string | null,\n  baseUrl?: string,\n): string | undefined {\n  if (!path || typeof path !== 'string') {\n    return undefined;\n  }\n  const trimmedPath = path.trim();\n  if (trimmedPath === '') return undefined;\n\n  // 绝对 URL / data URI 直接返回\n  if (isAbsoluteOrProtocolRelativeUrl(trimmedPath)) {\n    return trimmedPath;\n  }\n  // 所有其他路径统一走 getPublicUrl 处理\n  return getPublicUrl(trimmedPath, baseUrl);\n}\n","/**\n * 通用验证器工具函数\n */\n\n/**\n * 密码强度级别\n */\nexport type PasswordStrength = 'weak' | 'medium' | 'strong';\n\n/**\n * 密码强度检测结果\n */\nexport interface PasswordStrengthResult {\n  /** 强度级别 */\n  strength: PasswordStrength;\n  /** 强度分数 (0-100) */\n  score: number;\n  /** 建议列表 */\n  suggestions: string[];\n}\n\n/**\n * 密码强度建议消息（可自定义以支持国际化）\n */\nexport interface PasswordMessages {\n  empty: string;\n  minLength: string;\n  lowercase: string;\n  uppercase: string;\n  digit: string;\n  special: string;\n}\n\n/** 默认密码强度建议（英文） */\nconst DEFAULT_PASSWORD_MESSAGES: PasswordMessages = {\n  empty: 'Please enter a password',\n  minLength: 'Password must be at least 8 characters',\n  lowercase: 'Should contain lowercase letters',\n  uppercase: 'Should contain uppercase letters',\n  digit: 'Should contain digits',\n  special: 'Should contain special characters',\n};\n\n/**\n * 文件验证选项\n */\nexport interface FileValidateOptions {\n  /** 允许的文件类型 (MIME 类型或扩展名) */\n  allowedTypes?: string[];\n  /** 最大文件大小 (字节) */\n  maxSize?: number;\n}\n\n/**\n * 验证邮箱格式\n *\n * @param email - 邮箱地址\n * @returns 是否有效\n */\nexport function validateEmail(email: string): boolean {\n  if (!email) return false;\n  const pattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$/;\n  return pattern.test(email.trim());\n}\n\n/**\n * 验证中国手机号格式\n *\n * @param phone - 手机号\n * @returns 是否有效\n */\nexport function validatePhone(phone: string): boolean {\n  if (!phone) return false;\n  const pattern = /^1[3-9]\\d{9}$/;\n  return pattern.test(phone.trim());\n}\n\n/**\n * 验证 URL 格式\n *\n * @param url - URL 字符串\n * @returns 是否有效\n */\nexport function validateURL(url: string): boolean {\n  if (!url) return false;\n  try {\n    const parsed = new URL(url.trim());\n    return ['http:', 'https:'].includes(parsed.protocol);\n  } catch {\n    return false;\n  }\n}\n\n/**\n * 检测密码强度\n *\n * @param password - 密码\n * @param messages - 自定义建议消息（可选，用于国际化）\n * @returns 密码强度结果\n *\n * @example\n * ```ts\n * const result = validatePasswordStrength('Abc123!@#');\n * // { strength: 'strong', score: 85, suggestions: [] }\n *\n * // 自定义中文消息\n * const result = validatePasswordStrength('abc', {\n *   empty: '请输入密码',\n *   minLength: '密码长度至少8位',\n *   lowercase: '建议包含小写字母',\n *   uppercase: '建议包含大写字母',\n *   digit: '建议包含数字',\n *   special: '建议包含特殊字符',\n * });\n * ```\n */\nexport function validatePasswordStrength(\n  password: string,\n  messages?: Partial<PasswordMessages>,\n): PasswordStrengthResult {\n  const msg = { ...DEFAULT_PASSWORD_MESSAGES, ...messages };\n  const suggestions: string[] = [];\n  let score = 0;\n\n  if (!password) {\n    return { strength: 'weak', score: 0, suggestions: [msg.empty] };\n  }\n\n  // 长度评分\n  if (password.length >= 8) score += 20;\n  else suggestions.push(msg.minLength);\n\n  if (password.length >= 12) score += 10;\n  if (password.length >= 16) score += 5;\n\n  // 包含小写字母\n  if (/[a-z]/.test(password)) score += 15;\n  else suggestions.push(msg.lowercase);\n\n  // 包含大写字母\n  if (/[A-Z]/.test(password)) score += 15;\n  else suggestions.push(msg.uppercase);\n\n  // 包含数字\n  if (/\\d/.test(password)) score += 15;\n  else suggestions.push(msg.digit);\n\n  // 包含特殊字符\n  if (/[!@#$%^&*()_+\\-=[\\]{};':\"\\\\|,.<>/?]/.test(password)) score += 20;\n  else suggestions.push(msg.special);\n\n  // 确定强度级别\n  let strength: PasswordStrength;\n  if (score >= 70) {\n    strength = 'strong';\n  } else if (score >= 40) {\n    strength = 'medium';\n  } else {\n    strength = 'weak';\n  }\n\n  return { strength, score: Math.min(score, 100), suggestions };\n}\n\n/**\n * 验证中国身份证号\n *\n * @param idCard - 身份证号\n * @returns 是否有效\n */\nexport function validateIdCard(idCard: string): boolean {\n  if (!idCard) return false;\n  const str = idCard.trim();\n\n  // 18位身份证\n  if (str.length === 18) {\n    const pattern = /^\\d{17}[\\dXx]$/;\n    if (!pattern.test(str)) return false;\n\n    // 校验位验证\n    const weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];\n    const checkCodes = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];\n    let sum = 0;\n    for (let i = 0; i < 17; i++) {\n      sum += Number.parseInt(str[i], 10) * weights[i];\n    }\n    const checkCode = checkCodes[sum % 11];\n    return str[17].toUpperCase() === checkCode;\n  }\n\n  // 15位身份证\n  if (str.length === 15) {\n    return /^\\d{15}$/.test(str);\n  }\n\n  return false;\n}\n\n/**\n * 验证银行卡号 (Luhn 算法)\n *\n * @param cardNo - 银行卡号\n * @returns 是否有效\n */\nexport function validateBankCard(cardNo: string): boolean {\n  if (!cardNo) return false;\n  const str = cardNo.trim().replace(/\\s/g, '');\n  if (!/^\\d{13,19}$/.test(str)) return false;\n\n  // Luhn 算法\n  let sum = 0;\n  let isEven = false;\n  for (let i = str.length - 1; i >= 0; i--) {\n    let digit = Number.parseInt(str[i], 10);\n    if (isEven) {\n      digit *= 2;\n      if (digit > 9) digit -= 9;\n    }\n    sum += digit;\n    isEven = !isEven;\n  }\n  return sum % 10 === 0;\n}\n\n/**\n * 验证文件类型\n *\n * @param file - 文件对象\n * @param allowedTypes - 允许的类型 (MIME 类型或扩展名，如 ['.jpg', '.png', 'image/jpeg'])\n * @returns 是否有效\n */\nexport function validateFileType(\n  file: { name: string; type?: string },\n  allowedTypes: string[],\n): boolean {\n  if (!file || !allowedTypes.length) return true;\n\n  const fileName = file.name.toLowerCase();\n  const fileType = file.type?.toLowerCase() || '';\n\n  return allowedTypes.some((type) => {\n    const t = type.toLowerCase();\n    if (t.startsWith('.')) {\n      // 扩展名匹配\n      return fileName.endsWith(t);\n    }\n    // MIME 类型匹配\n    return fileType === t || fileType.startsWith(`${t.split('/')[0]}/`);\n  });\n}\n\n/**\n * 验证文件大小\n *\n * @param file - 文件对象\n * @param maxSize - 最大大小 (字节)\n * @returns 是否在限制内\n */\nexport function validateFileSize(\n  file: { size: number },\n  maxSize: number,\n): boolean {\n  if (!file || maxSize <= 0) return true;\n  return file.size <= maxSize;\n}\n\n/**\n * 验证数字范围\n *\n * @param value - 数值\n * @param min - 最小值 (含)\n * @param max - 最大值 (含)\n * @returns 是否在范围内\n */\nexport function validateNumberRange(\n  value: number,\n  min: number,\n  max: number,\n): boolean {\n  return value >= min && value <= max;\n}\n","/**\n * ValueEnum / Select Options 转换工具\n *\n * 用于将常量映射表转换为 ProTable valueEnum 格式或 Ant Design Select options 格式。\n * 三个项目大量使用 ProTable 的 valueEnum，均有手工转换逻辑。\n *\n */\n\n/**\n * ProTable valueEnum 项\n */\nexport interface ValueEnumItem {\n  /** 显示文本 */\n  text: string;\n  /** 状态（ProTable 内置：success, error, processing, warning, default） */\n  status?: 'success' | 'error' | 'processing' | 'warning' | 'default';\n  /** 颜色 */\n  color?: string;\n  /** 是否禁用 */\n  disabled?: boolean;\n}\n\n/**\n * ProTable valueEnum 类型\n */\nexport type ValueEnumMap = Record<string | number, ValueEnumItem | string>;\n\n/**\n * Select/Radio 选项\n */\nexport interface OptionItem<V = string | number> {\n  /** 显示文本 */\n  label: string;\n  /** 值 */\n  value: V;\n  /** 颜色（可选） */\n  color?: string;\n  /** 是否禁用 */\n  disabled?: boolean;\n}\n\n/**\n * 常量映射项的通用结构\n */\ninterface ConstantMapItem {\n  text: string;\n  color?: string;\n  status?: 'success' | 'error' | 'processing' | 'warning' | 'default';\n  disabled?: boolean;\n}\n\n/**\n * createValueEnum 选项\n */\nexport interface CreateValueEnumOptions {\n  /** 当 useOriginalStatus 为 false 时使用的默认 status */\n  defaultStatus?: 'success' | 'error' | 'processing' | 'warning' | 'default';\n  /** 是否使用原始映射中的 status 字段，默认 true */\n  useOriginalStatus?: boolean;\n}\n\n/**\n * 将常量映射表转换为 ProTable valueEnum 格式\n *\n * @param map - 常量映射表 `{ key: { text, color?, status? } }`\n * @param options - 可选配置\n * @returns ProTable 可用的 valueEnum 对象\n *\n * @example\n * ```ts\n * const STATUS_MAP = {\n *   1: { text: '启用', color: 'green', status: 'success' },\n *   0: { text: '禁用', color: 'red', status: 'error' },\n * } as const;\n *\n * // 使用原始 status\n * const valueEnum = createValueEnum(STATUS_MAP);\n *\n * // 统一使用 Default status\n * const valueEnum2 = createValueEnum(STATUS_MAP, {\n *   useOriginalStatus: false,\n *   defaultStatus: 'default',\n * });\n *\n * <ProTable columns={[{ title: '状态', dataIndex: 'status', valueEnum }]} />\n * ```\n */\nexport function createValueEnum(\n  map: Record<string | number, ConstantMapItem>,\n  options?: CreateValueEnumOptions,\n): ValueEnumMap {\n  const { defaultStatus = 'default', useOriginalStatus = true } = options ?? {};\n  const result: ValueEnumMap = {};\n\n  for (const [key, item] of Object.entries(map)) {\n    const status =\n      useOriginalStatus && item.status ? item.status : defaultStatus;\n\n    result[key] = {\n      text: item.text,\n      status,\n      ...(item.color ? { color: item.color } : {}),\n      ...(item.disabled ? { disabled: item.disabled } : {}),\n    };\n  }\n\n  return result;\n}\n\n/**\n * 从数组创建 valueEnum\n *\n * @param arr - 数据数组\n * @param valueKey - 值字段名\n * @param labelKey - 文本字段名\n * @param options - 可选配置\n * @returns ProTable 可用的 valueEnum 对象\n *\n * @example\n * ```ts\n * const categories = [\n *   { id: 1, name: '分类A' },\n *   { id: 2, name: '分类B' },\n * ];\n * const valueEnum = createValueEnumFromArray(categories, 'id', 'name');\n * // => { 1: { text: '分类A' }, 2: { text: '分类B' } }\n * ```\n */\nexport function createValueEnumFromArray<T extends Record<string, unknown>>(\n  arr: T[],\n  valueKey: keyof T & string,\n  labelKey: keyof T & string,\n  options?: {\n    /** 颜色字段名 */\n    colorKey?: keyof T & string;\n    /** 状态字段名 */\n    statusKey?: keyof T & string;\n  },\n): ValueEnumMap {\n  const result: ValueEnumMap = {};\n\n  for (const item of arr) {\n    const key = String(item[valueKey]);\n    const text = String(item[labelKey]);\n    const enumItem: ValueEnumItem = { text };\n\n    if (options?.colorKey && item[options.colorKey]) {\n      enumItem.color = String(item[options.colorKey]);\n    }\n    if (options?.statusKey && item[options.statusKey]) {\n      enumItem.status = item[options.statusKey] as ValueEnumItem['status'];\n    }\n\n    result[key] = enumItem;\n  }\n\n  return result;\n}\n\n/**\n * 将常量映射表转换为 Select/Radio 的 options 数组\n *\n * @param map - 常量映射表\n * @returns Select/Radio 可用的 options 数组\n *\n * @example\n * ```ts\n * const STATUS_MAP = {\n *   1: { text: '启用', color: 'green' },\n *   0: { text: '禁用', color: 'red' },\n * };\n *\n * const options = createSelectOptionsFromMap(STATUS_MAP);\n * // => [{ label: '启用', value: '1', color: 'green' }, { label: '禁用', value: '0', color: 'red' }]\n *\n * <Select options={options} />\n * ```\n */\nexport function createSelectOptionsFromMap(\n  map: Record<string | number, ConstantMapItem>,\n): OptionItem<string>[] {\n  return Object.entries(map).map(([key, item]) => ({\n    label: item.text,\n    value: key,\n    ...(item.color ? { color: item.color } : {}),\n    ...(item.disabled ? { disabled: item.disabled } : {}),\n  }));\n}\n\n/**\n * 从数组创建 Select/Radio 的 options 数组\n *\n * @param arr - 数据数组\n * @param valueKey - 值字段名\n * @param labelKey - 文本字段名\n * @returns options 数组\n *\n * @example\n * ```ts\n * const roles = [{ id: 1, roleName: '管理员' }, { id: 2, roleName: '普通用户' }];\n * const options = createSelectOptionsFromArray(roles, 'id', 'roleName');\n * // => [{ label: '管理员', value: 1 }, { label: '普通用户', value: 2 }]\n * ```\n */\nexport function createSelectOptionsFromArray<\n  T extends Record<string, unknown>,\n  V = T[keyof T],\n>(\n  arr: T[],\n  valueKey: keyof T & string,\n  labelKey: keyof T & string,\n): OptionItem<V>[] {\n  return arr.map((item) => ({\n    label: String(item[labelKey]),\n    value: item[valueKey] as V,\n  }));\n}\n\n/**\n * 获取枚举映射中指定值的显示文本\n *\n * @param map - 常量映射表\n * @param value - 枚举值\n * @param defaultText - 默认文本，默认 '--'\n * @returns 显示文本\n *\n * @example\n * ```ts\n * getEnumText(STATUS_MAP, 1) // '启用'\n * getEnumText(STATUS_MAP, 999) // '--'\n * ```\n */\nexport function getEnumText(\n  map: Record<string | number, ConstantMapItem>,\n  value: string | number | null | undefined,\n  defaultText: string = '--',\n): string {\n  if (value === null || value === undefined) return defaultText;\n  return map[value]?.text ?? defaultText;\n}\n\n/**\n * 获取枚举映射中指定值的颜色\n *\n * @param map - 常量映射表\n * @param value - 枚举值\n * @param defaultColor - 默认颜色，默认 'default'\n * @returns 颜色值\n *\n * @example\n * ```ts\n * getEnumColor(STATUS_MAP, 1) // 'green'\n * getEnumColor(STATUS_MAP, 999) // 'default'\n * ```\n */\nexport function getEnumColor(\n  map: Record<string | number, ConstantMapItem>,\n  value: string | number | null | undefined,\n  defaultColor: string = 'default',\n): string {\n  if (value === null || value === undefined) return defaultColor;\n  return map[value]?.color ?? defaultColor;\n}\n","/**\n * 水印配置工具\n *\n * 生成 Ant Design App 组件 watermark 属性，或独立使用的 canvas 水印。\n *\n */\n\n// ===== 类型定义 =====\n\n/**\n * 水印配置选项\n */\nexport interface WatermarkOptions {\n  /** 水印文字内容 (如用户名, 可以是字符串或数组) */\n  content?: string | string[];\n  /** 是否启用, 默认 true */\n  enabled?: boolean;\n  /** 字体大小, 默认 14 */\n  fontSize?: number;\n  /** 字体颜色, 默认 'rgba(0, 0, 0, 0.15)' */\n  fontColor?: string;\n  /** 旋转角度 (度), 默认 -22 */\n  rotate?: number;\n  /** 水印之间的间距 [水平, 垂直], 默认 [100, 100] */\n  gap?: [number, number];\n  /** 水印相对于容器的偏移 [x, y] */\n  offset?: [number, number];\n  /** z-index, 默认 9 */\n  zIndex?: number;\n  /** 字体族, 默认 sans-serif */\n  fontFamily?: string;\n  /** 字体粗细, 默认 'normal' */\n  fontWeight?: 'normal' | 'light' | 'bold' | number;\n}\n\n/**\n * Ant Design Watermark props 子集\n */\nexport interface AntdWatermarkProps {\n  content?: string | string[];\n  font?: {\n    fontSize?: number;\n    color?: string;\n    fontFamily?: string;\n    fontWeight?: 'normal' | 'light' | 'bold' | number;\n  };\n  rotate?: number;\n  gap?: [number, number];\n  offset?: [number, number];\n  zIndex?: number;\n}\n\n// ===== 工厂函数 =====\n\n/**\n * 创建 Ant Design Watermark 组件的 props\n *\n * @param options - 水印配置\n * @returns 当 enabled=false 或 content 为空时返回 undefined, 否则返回 Watermark props\n *\n * @example\n * ```tsx\n * import { Watermark } from 'antd';\n *\n * const watermarkProps = createWatermarkConfig({\n *   content: currentUser?.name,\n *   enabled: process.env.NODE_ENV === 'production',\n * });\n *\n * // 在 layout childrenRender 中使用\n * const layout = {\n *   childrenRender: (children) => watermarkProps\n *     ? <Watermark {...watermarkProps}>{children}</Watermark>\n *     : children,\n * };\n * ```\n *\n * @example\n * ```tsx\n * // 多行水印\n * const watermarkProps = createWatermarkConfig({\n *   content: [currentUser?.name ?? '', dayjs().format('YYYY-MM-DD')],\n *   fontSize: 12,\n *   fontColor: 'rgba(0, 0, 0, 0.1)',\n * });\n * ```\n */\nexport function createWatermarkConfig(\n  options: WatermarkOptions,\n): AntdWatermarkProps | undefined {\n  const {\n    content,\n    enabled = true,\n    fontSize = 14,\n    fontColor = 'rgba(0, 0, 0, 0.15)',\n    rotate = -22,\n    gap = [100, 100],\n    offset,\n    zIndex = 9,\n    fontFamily = 'sans-serif',\n    fontWeight = 'normal',\n  } = options;\n\n  // 不启用或无内容时返回 undefined\n  if (!enabled) return undefined;\n\n  if (!content) return undefined;\n\n  // 内容为空字符串或空数组\n  if (Array.isArray(content) && content.every((c) => !c)) return undefined;\n  if (typeof content === 'string' && !content.trim()) return undefined;\n\n  const result: AntdWatermarkProps = {\n    content,\n    font: {\n      fontSize,\n      color: fontColor,\n      fontFamily,\n      fontWeight,\n    },\n    rotate,\n    gap,\n    zIndex,\n  };\n\n  if (offset) {\n    result.offset = offset;\n  }\n\n  return result;\n}\n\n/**\n * 创建简单的用户水印配置\n *\n * 常见场景的快捷方式: 仅传用户名即可。\n *\n * @param userName - 用户名\n * @param enabled - 是否启用，默认 true。消费方应根据自身环境判断：\n *   - UmiJS: `process.env.NODE_ENV === 'production'`\n *   - Vite: `import.meta.env.PROD`\n * @returns Watermark props 或 undefined\n *\n * @example\n * ```tsx\n * const watermarkProps = createUserWatermark(currentUser?.name, import.meta.env.PROD);\n * ```\n */\nexport function createUserWatermark(\n  userName?: string | null,\n  enabled = true,\n): AntdWatermarkProps | undefined {\n  if (!userName) return undefined;\n\n  return createWatermarkConfig({\n    content: userName,\n    enabled,\n    fontSize: 14,\n    fontColor: 'rgba(0, 0, 0, 0.12)',\n  });\n}\n"]}