import { ErrorShowType } from '../constants/index.cjs'; import { d as ProTableResponse, A as ApiResponse } from '../api-DFOs5fnc.cjs'; import dayjs from 'dayjs'; import React from 'react'; /** * API 错误处理增强工具 * * 在请求层 error-handler 的基础上,提供业务层的错误处理包装。 * 包含 ProTable 请求包装器、统一错误处理器等。 * */ /** * API 错误处理配置 */ interface ApiErrorHandlerConfig { /** message 展示函数 */ showMessage?: (content: string, type: 'success' | 'error' | 'warning' | 'info') => void; /** notification 展示函数 */ showNotification?: (options: { message: string; description?: string; }) => void; /** 重定向函数 */ redirect?: (path: string) => void; /** 登录过期回调 */ onUnauthorized?: () => void; /** 登录过期的状态码 */ unauthorizedCodes?: (string | number)[]; /** notification 标题,默认 'Request Error' */ notificationTitle?: string; /** 重定向路径,默认 '/error' */ redirectPath?: string; } /** * 创建项目级 API 错误处理器 * * @param config - 错误处理配置 * @returns 错误处理函数 * * @example * ```ts * const handleApiError = createApiErrorHandler({ * showMessage: (content, type) => message[type](content), * showNotification: ({ message: msg, description }) => notification.error({ message: msg, description }), * onUnauthorized: () => emitLoginRequired(), * unauthorizedCodes: [401, 10014], * notificationTitle: '请求错误', * }); * * // 在请求拦截器中使用 * handleApiError(error, ErrorShowType.ERROR_MESSAGE); * ``` */ declare function createApiErrorHandler(config: ApiErrorHandlerConfig): (error: unknown, showType?: ErrorShowType) => void; /** * 从错误对象中提取错误消息 * * @param error - 错误对象 * @param defaultMessage - 默认错误消息,默认 'Unknown error' * @returns 错误消息字符串 */ declare function extractErrorMessage(error: unknown, defaultMessage?: string): string; /** * 从错误对象中提取错误码 * * @param error - 错误对象 * @returns 错误码 */ declare function extractErrorCode(error: unknown): string | number | undefined; /** * 包装 ProTable 的 request 函数,自动处理错误并返回标准格式 * * 确保即使 API 调用失败,ProTable 也不会崩溃,始终返回合法的空数据。 * * @param requestFn - 原始请求函数 * @param options - 配置选项 * @returns 包装后的请求函数 * * @example * ```ts * const safeRequest = wrapProTableRequest( * async (params) => { * const res = await getUserList(params); * return { data: res.data.list, total: res.data.total, success: true }; * }, * { onError: (err) => message.error(err.message) } * ); * * * ``` */ declare function wrapProTableRequest>(requestFn: (params: P) => Promise>, options?: { /** 错误回调 */ onError?: (error: Error) => void; }): (params: P) => Promise>; /** * API 辅助函数 * * 提供 API 响应判断、安全执行等通用工具。 * 从 types/api.ts 迁移而来,types/ 目录应仅包含类型定义。 */ /** * 判断 API 响应是否成功 * * 仅通过 `code` 与 `successCode` 比较来判断,不做隐式回退。 * 如果后端使用 `0` 作为成功码,请传 `successCode: 0`。 * * @param response - API 响应对象 * @param successCode - 成功状态码,默认 '200' * @returns 是否成功 * * @example * ```ts * const res = await fetchUser(1); * if (isApiSuccess(res)) { * console.log(res.data); * } * * // 后端使用 0 作为成功码 * if (isApiSuccess(res, 0)) { ... } * ``` */ declare function isApiSuccess(response: ApiResponse | null | undefined, successCode?: string | number): boolean; /** * 安全地执行 API 调用并处理错误 * * @param apiFn - API 调用函数 * @param options - 配置选项 * @returns API 响应数据或 null * * @example * ```ts * // 获取数据 * const data = await executeApiAction( * () => fetchUser(1), * { * onSuccess: (data, msg) => message.success(msg), * onError: (msg) => message.error(msg), * } * ); * * // 执行操作并判断成功 * const data = await executeApiAction( * () => deleteUser(id), * { * successMsg: 'Deleted', * onSuccess: (data, msg) => message.success(msg), * onError: (msg) => message.error(msg), * } * ); * if (data !== null) actionRef.current?.reload(); * ``` */ declare function executeApiAction(apiFn: () => Promise>, options?: { /** 成功时的提示消息 */ successMsg?: string; /** 失败时的提示消息 (覆盖 API 返回的 msg) */ errorMsg?: string; /** 成功回调 */ onSuccess?: (data: T, msg: string) => void; /** 错误回调 */ onError?: (msg: string, code: string | number) => void; /** 成功状态码 */ successCode?: string | number; /** 默认失败提示,默认 'Operation failed' */ defaultErrorMsg?: string; /** 默认网络错误提示,默认 'Network error' */ defaultNetworkErrorMsg?: string; }): Promise; /** * 认证工具函数工厂 * * * 通过配置适配不同的认证方式。 */ /** * AuthManager 配置 */ interface AuthManagerConfig { /** token/session 在 localStorage 中的 key */ tokenKey: string; /** 过期时间存储 key (可选,用于 session 有效期管理) */ expireKey?: string; /** 会话有效期 (毫秒),不设置则不自动过期 */ ttlMs?: number; /** 需要在 clearAuth 时额外清除的 localStorage key 列表 */ extraStorageKeys?: string[]; /** 登出后的回调 (如跳转登录页) */ onUnauthorized?: () => void; } /** * AuthManager 实例 */ interface AuthManager { /** 获取 token (自动检查过期) */ getToken: () => string | null; /** 设置 token (自动写入过期时间) */ setToken: (token: string) => void; /** 清除所有认证信息 */ clearAuth: () => void; /** 处理未授权状态 (清除认证 + 执行 onUnauthorized 回调) */ handleUnauthorized: () => void; /** 检查是否已认证 */ isAuthenticated: () => boolean; } declare function createAuthManager(config: AuthManagerConfig): AuthManager; /** * 登录事件常量 (用于跨组件通信触发登录模态框) */ declare const LOGIN_REQUIRED_EVENT = "auth:login-required"; /** * 触发登录请求事件 * * @example * ```ts * // 在 request interceptor 中 * emitLoginRequired(); * * // 在组件中监听 * window.addEventListener('auth:login-required', () => setLoginVisible(true)); * ``` */ declare function emitLoginRequired(): void; /** * 剪贴板工具函数 * * 使用 Clipboard API (所有现代浏览器均支持) */ /** * 复制文本到剪贴板 * * @param text - 要复制的文本 * @returns 是否复制成功 * * @example * ```ts * const success = await copyToClipboard('Hello World'); * if (success) { * message.success('已复制到剪贴板'); * } * ``` */ declare function copyToClipboard(text: string): Promise; /** * 业务辅助格式化工具 * * 包含特定业务场景逻辑(如中文面议、Java 后端数据格式)。 */ /** * 格式化价格显示(支持面议状态) * * @category Business Helpers * @param price - 价格值 * @param options - 配置选项 * @returns 格式化后的价格字符串 */ declare function formatPrice(price: number | string | undefined | null, options?: { prefix?: string; suffix?: string; negotiableText?: string; }): string; /** * 判断价格是否为面议 * * 统一的价格面议判断逻辑,支持 undefined / null / 空字符串 / NaN / 负数。 * * @category Business Helpers * @param price - 价格值 * @returns 是否面议 */ declare function isNegotiablePrice(price: number | string | undefined | null): boolean; /** * 格式化地址显示 * * 将逗号分隔的地址字符串替换为指定分隔符(默认空格)。 * * @category Business Helpers * @param location - 地址字符串 * @param separator - 分隔符,默认 ' ' * @returns 格式化后的地址 */ declare function formatLocation(location: string | undefined | null, separator?: string): string; /** 布尔标志类型:支持数字、字符串、布尔值 */ type BooleanFlag = number | string | boolean | undefined | null; /** * 检查布尔标志是否为真值 * * 支持后端返回的多种布尔表示形式(数字 1、字符串 "1"、布尔值等)。 * * @category Business Helpers * @param flag - 布尔标志值 * @param trueLabels - 额外的真值标签列表 * @returns 是否为真 */ declare function checkBooleanFlag(flag: BooleanFlag, trueLabels?: string[]): boolean; /** Java 字符串数组输入类型:字符串或字符串数组 */ type JavaStringArrayInput = string | string[] | undefined | null; /** * 解析 Java String 数组格式 * * 支持 JSON 数组字符串 `["a","b"]` 和普通字符串,自动过滤空值。 * 用于对接 Java 后端返回的字符串数组字段。 * * @category Business Helpers * @param val - 输入值 * @returns 解析后的字符串数组 */ declare function parseJavaStringArray(val: JavaStringArrayInput): string[]; /** * 格式化相关常量 */ /** 空值占位符 */ declare const EMPTY_PLACEHOLDER = "--"; /** * 日期时间格式化工具 */ /** 默认日期格式 */ declare const DEFAULT_DATE_FORMAT = "YYYY-MM-DD"; /** 默认日期时间格式 */ declare const DEFAULT_DATETIME_FORMAT = "YYYY-MM-DD HH:mm:ss"; /** * 初始化格式化工具的 locale 设置 * * 在应用启动时调用一次,设置 dayjs 的全局 locale。 * 如果不调用,dayjs 将使用默认的 'en' locale。 * * @param locale - dayjs locale 名称,如 'zh-cn' */ declare function initFormatters(locale: string): void; /** * 格式化日期 * * @param date - 日期值 (字符串/数字/Date/dayjs) * @param format - 格式模板,默认 'YYYY-MM-DD' * @returns 格式化后的日期字符串,无效日期返回 '--' */ declare function formatDate(date: string | number | Date | dayjs.Dayjs | null | undefined, format?: string): string; /** * 格式化日期时间 * * @param date - 日期值 * @param format - 格式模板,默认 'YYYY-MM-DD HH:mm:ss' * @returns 格式化后的日期时间字符串 */ declare function formatDateTime(date: string | number | Date | dayjs.Dayjs | null | undefined, format?: string): string; /** * 格式化为相对时间 (如 "5分钟前"、"3天前") * * 30天以内显示相对时间,超过30天显示具体日期。 * * @param date - 日期值 * @param thresholdDays - 超过此天数显示具体日期,默认 30 * @returns 相对时间字符串 */ declare function formatRelativeTime(date: string | number | Date | dayjs.Dayjs | null | undefined, thresholdDays?: number): string; /** * 数字格式化工具 */ /** * 格式化数字 (千分位分隔) * * 使用 `Intl.NumberFormat` 实现,支持多语言 locale、性能更优。 * * @param num - 数字 * @param precision - 小数位数,默认不处理 * @param locale - BCP 47 语言标签,如 'zh-CN'、'en-US',默认使用浏览器 locale * @returns 格式化后的字符串 */ declare function formatNumber(num: number | string | null | undefined, precision?: number, locale?: string): string; /** * 格式化货币 * * 使用 `Intl.NumberFormat` 实现,支持多语言 locale。 * 默认使用前缀符号模式(`¥1,234.50`),与原有行为一致。 * * @param amount - 金额 * @param currency - 货币符号,默认 '¥' * @param precision - 小数位数,默认 2 * @param locale - BCP 47 语言标签,默认使用浏览器 locale * @returns 格式化后的货币字符串 */ declare function formatCurrency(amount: number | string | null | undefined, currency?: string, precision?: number, locale?: string): string; /** * 格式化百分比 * * @param value - 数值 (0-1 或 0-100) * @param decimals - 小数位数,默认 2 * @param isRatio - 是否为比率 (0-1),默认 false * @returns 格式化后的百分比字符串 */ declare function formatPercentage(value: number | null | undefined, decimals?: number, isRatio?: boolean): string; /** * 格式化文件大小 * * @param bytes - 字节数 * @param decimals - 小数位数,默认 2 * @returns 格式化后的文件大小字符串 */ declare function formatBytes(bytes: number | null | undefined, decimals?: number): string; /** * 文本格式化工具 */ /** * 格式化手机号 (脱敏) * * @param phone - 手机号 * @param mask - 掩码字符,默认 '*' * @returns 脱敏后的手机号 */ declare function formatPhone(phone: string | null | undefined, mask?: string): string; /** * 格式化文本 (截断 + 省略号) * * @param text - 原始文本 * @param maxLength - 最大长度,默认 50 * @param suffix - 省略后缀,默认 '...' * @returns 截断后的文本 */ declare function formatText(text: string | null | undefined, maxLength?: number, suffix?: string): string; /** * 可配置的日志工具 * */ /** 日志级别 */ type LogLevel = 'debug' | 'info' | 'warn' | 'error'; /** * 消息展示接口 (适配 antd message API) */ interface MessageApi { info: (content: string) => void; warning: (content: string) => void; error: (content: string) => void; success: (content: string) => void; } /** Logger 配置 */ interface LoggerOptions { /** 日志前缀 */ prefix?: string; /** 最低日志级别,低于此级别的日志不会输出 */ level?: LogLevel; /** * 是否为生产环境(用于决定是否抑制日志) * * 默认 false。消费方应根据自身构建工具传入: * - UmiJS: `process.env.NODE_ENV === 'production'` * - Vite: `import.meta.env.PROD` */ isProduction?: boolean; /** 生产环境下是否仍输出所有级别日志,默认 false (仅输出 warn/error) */ enableAllInProduction?: boolean; /** 是否显示时间戳,默认 true */ showTimestamp?: boolean; /** * 消息展示 API 实例 (可选,适配 antd message 等) * * 传入后,info/warn/error/success 方法会同时调用 UI 提示。 * * @example * ```ts * import { message } from 'antd'; * const logger = createLogger({ prefix: 'App', messageApi: message }); * logger.error('操作失败'); // 同时输出到 console 和 antd message * ``` */ messageApi?: MessageApi; } /** Logger 实例 */ interface Logger { debug(message: string, ...args: unknown[]): void; info(message: string, ...args: unknown[]): void; warn(message: string, ...args: unknown[]): void; error(message: string, ...args: unknown[]): void; /** 成功日志 (info 级别) */ success(message: string, ...args: unknown[]): void; } /** * 创建 Logger 实例 * * @param options - Logger 配置 * @returns Logger 实例 * * @example * ```ts * // 基础用法 (纯 console) * const logger = createLogger({ prefix: 'Auth' }); * logger.info('User logged in', { userId: 123 }); * * // 集成 antd message * import { message } from 'antd'; * const logger = createLogger({ prefix: 'App', messageApi: message }); * logger.error('操作失败'); // console.error + antd message.error * logger.success('保存成功'); // console.info + antd message.success * ``` */ declare function createLogger(options?: LoggerOptions): Logger; /** * 导航 / 面包屑工具函数 * * 提供面包屑生成、菜单数据构建等通用导航功能。 */ /** * 面包屑项 */ interface BreadcrumbItem { /** 显示文本 */ title: string; /** 链接路径 */ path?: string; /** 图标 */ icon?: React.ReactNode; } /** * 路由配置项(简化版) */ interface RouteItem { /** 路径 */ path: string; /** 名称 */ name?: string; /** 图标 */ icon?: React.ReactNode; /** 子路由 */ routes?: RouteItem[]; /** 是否隐藏 */ hideInMenu?: boolean; /** 是否隐藏面包屑 */ hideInBreadcrumb?: boolean; /** 额外数据 */ [key: string]: unknown; } /** * 菜单项 */ interface MenuItem { /** 唯一标识 */ key: string; /** 显示文本 */ label: string; /** 链接路径 */ path?: string; /** 图标 */ icon?: React.ReactNode; /** 子菜单 */ children?: MenuItem[]; /** 是否禁用 */ disabled?: boolean; } /** * 将路径段转换为可读标题 * * @param segment - 路径段 * @returns 可读标题 * * @example * ```ts * pathSegmentToTitle('user-management') // '用户管理' (需要路由配置) 或 'User Management' * pathSegmentToTitle('userList') // 'User List' * ``` */ declare function pathSegmentToTitle(segment: string): string; /** * 根据当前路径和路由配置生成面包屑 * * @param pathname - 当前路径 * @param routes - 路由配置 * @param homeTitle - 首页标题,默认 'Home' * @returns 面包屑项数组 * * @example * ```ts * const breadcrumbs = generateBreadcrumbItems('/system/user/edit/1', routes); * // => [{ title: '首页', path: '/' }, { title: '系统管理', path: '/system' }, { title: '用户管理', path: '/system/user' }, { title: '编辑' }] * ``` */ declare function generateBreadcrumbItems(pathname: string, routes: RouteItem[], homeTitle?: string): BreadcrumbItem[]; /** * 根据路由配置和权限生成菜单数据 * * @param routes - 路由配置 * @param permissions - 用户权限列表(可选,不传则不做权限过滤) * @param options - 配置选项 * @returns 菜单数据 * * @example * ```ts * const menuData = generateMenuData(routes, userPermissions); * ``` */ declare function generateMenuData(routes: RouteItem[], permissions?: string[], options?: { /** 权限字段名,默认 'access' */ accessKey?: string; /** 父路径前缀 */ parentPath?: string; }): MenuItem[]; /** * 在菜单数据中查找匹配路径的菜单项 * * @param menuItems - 菜单数据 * @param path - 要查找的路径 * @returns 匹配的菜单项,未找到返回 null */ declare function findMenuItemByPath(menuItems: MenuItem[], path: string): MenuItem | null; /** * Web Vitals 性能监控工具 * * 提供 Core Web Vitals 性能指标的采集和报告功能。 * 默认仅在开发模式下输出到控制台,也支持自定义上报。 * */ /** * 性能指标数据 */ interface PerformanceMetric { /** 指标名称 */ name: string; /** 指标值 */ value: number; /** 评级 (good / needs-improvement / poor) */ rating?: string; /** 导航类型 */ navigationType?: string; } /** * 性能监控配置 */ interface PerformanceMonitoringOptions { /** 是否启用,默认 false(消费方根据自身环境判断后显式开启) */ enabled?: boolean; /** 指标上报回调 */ onMetric?: (metric: PerformanceMetric) => void; /** 是否在控制台输出,默认 true */ consoleOutput?: boolean; } /** * 初始化性能监控 * * 采集 Core Web Vitals 指标: * - LCP (Largest Contentful Paint): 最大内容绘制时间 * - INP (Interaction to Next Paint): 交互到下一次绘制延迟(2024 年 3 月起取代 FID) * - CLS (Cumulative Layout Shift): 累积布局偏移 * - FCP (First Contentful Paint): 首次内容绘制 * - TTFB (Time to First Byte): 首字节到达时间 * * @param options - 配置选项 * * @example * ```ts * // 开发模式:显式启用并输出到控制台 * initPerformanceMonitoring({ enabled: import.meta.env.DEV }); * * // 生产模式:上报到分析服务 * initPerformanceMonitoring({ * enabled: true, * consoleOutput: false, * onMetric: (metric) => { * analytics.track('web_vital', metric); * }, * }); * ``` */ /** * 清理函数类型,调用后断开所有观察器 */ type PerformanceCleanup = () => void; declare function initPerformanceMonitoring(options?: PerformanceMonitoringOptions): PerformanceCleanup; /** * 权限检查工具函数 */ /** * 检查菜单权限 * * 编码使用冒号分隔层级(与 SDK PermissionConfigCompiler 一致): * - `*` 匹配所有权限 * - `admin:*` 匹配 admin 下的所有子权限 * - `admin:topic` 精确匹配 * * @param userMenus - 用户拥有的菜单权限列表 * @param code - 要检查的权限 code * @returns 是否有权限 * * @example * ```ts * const menus = ['admin:system:user', 'admin:system:role', 'dashboard']; * checkMenuPermission(menus, 'admin:system:user') // true * checkMenuPermission(menus, 'admin:*') // true (有 admin 下的子权限) * checkMenuPermission(menus, 'settings') // false * ``` */ declare function checkMenuPermission(userMenus: string[] | undefined | null, code: string): boolean; /** * 检查按钮权限 * * @param userButtons - 用户拥有的按钮权限列表 * @param code - 要检查的按钮权限 code * @returns 是否有权限 * * @example * ```ts * const buttons = ['user:create', 'user:edit', 'role:view']; * checkButtonPermission(buttons, 'user:create') // true * checkButtonPermission(buttons, 'user:delete') // false * ``` */ declare function checkButtonPermission(userButtons: string[] | undefined | null, code: string): boolean; /** * 批量检查多个权限 (全部满足) * * @param userPermissions - 用户权限列表 * @param codes - 要检查的权限列表 * @returns 是否全部有权限 */ declare function checkAllPermissions(userPermissions: string[] | undefined | null, codes: string[]): boolean; /** * 批量检查多个权限 (任一满足) * * @param userPermissions - 用户权限列表 * @param codes - 要检查的权限列表 * @returns 是否有任一权限 */ declare function checkAnyPermission(userPermissions: string[] | undefined | null, codes: string[]): boolean; /** * 中国行政区划数据工具 * * 将行政区划数据转换为 Ant Design Cascader 组件所需的格式。 * 使用 china-division 包 (optional peer dependency) 或自定义数据源。 * * **注意**: 该模块专为中国行政区划设计 (China-specific)。 * 数据源通过 `setRegionDataSource()` 注入,不直接依赖具体数据包。 */ /** * 级联选项 */ interface CascaderOption { /** 显示文本 */ label: string; /** 值 */ value: string; /** 子选项 */ children?: CascaderOption[]; } /** * 省/自治区/直辖市 */ interface ProvinceItem { code: string; name: string; } /** * 城市 */ interface CityItem { code: string; name: string; provinceCode: string; } /** * 区/县 */ interface AreaItem { code: string; name: string; cityCode: string; provinceCode: string; } /** * 原始地区数据 */ interface RegionDataSource { provinces: ProvinceItem[]; cities: CityItem[]; areas: AreaItem[]; } /** * 地区数据配置 */ interface RegionConfig { /** * Cascader option 的 value 使用哪个字段 * - 'code': 使用行政区划编码 (默认, 如 '110000') * - 'name': 使用名称 (如 '北京市') */ valueField?: 'code' | 'name'; } /** * 重置缓存 (测试用) */ declare function resetRegionCache(): void; /** * 设置数据源 * * 如果使用 china-division 包, 需要在应用初始化时调用此方法设置数据源。 * * @example * ```ts * import provinces from 'china-division/dist/provinces.json'; * import cities from 'china-division/dist/cities.json'; * import areas from 'china-division/dist/areas.json'; * * setRegionDataSource({ provinces, cities, areas }); * ``` */ declare function setRegionDataSource(data: RegionDataSource, config?: RegionConfig): void; /** * 获取省市区三级级联数据 * * @returns Ant Design Cascader 格式的省市区数据 * * @example * ```tsx * import { getRegionData } from '@aspect/shared/utils'; * * * ``` */ declare function getRegionData(): CascaderOption[]; /** * 获取省市二级级联数据 (不含区/县) * * @returns Ant Design Cascader 格式的省市数据 * * @example * ```tsx * * ``` */ declare function getCityData(): CascaderOption[]; /** * 根据地区编码获取名称 * * @param code - 行政区划编码 * @returns 地区名称, 未找到返回 code 本身 * * @example * ```ts * getRegionName('110000'); // => '北京市' * getRegionName('110100'); // => '北京市' (市辖区) * getRegionName('110101'); // => '东城区' * ``` */ declare function getRegionName(code: string): string; /** * 根据编码数组获取完整地址文本 * * @param codes - [省编码, 市编码?, 区编码?] * @param separator - 分隔符, 默认 ' ' * @returns 完整地址文本 * * @example * ```ts * getRegionFullText(['110000', '110100', '110101']); * // => '北京市 北京市 东城区' * * getRegionFullText(['110000', '110100', '110101'], '/'); * // => '北京市/北京市/东城区' * ``` */ declare function getRegionFullText(codes: string[], separator?: string): string; /** * HTML 净化工具函数 * * dompurify 作为可选 peerDependency,使用参数注入模式避免硬依赖。 */ /** DOMPurify sanitize 函数签名 */ type SanitizeFn = (html: string, options?: Record) => string; /** * 初始化 HTML 净化器 * * 在应用启动时调用一次,传入 DOMPurify 实例。 * * @param purify - DOMPurify 实例 (import DOMPurify from 'dompurify') * * @example * ```ts * // 在 app.tsx 中初始化 * import DOMPurify from 'dompurify'; * import { initSanitizer } from '@aspect/shared/utils'; * initSanitizer(DOMPurify); * ``` */ declare function initSanitizer(purify: { sanitize: SanitizeFn; }): void; /** * 净化 HTML 字符串,防止 XSS 攻击 * * 需先通过 `initSanitizer` 初始化 DOMPurify。 * * @param html - 待净化的 HTML 字符串 * @param options - DOMPurify 选项 * @returns 净化后的安全 HTML 字符串 * * @example * ```ts * const safeHtml = sanitizeHtml('

Hello

'); * // '

Hello

' * ``` */ declare function sanitizeHtml(html: string, options?: Record): string; /** * 移除所有 HTML 标签,只保留纯文本 * * @param html - HTML 字符串 * @returns 纯文本 */ declare function stripHtmlTags(html: string): string; /** * localStorage/sessionStorage 安全封装 + TTL + 内存缓存 */ /** 存储类型 */ type StorageType = 'local' | 'session'; /** 存储选项 */ interface StorageOptions { /** 存储类型,默认 'local' */ storageType?: StorageType; /** 过期时间 (毫秒),不设置则永不过期 */ ttl?: number; } /** * 安全读取存储数据 * * @param key - 存储 key * @param storageType - 存储类型,默认 'local' * @returns 解析后的数据或 null * * @example * ```ts * const user = safeGetStorage('currentUser'); * const token = safeGetStorage('token'); * ``` */ declare function safeGetStorage(key: string, storageType?: StorageType): T | null; /** * 安全写入存储数据 * * @param key - 存储 key * @param value - 要存储的数据 * @param options - 存储选项 (TTL 等) * @returns 是否写入成功 * * @example * ```ts * safeSetStorage('user', { id: 1, name: 'test' }); * safeSetStorage('token', 'abc123', { ttl: 7 * 24 * 60 * 60 * 1000 }); // 7天过期 * safeSetStorage('cache', data, { storageType: 'session' }); * ``` */ declare function safeSetStorage(key: string, value: unknown, options?: StorageOptions): boolean; /** * 安全删除存储数据 * * @param key - 存储 key * @param storageType - 存储类型,默认 'local' */ declare function safeRemoveStorage(key: string, storageType?: StorageType): void; /** * 清空指定类型的存储 * * @param storageType - 存储类型,默认 'local' */ declare function clearStorage(storageType?: StorageType): void; /** * 检查存储项是否已过期 * * @param key - 存储 key * @param storageType - 存储类型,默认 'local' * @returns 是否已过期 (不存在也返回 true) */ declare function isStorageExpired(key: string, storageType?: StorageType): boolean; /** * 清理所有已过期的存储项 * * @param storageType - 存储类型,默认 'local' * @returns 清理的条数 */ declare function cleanExpiredStorage(storageType?: StorageType): number; /** * 获取存储空间大小 (估算,单位字节) * * @param storageType - 存储类型,默认 'local' * @returns 估算大小 (字节) */ declare function getStorageSize(storageType?: StorageType): number; /** * 内存缓存配置 */ interface MemoryCacheOptions { /** 最大缓存条数,默认 100 */ maxSize?: number; /** 默认过期时间 (毫秒),默认不过期 */ defaultTtl?: number; } /** * 内存缓存实例 */ interface MemoryCache { /** 获取缓存值 */ get(key: string): T | undefined; /** 设置缓存值 */ set(key: string, value: unknown, ttl?: number): void; /** 删除缓存值 */ delete(key: string): boolean; /** 检查 key 是否存在 (且未过期) */ has(key: string): boolean; /** 清空所有缓存 */ clear(): void; /** 获取当前缓存大小 */ readonly size: number; } /** * 创建内存缓存实例 * * @param options - 缓存配置 * @returns 缓存实例 * * @example * ```ts * const cache = createMemoryCache({ maxSize: 50, defaultTtl: 60000 }); * cache.set('key', { data: 'value' }); * const value = cache.get<{ data: string }>('key'); * ``` */ declare function createMemoryCache(options?: MemoryCacheOptions): MemoryCache; /** * 主题管理工具 * * 提供主题管理的核心逻辑:主题切换、持久化、DOM 更新、系统偏好检测等。 * */ /** * 主题定义 */ interface ThemeDefinition { /** 主题 ID */ id: string; /** 主题名称 */ name: string; /** 是否为暗色主题 */ isDark: boolean; /** 主色调 */ primaryColor?: string; /** 自定义 CSS 变量 */ cssVars?: Record; /** antd 主题 token */ token?: Record; } /** * 主题管理器配置 */ interface ThemeManagerOptions { /** 可用的主题列表 */ themes: ThemeDefinition[]; /** 默认主题 ID */ defaultThemeId?: string; /** 存储 key,默认 'app-theme' */ storageKey?: string; /** 是否跟随系统暗色偏好,默认 false */ followSystem?: boolean; } /** * 主题管理器 */ interface ThemeManager { /** 获取当前主题 */ getCurrentTheme: () => ThemeDefinition; /** 获取当前主题 ID */ getCurrentThemeId: () => string; /** 切换主题 */ setTheme: (themeId: string) => void; /** 获取所有可用主题 */ getThemes: () => ThemeDefinition[]; /** 判断当前是否为暗色主题 */ isDark: () => boolean; /** 切换明暗模式 */ toggleDarkMode: () => void; } /** * 创建主题管理器 * * @param options - 主题管理器配置 * @returns 主题管理器实例 * * @example * ```ts * const themeManager = createThemeManager({ * themes: [ * { id: 'light', name: '明亮', isDark: false, primaryColor: '#1677ff' }, * { id: 'dark', name: '暗色', isDark: true, primaryColor: '#1668dc' }, * ], * defaultThemeId: 'light', * followSystem: true, * }); * * // 切换主题 * themeManager.setTheme('dark'); * // 获取当前主题 * const theme = themeManager.getCurrentTheme(); * ``` */ declare function createThemeManager(options: ThemeManagerOptions): ThemeManager; /** * 将主题应用到 DOM * * - 设置 `` 的 `data-theme` 属性 * - 设置 `` 的 `class` (dark/light) * - 设置 CSS 变量 * * @param theme - 主题定义 */ declare function applyThemeToDom(theme: ThemeDefinition): void; /** * 检测系统是否偏好暗色模式 * * @returns 系统是否偏好暗色模式 */ declare function getSystemPrefersDark(): boolean; /** * 判断主题 ID 是否对应暗色主题 * * @param themeId - 主题 ID * @param themes - 主题列表 * @returns 是否为暗色主题 */ declare function isDarkTheme(themeId: string, themes: ThemeDefinition[]): boolean; /** * 监听系统暗色模式变化 * * @param callback - 变化回调 * @returns 取消监听的函数 * * @example * ```ts * const unwatch = watchSystemDarkMode((isDark) => { * themeManager.setTheme(isDark ? 'dark' : 'light'); * }); * * // 清理 * unwatch(); * ``` */ declare function watchSystemDarkMode(callback: (isDark: boolean) => void): () => void; /** * 通用树操作工具函数 * * 提供对树形结构数据的常用操作:扁平化、查找、过滤、映射、构建等。 * 适用于菜单树、分类树、组织树、权限树等各种树形场景。 * */ /** * 将树形结构扁平化为一维数组 * * @param tree - 树节点数组 * @param childrenKey - 子节点字段名,默认 'children' * @returns 扁平化后的节点数组(不含 children 属性) * * @example * ```ts * const tree = [ * { id: 1, name: 'A', children: [{ id: 2, name: 'B' }] }, * { id: 3, name: 'C' }, * ]; * flattenTree(tree); * // => [{ id: 1, name: 'A' }, { id: 2, name: 'B' }, { id: 3, name: 'C' }] * ``` */ declare function flattenTree>(tree: T[], childrenKey?: string): T[]; /** * 在树中查找满足条件的第一个节点 * * @param tree - 树节点数组 * @param predicate - 匹配函数 * @param childrenKey - 子节点字段名,默认 'children' * @returns 匹配的节点,未找到返回 null * * @example * ```ts * const node = findNodeInTree(tree, (n) => n.id === 5); * ``` */ declare function findNodeInTree>(tree: T[], predicate: (node: T) => boolean, childrenKey?: string): T | null; /** * 在树中查找目标节点的父节点 * * @param tree - 树节点数组 * @param predicate - 目标节点匹配函数 * @param childrenKey - 子节点字段名,默认 'children' * @returns 父节点,未找到或目标在根层级时返回 null * * @example * ```ts * const parent = findParentNode(tree, (n) => n.id === 5); * ``` */ declare function findParentNode>(tree: T[], predicate: (node: T) => boolean, childrenKey?: string): T | null; /** * 过滤树节点,保留匹配节点及其祖先路径 * * 如果子节点匹配,其所有祖先节点也会被保留(即使祖先节点本身不匹配)。 * * @param tree - 树节点数组 * @param predicate - 匹配函数 * @param childrenKey - 子节点字段名,默认 'children' * @returns 过滤后的新树 * * @example * ```ts * const filtered = filterTree(menuTree, (n) => n.visible !== false); * ``` */ declare function filterTree>(tree: T[], predicate: (node: T) => boolean, childrenKey?: string): T[]; /** * 从扁平列表构建树形结构 * * @param list - 扁平节点列表 * @param options - 配置选项 * @returns 树形结构数组 * * @example * ```ts * const list = [ * { id: 1, parentId: 0, name: 'Root' }, * { id: 2, parentId: 1, name: 'Child 1' }, * { id: 3, parentId: 1, name: 'Child 2' }, * ]; * const tree = buildTreeFromFlat(list, { rootParentId: 0 }); * ``` */ declare function buildTreeFromFlat>(list: T[], options?: { /** ID 字段名,默认 'id' */ idKey?: string; /** 父 ID 字段名,默认 'parentId' */ parentIdKey?: string; /** 子节点字段名,默认 'children' */ childrenKey?: string; /** 根节点的 parentId 值,默认 null/undefined/0/'' */ rootParentId?: string | number | null; }): T[]; /** * 映射树的每个节点,生成新树 * * @param tree - 原始树 * @param mapper - 映射函数 * @param childrenKey - 子节点字段名,默认 'children' * @returns 映射后的新树 * * @example * ```ts * const options = mapTree(categories, (node) => ({ * label: node.name, * value: node.id, * })); * ``` */ declare function mapTree, R extends Record>(tree: T[], mapper: (node: T, depth: number) => R, childrenKey?: string): R[]; /** * 判断一个节点是否是另一个节点的后代 * * 单次遍历实现:找到祖先节点后立即在其子树中搜索目标,避免两次全树遍历。 * * @param tree - 树节点数组 * @param ancestorId - 祖先节点 ID * @param targetId - 目标节点 ID * @param idKey - ID 字段名,默认 'id' * @param childrenKey - 子节点字段名,默认 'children' * @returns 是否为后代关系 * * @example * ```ts * isDescendant(tree, 1, 5) // true: 节点 5 是节点 1 的后代 * ``` */ declare function isDescendant>(tree: T[], ancestorId: string | number, targetId: string | number, idKey?: string, childrenKey?: string): boolean; /** * 获取从根到目标节点的路径 * * @param tree - 树节点数组 * @param predicate - 目标节点匹配函数 * @param childrenKey - 子节点字段名,默认 'children' * @returns 路径数组(从根到目标),未找到返回空数组 * * @example * ```ts * const path = getNodePath(tree, (n) => n.id === 5); * // => [rootNode, parentNode, targetNode] * ``` */ declare function getNodePath>(tree: T[], predicate: (node: T) => boolean, childrenKey?: string): T[]; /** * 递归排序树的每一层节点 * * @param tree - 树节点数组 * @param compareFn - 比较函数,同 Array.sort * @param childrenKey - 子节点字段名,默认 'children' * @returns 排序后的新树 * * @example * ```ts * const sorted = sortTree(menuTree, (a, b) => a.orderSeq - b.orderSeq); * ``` */ declare function sortTree>(tree: T[], compareFn: (a: T, b: T) => number, childrenKey?: string): T[]; /** * 遍历树的每个节点(深度优先) * * @param tree - 树节点数组 * @param callback - 回调函数,返回 false 可中止遍历 * @param childrenKey - 子节点字段名,默认 'children' * * @example * ```ts * walkTree(menuTree, (node, depth) => { * console.log(' '.repeat(depth) + node.name); * }); * ``` */ declare function walkTree>(tree: T[], callback: (node: T, depth: number, parent: T | null) => undefined | false, childrenKey?: string): void; /** * URL / 路由工具函数 * * 提供安全的 URL 操作、外部链接处理、查询字符串解析等通用功能。 * */ /** * 安全地在新标签页中打开 URL * * 自动添加 `noopener,noreferrer` 安全属性,防止新窗口通过 window.opener 访问原页面。 * 出于安全考虑,拒绝 `javascript:` / `data:` / `vbscript:` / `file:` 协议。 * * @param url - 要打开的 URL * @param features - 窗口特性字符串(可选) * @returns 新窗口的引用,打开失败返回 null * * @example * ```ts * openInNewTab('https://example.com'); * openInNewTab('/detail/123'); // 相对路径也支持 * ``` */ declare function openInNewTab(url: string, features?: string): Window | null; /** * 标准化外部 URL * * 自动为缺少协议的 URL 补充 `https://` 前缀。 * * @param url - 原始 URL * @returns 标准化后的 URL * * @example * ```ts * normalizeExternalUrl('example.com') // 'https://example.com' * normalizeExternalUrl('http://example.com') // 'http://example.com' * normalizeExternalUrl('https://example.com') // 'https://example.com' * normalizeExternalUrl('//cdn.example.com/a.js') // '//cdn.example.com/a.js' * ``` */ declare function normalizeExternalUrl(url: string): string; /** * 判断是否为外部链接 * * @param url - URL 字符串 * @returns 是否为外部链接 * * @example * ```ts * isExternalUrl('https://example.com') // true * isExternalUrl('http://example.com') // true * isExternalUrl('//cdn.example.com') // true * isExternalUrl('/dashboard') // false * isExternalUrl('about') // false * ``` */ declare function isExternalUrl(url: string): boolean; /** * 拼接公共资源路径 * * @param path - 资源相对路径 * @param baseUrl - 基础 URL,默认为空(使用相对路径) * @returns 完整的资源 URL * * @example * ```ts * getPublicUrl('/images/logo.png', 'https://cdn.example.com') * // => 'https://cdn.example.com/images/logo.png' * * getPublicUrl('images/logo.png') * // => '/images/logo.png' * ``` */ declare function getPublicUrl(path: string, baseUrl?: string): string; /** * 构建查询字符串 * * 自动过滤 null、undefined 和空字符串值。 * * @param params - 参数对象 * @returns 查询字符串(不含 '?') * * @example * ```ts * buildQueryString({ page: 1, keyword: 'test', status: null }) * // => 'page=1&keyword=test' * * buildQueryString({ tags: ['a', 'b'] }) * // => 'tags=a&tags=b' * ``` */ declare function buildQueryString(params: Record): string; /** * 解析查询字符串为对象 * * @param search - 查询字符串(可以带或不带 '?') * @returns 参数对象 * * @example * ```ts * parseQueryString('?page=1&keyword=test') * // => { page: '1', keyword: 'test' } * * parseQueryString('tags=a&tags=b') * // => { tags: ['a', 'b'] } * ``` */ declare function parseQueryString(search: string): Record; /** * 安全地打开外部链接(标准化 + 新标签页) * * @param url - 外部 URL * @returns 新窗口的引用 * * @example * ```ts * openExternalUrl('example.com') // 自动补 https:// 并在新标签页打开 * ``` */ declare function openExternalUrl(url: string): Window | null; /** * 获取资源 URL * * 处理资源路径,支持绝对 URL、data URI 和相对路径。 * 绝对 URL 和 data URI 直接返回,其他路径通过 getPublicUrl 拼接。 * * @param path - 资源路径 * @param baseUrl - 基础 URL(可选),用于拼接相对路径 * @returns 完整的资源 URL 或 undefined * * @example * ```ts * getResourceUrl('https://cdn.example.com/avatar.png') // 直接返回 * getResourceUrl('data:image/png;base64,...') // 直接返回 * getResourceUrl('/uploads/avatar.png', '/api') // '/api/uploads/avatar.png' * getResourceUrl(null) // undefined * ``` */ declare function getResourceUrl(path?: string | null, baseUrl?: string): string | undefined; /** * 通用验证器工具函数 */ /** * 密码强度级别 */ type PasswordStrength = 'weak' | 'medium' | 'strong'; /** * 密码强度检测结果 */ interface PasswordStrengthResult { /** 强度级别 */ strength: PasswordStrength; /** 强度分数 (0-100) */ score: number; /** 建议列表 */ suggestions: string[]; } /** * 密码强度建议消息(可自定义以支持国际化) */ interface PasswordMessages { empty: string; minLength: string; lowercase: string; uppercase: string; digit: string; special: string; } /** * 文件验证选项 */ interface FileValidateOptions { /** 允许的文件类型 (MIME 类型或扩展名) */ allowedTypes?: string[]; /** 最大文件大小 (字节) */ maxSize?: number; } /** * 验证邮箱格式 * * @param email - 邮箱地址 * @returns 是否有效 */ declare function validateEmail(email: string): boolean; /** * 验证中国手机号格式 * * @param phone - 手机号 * @returns 是否有效 */ declare function validatePhone(phone: string): boolean; /** * 验证 URL 格式 * * @param url - URL 字符串 * @returns 是否有效 */ declare function validateURL(url: string): boolean; /** * 检测密码强度 * * @param password - 密码 * @param messages - 自定义建议消息(可选,用于国际化) * @returns 密码强度结果 * * @example * ```ts * const result = validatePasswordStrength('Abc123!@#'); * // { strength: 'strong', score: 85, suggestions: [] } * * // 自定义中文消息 * const result = validatePasswordStrength('abc', { * empty: '请输入密码', * minLength: '密码长度至少8位', * lowercase: '建议包含小写字母', * uppercase: '建议包含大写字母', * digit: '建议包含数字', * special: '建议包含特殊字符', * }); * ``` */ declare function validatePasswordStrength(password: string, messages?: Partial): PasswordStrengthResult; /** * 验证中国身份证号 * * @param idCard - 身份证号 * @returns 是否有效 */ declare function validateIdCard(idCard: string): boolean; /** * 验证银行卡号 (Luhn 算法) * * @param cardNo - 银行卡号 * @returns 是否有效 */ declare function validateBankCard(cardNo: string): boolean; /** * 验证文件类型 * * @param file - 文件对象 * @param allowedTypes - 允许的类型 (MIME 类型或扩展名,如 ['.jpg', '.png', 'image/jpeg']) * @returns 是否有效 */ declare function validateFileType(file: { name: string; type?: string; }, allowedTypes: string[]): boolean; /** * 验证文件大小 * * @param file - 文件对象 * @param maxSize - 最大大小 (字节) * @returns 是否在限制内 */ declare function validateFileSize(file: { size: number; }, maxSize: number): boolean; /** * 验证数字范围 * * @param value - 数值 * @param min - 最小值 (含) * @param max - 最大值 (含) * @returns 是否在范围内 */ declare function validateNumberRange(value: number, min: number, max: number): boolean; /** * ValueEnum / Select Options 转换工具 * * 用于将常量映射表转换为 ProTable valueEnum 格式或 Ant Design Select options 格式。 * 三个项目大量使用 ProTable 的 valueEnum,均有手工转换逻辑。 * */ /** * ProTable valueEnum 项 */ interface ValueEnumItem { /** 显示文本 */ text: string; /** 状态(ProTable 内置:success, error, processing, warning, default) */ status?: 'success' | 'error' | 'processing' | 'warning' | 'default'; /** 颜色 */ color?: string; /** 是否禁用 */ disabled?: boolean; } /** * ProTable valueEnum 类型 */ type ValueEnumMap = Record; /** * Select/Radio 选项 */ interface OptionItem { /** 显示文本 */ label: string; /** 值 */ value: V; /** 颜色(可选) */ color?: string; /** 是否禁用 */ disabled?: boolean; } /** * 常量映射项的通用结构 */ interface ConstantMapItem { text: string; color?: string; status?: 'success' | 'error' | 'processing' | 'warning' | 'default'; disabled?: boolean; } /** * createValueEnum 选项 */ interface CreateValueEnumOptions { /** 当 useOriginalStatus 为 false 时使用的默认 status */ defaultStatus?: 'success' | 'error' | 'processing' | 'warning' | 'default'; /** 是否使用原始映射中的 status 字段,默认 true */ useOriginalStatus?: boolean; } /** * 将常量映射表转换为 ProTable valueEnum 格式 * * @param map - 常量映射表 `{ key: { text, color?, status? } }` * @param options - 可选配置 * @returns ProTable 可用的 valueEnum 对象 * * @example * ```ts * const STATUS_MAP = { * 1: { text: '启用', color: 'green', status: 'success' }, * 0: { text: '禁用', color: 'red', status: 'error' }, * } as const; * * // 使用原始 status * const valueEnum = createValueEnum(STATUS_MAP); * * // 统一使用 Default status * const valueEnum2 = createValueEnum(STATUS_MAP, { * useOriginalStatus: false, * defaultStatus: 'default', * }); * * * ``` */ declare function createValueEnum(map: Record, options?: CreateValueEnumOptions): ValueEnumMap; /** * 从数组创建 valueEnum * * @param arr - 数据数组 * @param valueKey - 值字段名 * @param labelKey - 文本字段名 * @param options - 可选配置 * @returns ProTable 可用的 valueEnum 对象 * * @example * ```ts * const categories = [ * { id: 1, name: '分类A' }, * { id: 2, name: '分类B' }, * ]; * const valueEnum = createValueEnumFromArray(categories, 'id', 'name'); * // => { 1: { text: '分类A' }, 2: { text: '分类B' } } * ``` */ declare function createValueEnumFromArray>(arr: T[], valueKey: keyof T & string, labelKey: keyof T & string, options?: { /** 颜色字段名 */ colorKey?: keyof T & string; /** 状态字段名 */ statusKey?: keyof T & string; }): ValueEnumMap; /** * 将常量映射表转换为 Select/Radio 的 options 数组 * * @param map - 常量映射表 * @returns Select/Radio 可用的 options 数组 * * @example * ```ts * const STATUS_MAP = { * 1: { text: '启用', color: 'green' }, * 0: { text: '禁用', color: 'red' }, * }; * * const options = createSelectOptionsFromMap(STATUS_MAP); * // => [{ label: '启用', value: '1', color: 'green' }, { label: '禁用', value: '0', color: 'red' }] * *