{"version":3,"sources":["../src/hooks/shared-async.ts","../src/hooks/shared-request.ts","../src/hooks/useCrudList.ts","../src/hooks/useDetailPage.ts","../src/hooks/useDetailPageMode.ts","../src/hooks/useDownload.ts","../src/hooks/useFileSelector.ts","../src/hooks/useFileUpload.ts","../src/hooks/useFormModal.ts","../src/hooks/useFormSubmit.ts","../src/hooks/useIntlText.ts","../src/hooks/useListData.ts","../src/hooks/useModal.ts","../src/hooks/useResponsive.ts","../src/hooks/useTableConfig.tsx","../src/hooks/useTableData.ts","../src/hooks/useUserPreference.ts"],"names":["isApiSuccess","useRef","useLatestRef","useCallback","useState","error","useEffect","useMemo","ANIMATION_DURATION","TABLE_DEFAULTS","jsx","Button","Space","Typography","Popconfirm"],"mappings":"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","file":"chunk-4OFSUPHM.cjs","sourcesContent":["/**\n * Hook 内部异步请求共享工具\n *\n * 仅供 hooks 模块内部复用，不对外导出。\n */\n\nimport type { MutableRefObject } from 'react';\n\n/** 将未知错误标准化为 Error 实例 */\nexport function normalizeError(error: unknown): Error {\n  return error instanceof Error ? error : new Error(String(error));\n}\n\n/** 是否为 AbortController 取消导致的错误 */\nfunction isAbortError(error: unknown): boolean {\n  return error instanceof DOMException && error.name === 'AbortError';\n}\n\n/**\n * 启动一次新的可取消请求：\n * - 先取消上一次请求\n * - 再创建并记录新的 controller\n */\nexport function startAbortableRequest(\n  controllerRef: MutableRefObject<AbortController | null>,\n): AbortController {\n  controllerRef.current?.abort();\n  const controller = new AbortController();\n  controllerRef.current = controller;\n  return controller;\n}\n\n/** 在请求未被取消时才更新 loading 状态 */\nfunction setLoadingIfNotAborted(\n  controller: AbortController,\n  setLoading: (loading: boolean) => void,\n): void {\n  if (!controller.signal.aborted) {\n    setLoading(false);\n  }\n}\n\n/**\n * 统一处理可取消请求的异常：\n * - 忽略 abort 错误\n * - 在未取消时落库错误并回调\n */\nexport function handleAbortableRequestError(options: {\n  error: unknown;\n  controller: AbortController;\n  setError: (error: Error) => void;\n  onError?: (error: Error) => void;\n}): void {\n  const { error, controller, setError, onError } = options;\n  if (controller.signal.aborted || isAbortError(error)) {\n    return;\n  }\n\n  const normalized = normalizeError(error);\n  setError(normalized);\n  onError?.(normalized);\n}\n\n/** 统一处理业务操作失败（消息提示 + onError 回调） */\nexport function handleOperationError(options: {\n  error: unknown;\n  fallbackMessage: string;\n  showError?: (message: string) => void;\n  onError?: (error: Error) => void;\n}): Error {\n  const { error, fallbackMessage, showError, onError } = options;\n  const normalized = normalizeError(error);\n  showError?.(normalized.message || fallbackMessage);\n  onError?.(normalized);\n  return normalized;\n}\n\n/**\n * 执行可取消任务并统一处理异常与 loading 结束逻辑。\n *\n * 注意：任务内部应自行处理 `controller.signal.aborted` 的业务分支。\n */\nexport async function runAbortableTask<T>(options: {\n  controller: AbortController;\n  setLoading: (loading: boolean) => void;\n  execute: () => Promise<T>;\n  onError: (error: unknown) => void;\n}): Promise<T | undefined> {\n  const { controller, setLoading, execute, onError } = options;\n  try {\n    return await execute();\n  } catch (error) {\n    onError(error);\n    return undefined;\n  } finally {\n    setLoadingIfNotAborted(controller, setLoading);\n  }\n}\n\n/** 统一处理 API 业务失败（创建 Error + 设置错误 + 回调） */\nexport function handleApiFailure(options: {\n  message?: string;\n  fallbackMessage: string;\n  setError: (error: Error) => void;\n  onError?: (error: Error) => void;\n}): Error {\n  const { message, fallbackMessage, setError, onError } = options;\n  const error = new Error(message || fallbackMessage);\n  setError(error);\n  onError?.(error);\n  return error;\n}\n","/**\n * ProTable 分页请求共享逻辑\n *\n * 被 useTableData 和 useCrudList 共用，消除重复的 request 函数实现。\n * 内部模块，不对外导出。\n */\n\nimport type {\n  ApiResponse,\n  PaginatedData,\n  ProTableResponse,\n} from '../types/api';\nimport { isApiSuccess } from '../utils/api-helpers';\n\nexport interface TableRequestParams {\n  current?: number;\n  pageSize?: number;\n  [key: string]: unknown;\n}\n\n/** 分页请求参数 */\ninterface FetchPaginatedOptions<T, P> {\n  /** ProTable 传入的原始参数 */\n  params: TableRequestParams;\n  /** 排序信息 */\n  sort?: Record<string, 'ascend' | 'descend' | null>;\n  /** 筛选信息 */\n  filter?: TableRequestParams;\n  /** API 请求函数 */\n  fetchApi: (params: P) => Promise<ApiResponse<PaginatedData<T>>>;\n  /** 成功状态码 */\n  successCode: string | number;\n  /** 参数转换器 */\n  transformParams?: (params: TableRequestParams) => P;\n  /** 数据转换器 */\n  transformData?: (list: T[]) => T[];\n}\n\n/**\n * 执行分页数据请求并转换为 ProTable 响应格式\n *\n * @returns ProTable 标准响应 `{ data, success, total }`\n */\nexport async function fetchPaginatedData<T, P = Record<string, unknown>>(\n  options: FetchPaginatedOptions<T, P>,\n): Promise<ProTableResponse<T>> {\n  const {\n    params,\n    sort,\n    filter,\n    fetchApi,\n    successCode,\n    transformParams,\n    transformData,\n  } = options;\n\n  // 解构出 ProTable 特有字段，避免 current 被透传到后端\n  const { current, pageSize, ...restParams } = params;\n\n  const apiParams: P = transformParams\n    ? transformParams({ ...params, sort, filter })\n    : ({\n        pageNo: current ?? 1,\n        pageSize: pageSize ?? 10,\n        ...restParams,\n        sort,\n        filter,\n      } as P);\n\n  const response = await fetchApi(apiParams);\n  const isSuccess = isApiSuccess(response, successCode);\n\n  if (isSuccess && response.data) {\n    const list = transformData\n      ? transformData(response.data.list || [])\n      : response.data.list || [];\n\n    return {\n      data: list,\n      success: true,\n      total: response.data.total || 0,\n    };\n  }\n\n  return { data: [], success: false, total: 0 };\n}\n","/**\n * CRUD 列表管理 Hook\n *\n * 封装 ProTable 列表页常见的完整 CRUD 逻辑：\n * 数据请求、搜索/筛选、删除确认、页面导航等。\n * 比 useTableData 更完整，适用于标准的列表管理页面。\n */\n\nimport { useCallback, useRef } from 'react';\nimport type {\n  ApiResponse,\n  PaginatedData,\n  ProTableResponse,\n} from '../types/api';\nimport { isApiSuccess } from '../utils/api-helpers';\nimport { normalizeError } from './shared-async';\nimport { fetchPaginatedData, type TableRequestParams } from './shared-request';\nimport { useLatestRef } from './useLatestRef';\n\n/**\n * CRUD 列表配置\n */\nexport interface UseCrudListOptions<T, P = Record<string, unknown>> {\n  /** 列表数据请求 API */\n  fetchApi: (params: P) => Promise<ApiResponse<PaginatedData<T>>>;\n  /** 删除单条记录 API */\n  deleteApi?: (id: string | number) => Promise<ApiResponse<unknown>>;\n  /** 批量删除 API */\n  batchDeleteApi?: (ids: (string | number)[]) => Promise<ApiResponse<unknown>>;\n  /** 成功状态码，默认 '200' */\n  successCode?: string | number;\n  /** 请求前的参数转换 */\n  transformParams?: (params: TableRequestParams) => P;\n  /** 响应后的数据转换 */\n  transformData?: (list: T[]) => T[];\n  /** 页面路径前缀（用于导航到创建/编辑/详情页） */\n  basePath?: string;\n  /** 导航函数 */\n  navigate?: (path: string) => void;\n  /** 消息展示函数 */\n  showMessage?: (\n    content: string,\n    type: 'success' | 'error' | 'warning',\n  ) => void;\n  /** 确认弹窗函数 */\n  showConfirm?: (options: {\n    title: string;\n    content: string;\n    onOk: () => Promise<void>;\n  }) => void;\n  /** 请求失败回调 */\n  onError?: (error: Error) => void;\n  /** 自定义文案（用于国际化） */\n  messages?: Partial<CrudListMessages>;\n}\n\n/** CRUD 列表文案配置 */\ninterface CrudListMessages {\n  deleteSuccess: string;\n  deleteFailed: string;\n  batchDeleteSuccess: (count: number) => string;\n  batchDeleteFailed: string;\n  confirmDeleteTitle: string;\n  confirmDeleteContent: (name?: string) => string;\n  confirmBatchDeleteTitle: string;\n  confirmBatchDeleteContent: (count: number) => string;\n}\n\nconst DEFAULT_CRUD_MESSAGES: CrudListMessages = {\n  deleteSuccess: 'Deleted successfully',\n  deleteFailed: 'Delete failed',\n  batchDeleteSuccess: (count) => `Successfully deleted ${count} records`,\n  batchDeleteFailed: 'Batch delete failed',\n  confirmDeleteTitle: 'Confirm Delete',\n  confirmDeleteContent: (name) =>\n    name ? `Delete \"${name}\"?` : 'Delete this record?',\n  confirmBatchDeleteTitle: 'Confirm Batch Delete',\n  confirmBatchDeleteContent: (count) => `Delete ${count} selected records?`,\n};\n\n/**\n * CRUD 列表返回值\n */\nexport interface UseCrudListReturn<T> {\n  /** ProTable 的 request 函数 */\n  request: (\n    params: TableRequestParams,\n    sort?: Record<string, 'ascend' | 'descend' | null>,\n    filter?: TableRequestParams,\n  ) => Promise<ProTableResponse<T>>;\n  /** actionRef - 传给 ProTable */\n  actionRef: React.MutableRefObject<TableActionRef | null>;\n  /** 刷新表格 */\n  reload: () => void;\n  /** 导航到创建页面 */\n  goCreate: () => void;\n  /** 导航到编辑页面 */\n  goEdit: (id: string | number) => void;\n  /** 导航到详情页面 */\n  goDetail: (id: string | number) => void;\n  /** 删除单条记录（带确认弹窗） */\n  handleDelete: (id: string | number, name?: string) => void;\n  /** 批量删除（带确认弹窗） */\n  handleBatchDelete: (ids: (string | number)[]) => void;\n}\n\ninterface TableActionRef {\n  reload?: () => void;\n  reloadAndRest?: () => void;\n  clearSelected?: () => void;\n}\n\n/**\n * CRUD 列表管理 Hook\n *\n * @example\n * ```tsx\n * const {\n *   request, actionRef, reload,\n *   goCreate, goEdit, goDetail,\n *   handleDelete,\n * } = useCrudList({\n *   fetchApi: getUserList,\n *   deleteApi: deleteUser,\n *   basePath: '/system/user',\n *   navigate: history.push,\n *   showMessage: (content, type) => message[type](content),\n *   showConfirm: ({ title, content, onOk }) => Modal.confirm({ title, content, onOk }),\n * });\n *\n * <ProTable\n *   actionRef={actionRef}\n *   request={request}\n *   toolBarRender={() => [\n *     <Button key=\"add\" type=\"primary\" onClick={goCreate}>新建</Button>\n *   ]}\n * />\n * ```\n */\nexport function useCrudList<T, P = Record<string, unknown>>(\n  options: UseCrudListOptions<T, P>,\n): UseCrudListReturn<T> {\n  const { fetchApi, successCode = '200', basePath = '', navigate } = options;\n\n  const actionRef = useRef<TableActionRef | null>(null);\n\n  // 用 useLatestRef 稳定所有可能不稳定的回调和对象引用\n  const transformParamsRef = useLatestRef(options.transformParams);\n  const transformDataRef = useLatestRef(options.transformData);\n  const onErrorRef = useLatestRef(options.onError);\n  const deleteApiRef = useLatestRef(options.deleteApi);\n  const batchDeleteApiRef = useLatestRef(options.batchDeleteApi);\n  const showMessageRef = useLatestRef(options.showMessage);\n  const showConfirmRef = useLatestRef(options.showConfirm);\n  const msgRef = useLatestRef({\n    ...DEFAULT_CRUD_MESSAGES,\n    ...options.messages,\n  });\n\n  const request = useCallback(\n    async (\n      params: TableRequestParams,\n      sort?: Record<string, 'ascend' | 'descend' | null>,\n      filter?: TableRequestParams,\n    ): Promise<ProTableResponse<T>> => {\n      try {\n        return await fetchPaginatedData<T, P>({\n          params,\n          sort,\n          filter,\n          fetchApi,\n          successCode,\n          transformParams: transformParamsRef.current,\n          transformData: transformDataRef.current,\n        });\n      } catch (error) {\n        onErrorRef.current?.(normalizeError(error));\n        return { data: [], success: false, total: 0 };\n      }\n    },\n    [fetchApi, successCode, onErrorRef, transformDataRef, transformParamsRef],\n  );\n\n  const reload = useCallback(() => {\n    actionRef.current?.reload?.();\n  }, []);\n\n  const goCreate = useCallback(() => {\n    if (basePath && navigate) {\n      navigate(`${basePath}/create`);\n    }\n  }, [basePath, navigate]);\n\n  const goEdit = useCallback(\n    (id: string | number) => {\n      if (basePath && navigate) {\n        navigate(`${basePath}/edit/${id}`);\n      }\n    },\n    [basePath, navigate],\n  );\n\n  const goDetail = useCallback(\n    (id: string | number) => {\n      if (basePath && navigate) {\n        navigate(`${basePath}/detail/${id}`);\n      }\n    },\n    [basePath, navigate],\n  );\n\n  const handleDelete = useCallback(\n    (id: string | number, name?: string) => {\n      const deleteApi = deleteApiRef.current;\n      if (!deleteApi) return;\n\n      const msg = msgRef.current;\n      const doDelete = async () => {\n        try {\n          const response = await deleteApi(id);\n          const isSuccess = isApiSuccess(response, successCode);\n          if (isSuccess) {\n            showMessageRef.current?.(msg.deleteSuccess, 'success');\n            reload();\n          } else {\n            const errorMessage =\n              response.msg ||\n              response.message ||\n              response.errorMessage ||\n              msg.deleteFailed;\n            showMessageRef.current?.(errorMessage, 'error');\n          }\n        } catch (error) {\n          const err = normalizeError(error);\n          showMessageRef.current?.(err.message || msg.deleteFailed, 'error');\n        }\n      };\n\n      if (showConfirmRef.current) {\n        showConfirmRef.current({\n          title: msg.confirmDeleteTitle,\n          content: msg.confirmDeleteContent(name),\n          onOk: doDelete,\n        });\n      } else {\n        doDelete();\n      }\n    },\n    [reload, successCode, deleteApiRef, msgRef, showConfirmRef, showMessageRef],\n  );\n\n  const handleBatchDelete = useCallback(\n    (ids: (string | number)[]) => {\n      const batchDeleteApi = batchDeleteApiRef.current;\n      if (!batchDeleteApi || ids.length === 0) return;\n\n      const msg = msgRef.current;\n      const doDelete = async () => {\n        try {\n          const response = await batchDeleteApi(ids);\n          const isSuccess = isApiSuccess(response, successCode);\n          if (isSuccess) {\n            showMessageRef.current?.(\n              msg.batchDeleteSuccess(ids.length),\n              'success',\n            );\n            actionRef.current?.clearSelected?.();\n            reload();\n          } else {\n            const errorMessage =\n              response.msg ||\n              response.message ||\n              response.errorMessage ||\n              msg.batchDeleteFailed;\n            showMessageRef.current?.(errorMessage, 'error');\n          }\n        } catch (error) {\n          const err = normalizeError(error);\n          showMessageRef.current?.(\n            err.message || msg.batchDeleteFailed,\n            'error',\n          );\n        }\n      };\n\n      if (showConfirmRef.current) {\n        showConfirmRef.current({\n          title: msg.confirmBatchDeleteTitle,\n          content: msg.confirmBatchDeleteContent(ids.length),\n          onOk: doDelete,\n        });\n      } else {\n        doDelete();\n      }\n    },\n    [\n      reload,\n      successCode,\n      batchDeleteApiRef,\n      msgRef,\n      showConfirmRef,\n      showMessageRef,\n    ],\n  );\n\n  return {\n    request,\n    actionRef,\n    reload,\n    goCreate,\n    goEdit,\n    goDetail,\n    handleDelete,\n    handleBatchDelete,\n  };\n}\n","/**\n * 详情页数据管理 Hook\n *\n */\n\nimport type { Dispatch, SetStateAction } from 'react';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport type { ApiResponse } from '../types/api';\nimport { isApiSuccess } from '../utils/api-helpers';\nimport {\n  handleAbortableRequestError,\n  handleApiFailure,\n  runAbortableTask,\n  startAbortableRequest,\n} from './shared-async';\nimport { useLatestRef } from './useLatestRef';\n\n/**\n * useDetailPage 配置\n */\nexport interface UseDetailPageOptions<T> {\n  /** 详情数据请求 API */\n  fetchApi: (id: string | number) => Promise<ApiResponse<T>>;\n  /** 记录 ID */\n  id: string | number | undefined;\n  /** 是否在 ID 变化时自动请求，默认 true */\n  autoFetch?: boolean;\n  /** 成功状态码，默认 '200' */\n  successCode?: string | number;\n  /** 数据转换 */\n  transformData?: (data: T) => T;\n  /** 请求成功回调 */\n  onSuccess?: (data: T) => void;\n  /** 请求失败回调 */\n  onError?: (error: Error) => void;\n}\n\n/**\n * useDetailPage 返回值\n */\nexport interface UseDetailPageReturn<T> {\n  /** 详情数据 */\n  data: T | null;\n  /** 加载中状态 */\n  loading: boolean;\n  /** 错误信息 */\n  error: Error | null;\n  /** 手动获取指定 ID 的数据（适用于 autoFetch: false 场景） */\n  fetch: (id: string | number) => Promise<void>;\n  /** 手动刷新当前数据 */\n  refresh: () => Promise<void>;\n  /** 手动设置数据 */\n  setData: Dispatch<SetStateAction<T | null>>;\n}\n\n/**\n * 详情页数据管理 Hook\n *\n * @example\n * ```tsx\n * const { data, loading, error, refresh } = useDetailPage({\n *   fetchApi: (id) => getUserDetail(id),\n *   id: params.id,\n *   onError: (err) => message.error(err.message),\n * });\n * ```\n */\nexport function useDetailPage<T>(\n  options: UseDetailPageOptions<T>,\n): UseDetailPageReturn<T> {\n  const { fetchApi, id, autoFetch = true, successCode = '200' } = options;\n\n  const [data, setData] = useState<T | null>(null);\n  const [loading, setLoading] = useState(false);\n  const [error, setError] = useState<Error | null>(null);\n\n  // 记录当前 ID，用于 refresh 和手动 fetch 场景\n  const currentIdRef = useLatestRef(id);\n\n  // AbortController 引用，用于取消进行中的请求\n  const abortControllerRef = useRef<AbortController | null>(null);\n\n  // 用 useLatestRef 稳定回调引用，防止内联函数导致无限循环\n  const fetchApiRef = useLatestRef(fetchApi);\n  const transformDataRef = useLatestRef(options.transformData);\n  const onSuccessRef = useLatestRef(options.onSuccess);\n  const onErrorRef = useLatestRef(options.onError);\n\n  const doFetch = useCallback(\n    async (targetId: string | number) => {\n      const controller = startAbortableRequest(abortControllerRef);\n\n      setLoading(true);\n      setError(null);\n\n      await runAbortableTask({\n        controller,\n        setLoading,\n        execute: async () => {\n          const response = await fetchApiRef.current(targetId);\n\n          // 请求已被取消，忽略结果\n          if (controller.signal.aborted) return;\n\n          const isSuccess = isApiSuccess(response, successCode);\n\n          if (isSuccess && response.data) {\n            const result = transformDataRef.current\n              ? transformDataRef.current(response.data)\n              : response.data;\n            setData(result);\n            onSuccessRef.current?.(result);\n          } else {\n            handleApiFailure({\n              message:\n                response.msg || response.message || response.errorMessage,\n              fallbackMessage: 'Failed to fetch detail',\n              setError,\n              onError: onErrorRef.current,\n            });\n          }\n        },\n        onError: (error) =>\n          handleAbortableRequestError({\n            error,\n            controller,\n            setError,\n            onError: onErrorRef.current,\n          }),\n      });\n    },\n    [successCode, fetchApiRef, onErrorRef, onSuccessRef, transformDataRef],\n  );\n\n  /** 手动获取指定 ID 的数据 */\n  const fetchById = useCallback(\n    async (targetId: string | number) => {\n      currentIdRef.current = targetId;\n      await doFetch(targetId);\n    },\n    [doFetch, currentIdRef],\n  );\n\n  /** 刷新当前数据 */\n  const refresh = useCallback(async () => {\n    const currentId = currentIdRef.current;\n    if (currentId !== undefined && currentId !== null) {\n      await doFetch(currentId);\n    }\n  }, [doFetch, currentIdRef]);\n\n  useEffect(() => {\n    if (autoFetch && id !== undefined && id !== null) {\n      doFetch(id);\n    }\n    // 组件卸载或 id 变化时取消进行中的请求\n    return () => {\n      abortControllerRef.current?.abort();\n    };\n  }, [autoFetch, id, doFetch]);\n\n  return { data, loading, error, fetch: fetchById, refresh, setData };\n}\n","/**\n * 详情页模式管理 Hook\n *\n * 管理详情页的 create / edit / view 三态切换、表单提交处理。\n * 与 useDetailPage（数据获取）互补，专注于页面交互逻辑。\n */\n\nimport { useCallback, useMemo, useState } from 'react';\nimport type { ApiResponse } from '../types/api';\nimport { handleOperationError } from './shared-async';\nimport { useLatestRef } from './useLatestRef';\n\n/**\n * 页面模式\n */\nexport type PageMode = 'create' | 'edit' | 'view';\n\n/**\n * DetailPageMode 文案配置（支持国际化）\n */\nexport interface DetailPageModeMessages {\n  /** 创建成功提示，默认 'Created successfully' */\n  createSuccess: string;\n  /** 更新成功提示，默认 'Updated successfully' */\n  updateSuccess: string;\n  /** 操作失败提示，默认 'Operation failed' */\n  operationFailed: string;\n  /** 缺少 API 函数错误提示，默认 'Config error: missing API function' */\n  missingApi: string;\n}\n\nconst DEFAULT_DETAIL_PAGE_MESSAGES: DetailPageModeMessages = {\n  createSuccess: 'Created successfully',\n  updateSuccess: 'Updated successfully',\n  operationFailed: 'Operation failed',\n  missingApi: 'Config error: missing API function',\n};\n\n/**\n * useDetailPageMode 配置\n */\nexport interface UseDetailPageModeOptions<T = Record<string, unknown>> {\n  /** 当前记录 ID（有 ID 且非 create 模式时为编辑/查看模式） */\n  id?: string | number;\n  /** 创建 API */\n  createApi?: (data: T) => Promise<ApiResponse<unknown>>;\n  /** 更新 API */\n  updateApi?: (id: string | number, data: T) => Promise<ApiResponse<unknown>>;\n  /** 成功状态码，默认 '200' */\n  successCode?: string | number;\n  /** 初始模式，不传则根据 id 自动判断 */\n  initialMode?: PageMode;\n  /** 导航函数（返回上一页） */\n  goBack?: () => void;\n  /** 消息展示函数 */\n  showMessage?: (content: string, type: 'success' | 'error') => void;\n  /** 自定义文案（支持国际化） */\n  messages?: Partial<DetailPageModeMessages>;\n  /** 提交成功回调 */\n  onSuccess?: (mode: PageMode, data: unknown) => void;\n  /** 提交失败回调 */\n  onError?: (error: Error) => void;\n}\n\n/**\n * useDetailPageMode 返回值\n */\nexport interface UseDetailPageModeReturn<T = Record<string, unknown>> {\n  /** 当前页面模式 */\n  mode: PageMode;\n  /** 是否为创建模式 */\n  isCreate: boolean;\n  /** 是否为编辑模式 */\n  isEdit: boolean;\n  /** 是否为查看模式 */\n  isView: boolean;\n  /** 表单是否只读 */\n  readonly: boolean;\n  /** 切换模式 */\n  setMode: (mode: PageMode) => void;\n  /** 从查看切换到编辑 */\n  switchToEdit: () => void;\n  /** 提交中状态 */\n  submitting: boolean;\n  /** 提交表单 */\n  handleSubmit: (data: T) => Promise<boolean>;\n  /** 返回上一页 */\n  handleBack: () => void;\n}\n\n/**\n * 详情页模式管理 Hook\n *\n * @example\n * ```tsx\n * const {\n *   mode, isCreate, readonly, submitting,\n *   handleSubmit, handleBack, switchToEdit,\n * } = useDetailPageMode({\n *   id: params.id,\n *   createApi: createUser,\n *   updateApi: (id, data) => updateUser(id, data),\n *   goBack: () => history.push('/user/list'),\n *   showMessage: (content, type) => message[type](content),\n *   onSuccess: () => actionRef.current?.reload(),\n * });\n *\n * <ProForm\n *   readonly={readonly}\n *   loading={submitting}\n *   onFinish={handleSubmit}\n * />\n * ```\n */\nexport function useDetailPageMode<T = Record<string, unknown>>(\n  options: UseDetailPageModeOptions<T>,\n): UseDetailPageModeReturn<T> {\n  const { id, successCode = '200' } = options;\n\n  // 用 useLatestRef 稳定文案和回调引用，避免每次渲染重建对象导致 useCallback 失效\n  const msgRef = useLatestRef<DetailPageModeMessages>({\n    ...DEFAULT_DETAIL_PAGE_MESSAGES,\n    ...options.messages,\n  });\n\n  const createApiRef = useLatestRef(options.createApi);\n  const updateApiRef = useLatestRef(options.updateApi);\n  const showMessageRef = useLatestRef(options.showMessage);\n  const onSuccessRef = useLatestRef(options.onSuccess);\n  const onErrorRef = useLatestRef(options.onError);\n  const goBackRef = useLatestRef(options.goBack);\n\n  // 自动推断初始模式\n  const defaultMode: PageMode = options.initialMode ?? (id ? 'view' : 'create');\n  const [mode, setMode] = useState<PageMode>(defaultMode);\n  const [submitting, setSubmitting] = useState(false);\n\n  const isCreate = mode === 'create';\n  const isEdit = mode === 'edit';\n  const isView = mode === 'view';\n  const readonly = isView;\n\n  const switchToEdit = useCallback(() => {\n    setMode('edit');\n  }, []);\n\n  const handleSubmit = useCallback(\n    async (data: T): Promise<boolean> => {\n      const msg = msgRef.current;\n      setSubmitting(true);\n      try {\n        let response: ApiResponse<unknown>;\n\n        if (isCreate && createApiRef.current) {\n          response = await createApiRef.current(data);\n        } else if (isEdit && updateApiRef.current && id) {\n          response = await updateApiRef.current(id, data);\n        } else {\n          showMessageRef.current?.(msg.missingApi, 'error');\n          return false;\n        }\n\n        const isSuccess = String(response.code) === String(successCode);\n        if (isSuccess) {\n          showMessageRef.current?.(\n            isCreate ? msg.createSuccess : msg.updateSuccess,\n            'success',\n          );\n          onSuccessRef.current?.(mode, response.data);\n          return true;\n        }\n\n        showMessageRef.current?.(response.msg || msg.operationFailed, 'error');\n        return false;\n      } catch (error) {\n        handleOperationError({\n          error,\n          fallbackMessage: msg.operationFailed,\n          showError: (message) => showMessageRef.current?.(message, 'error'),\n          onError: onErrorRef.current,\n        });\n        return false;\n      } finally {\n        setSubmitting(false);\n      }\n    },\n    [\n      isCreate,\n      isEdit,\n      id,\n      successCode,\n      mode,\n      createApiRef,\n      msgRef,\n      onErrorRef,\n      onSuccessRef,\n      showMessageRef,\n      updateApiRef,\n    ],\n  );\n\n  const handleBack = useCallback(() => {\n    goBackRef.current?.();\n  }, [goBackRef]);\n\n  return useMemo(\n    () => ({\n      mode,\n      isCreate,\n      isEdit,\n      isView,\n      readonly,\n      setMode,\n      switchToEdit,\n      submitting,\n      handleSubmit,\n      handleBack,\n    }),\n    [\n      mode,\n      isCreate,\n      isEdit,\n      isView,\n      readonly,\n      switchToEdit,\n      submitting,\n      handleSubmit,\n      handleBack,\n    ],\n  );\n}\n","/**\n * 文件下载 Hook\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\n\n/** 下载后延迟释放 Object URL 的等待时间 (ms) */\nconst URL_REVOKE_DELAY = 10_000;\n\n/**\n * useDownload 返回值\n */\nexport interface UseDownloadReturn {\n  /** 下载中状态 */\n  downloading: boolean;\n  /** 执行下载 (从 URL) */\n  downloadFromUrl: (url: string, filename?: string) => Promise<void>;\n  /** 执行下载 (从 Blob) */\n  downloadFromBlob: (blob: Blob, filename: string) => void;\n  /** 执行下载 (从 API 响应) */\n  downloadFromApi: (\n    apiFn: () => Promise<Response | Blob>,\n    filename?: string,\n  ) => Promise<void>;\n  /** 下载 JSON 数据为文件 */\n  downloadJSON: (\n    data: unknown,\n    filename: string,\n    options?: DownloadJSONOptions,\n  ) => void;\n}\n\n/**\n * downloadJSON 选项\n */\nexport interface DownloadJSONOptions {\n  /** 是否在文件名中添加时间戳，默认 true */\n  addTimestamp?: boolean;\n  /** 日期格式函数（默认使用 ISO 日期格式 YYYYMMDDHHmmss） */\n  formatDate?: (date: Date) => string;\n}\n\n/**\n * 从 Content-Disposition 头中解析文件名\n */\nfunction parseFilenameFromHeader(\n  contentDisposition: string | null,\n): string | null {\n  if (!contentDisposition) return null;\n\n  // 尝试 filename*=UTF-8''xxx 格式\n  const utf8Match = contentDisposition.match(/filename\\*=UTF-8''([^;]+)/i);\n  if (utf8Match?.[1]) {\n    return decodeURIComponent(utf8Match[1]);\n  }\n\n  // 尝试 filename=\"xxx\" 格式\n  const quotedMatch = contentDisposition.match(/filename=\"([^\"]+)\"/i);\n  if (quotedMatch?.[1]) {\n    return quotedMatch[1];\n  }\n\n  // 尝试 filename=xxx 格式\n  const plainMatch = contentDisposition.match(/filename=([^;\\s]+)/i);\n  if (plainMatch?.[1]) {\n    return plainMatch[1];\n  }\n\n  return null;\n}\n\n/**\n * 触发浏览器下载（延迟释放 Object URL，确保下载已启动）\n *\n * @returns 清理函数，可在组件卸载时调用以释放资源\n */\nfunction triggerDownload(\n  blob: Blob,\n  filename: string,\n): ReturnType<typeof setTimeout> {\n  const url = URL.createObjectURL(blob);\n  const link = document.createElement('a');\n  link.href = url;\n  link.download = filename;\n  link.style.display = 'none';\n  document.body.appendChild(link);\n  link.click();\n  document.body.removeChild(link);\n  // 延迟释放 — 浏览器需要时间启动下载，立即释放可能导致下载失败\n  return setTimeout(() => URL.revokeObjectURL(url), URL_REVOKE_DELAY);\n}\n\n/**\n * 文件下载 Hook\n *\n * 支持从 URL、Blob、API 响应等多种方式下载文件。\n *\n * @example\n * ```tsx\n * const { downloading, downloadFromUrl, downloadFromApi } = useDownload();\n *\n * // 从 URL 下载\n * <Button onClick={() => downloadFromUrl('/api/export/users', 'users.xlsx')}>\n *   导出\n * </Button>\n *\n * // 从 API 下载\n * <Button\n *   loading={downloading}\n *   onClick={() => downloadFromApi(() => exportUsers(), 'users.xlsx')}\n * >\n *   导出\n * </Button>\n * ```\n */\nexport function useDownload(): UseDownloadReturn {\n  const [downloading, setDownloading] = useState(false);\n  const timersRef = useRef<Set<ReturnType<typeof setTimeout>>>(new Set());\n\n  // 组件卸载时清理所有 pending timers\n  useEffect(() => {\n    return () => {\n      for (const timer of timersRef.current) {\n        clearTimeout(timer);\n      }\n      timersRef.current.clear();\n    };\n  }, []);\n\n  /** 跟踪下载定时器，完成后自动从集合中移除 */\n  const trackDownload = useCallback((blob: Blob, filename: string) => {\n    const timer = triggerDownload(blob, filename);\n    timersRef.current.add(timer);\n    // timer 到期后自动移除\n    setTimeout(() => timersRef.current.delete(timer), URL_REVOKE_DELAY + 500);\n  }, []);\n\n  const downloadFromBlob = useCallback(\n    (blob: Blob, filename: string) => {\n      trackDownload(blob, filename);\n    },\n    [trackDownload],\n  );\n\n  const downloadFromUrl = useCallback(\n    async (url: string, filename?: string) => {\n      setDownloading(true);\n      try {\n        const response = await fetch(url);\n        if (!response.ok) {\n          throw new Error(`Download failed: HTTP ${response.status}`);\n        }\n\n        const blob = await response.blob();\n        const name =\n          filename ||\n          parseFilenameFromHeader(\n            response.headers.get('content-disposition'),\n          ) ||\n          'download';\n\n        trackDownload(blob, name);\n      } finally {\n        setDownloading(false);\n      }\n    },\n    [trackDownload],\n  );\n\n  const downloadFromApi = useCallback(\n    async (apiFn: () => Promise<Response | Blob>, filename?: string) => {\n      setDownloading(true);\n      try {\n        const result = await apiFn();\n\n        if (result instanceof Blob) {\n          trackDownload(result, filename || 'download');\n          return;\n        }\n\n        // Response 对象\n        if (result instanceof Response) {\n          if (!result.ok) {\n            throw new Error(`Download failed: HTTP ${result.status}`);\n          }\n          const blob = await result.blob();\n          const name =\n            filename ||\n            parseFilenameFromHeader(\n              result.headers.get('content-disposition'),\n            ) ||\n            'download';\n          trackDownload(blob, name);\n        }\n      } finally {\n        setDownloading(false);\n      }\n    },\n    [trackDownload],\n  );\n\n  const downloadJSON = useCallback(\n    (data: unknown, filename: string, options?: DownloadJSONOptions) => {\n      const { addTimestamp = true, formatDate: formatDateFn } = options ?? {};\n\n      let finalFilename = filename;\n      if (addTimestamp) {\n        const now = new Date();\n        const timestamp = formatDateFn\n          ? formatDateFn(now)\n          : `${now.getFullYear()}${String(now.getMonth() + 1).padStart(2, '0')}${String(now.getDate()).padStart(2, '0')}${String(now.getHours()).padStart(2, '0')}${String(now.getMinutes()).padStart(2, '0')}${String(now.getSeconds()).padStart(2, '0')}`;\n        const parts = finalFilename.split('.');\n        if (parts.length > 1) {\n          const ext = parts.pop();\n          finalFilename = `${parts.join('.')}_${timestamp}.${ext}`;\n        } else {\n          finalFilename = `${finalFilename}_${timestamp}.json`;\n        }\n      }\n\n      // JSON.stringify 可能抛出异常（循环引用、BigInt 等），需捕获\n      const jsonStr = JSON.stringify(data, null, 2);\n      const blob = new Blob([jsonStr], { type: 'application/json' });\n      trackDownload(blob, finalFilename);\n    },\n    [trackDownload],\n  );\n\n  return {\n    downloading,\n    downloadFromUrl,\n    downloadFromBlob,\n    downloadFromApi,\n    downloadJSON,\n  };\n}\n","/**\n * 文件选择 Hook\n *\n * 提供浏览器原生文件选择能力，通过动态创建 input[type=file] 实现。\n * 与 useFileUpload（管理上传过程）互补，本 hook 仅负责文件选择和读取。\n *\n * 提供文件选择、验证和预览等功能\n */\n\nimport { useCallback, useRef } from 'react';\n\n/**\n * 文件选择选项\n */\nexport interface FileSelectOptions {\n  /** 接受的文件类型，如 '.json', '.csv', 'image/*' */\n  accept?: string;\n  /** 是否允许多选 */\n  multiple?: boolean;\n}\n\n/**\n * useFileSelector 返回值\n */\nexport interface UseFileSelectorReturn {\n  /** 选择并读取 JSON 文件，返回解析后的数据 */\n  selectJSONFile: (options?: FileSelectOptions) => Promise<unknown>;\n  /** 选择文件，返回 File 对象 */\n  selectFile: (options?: FileSelectOptions) => Promise<File>;\n  /** 选择多个文件，返回 File 数组 */\n  selectFiles: (\n    options?: Omit<FileSelectOptions, 'multiple'>,\n  ) => Promise<File[]>;\n}\n\n/**\n * 创建隐藏的 file input 元素，统一处理并发防护和清理逻辑\n *\n * @param pendingRef - 并发防护 ref\n * @param accept - 文件类型过滤\n * @param multiple - 是否允许多选\n * @param onFiles - 文件选中后的回调\n */\nfunction openFileDialog<T>(\n  pendingRef: React.MutableRefObject<boolean>,\n  accept: string,\n  multiple: boolean,\n  onFiles: (files: FileList) => T | Promise<T>,\n): Promise<T> {\n  if (pendingRef.current) {\n    return Promise.reject(new Error('File selection in progress'));\n  }\n  pendingRef.current = true;\n\n  return new Promise<T>((resolve, reject) => {\n    const input = document.createElement('input');\n    input.type = 'file';\n    input.style.display = 'none';\n    input.accept = accept;\n    input.multiple = multiple;\n    document.body.appendChild(input);\n\n    let settled = false;\n\n    const settle = () => {\n      if (!settled) {\n        settled = true;\n        pendingRef.current = false;\n        // 清理 input 元素和事件\n        input.onchange = null;\n        input.removeEventListener('cancel', handleCancel);\n        if (document.body.contains(input)) {\n          document.body.removeChild(input);\n        }\n      }\n    };\n\n    const handleCancel = () => {\n      if (!settled) {\n        settle();\n        reject(new Error('Selection cancelled'));\n      }\n    };\n\n    input.addEventListener('cancel', handleCancel);\n\n    input.onchange = async (e: Event) => {\n      const files = (e.target as HTMLInputElement).files;\n      settle();\n\n      if (!files || files.length === 0) {\n        reject(new Error('No file selected'));\n        return;\n      }\n\n      try {\n        const result = await onFiles(files);\n        resolve(result);\n      } catch (err) {\n        reject(err);\n      }\n    };\n\n    input.click();\n  });\n}\n\n/**\n * 文件选择 Hook\n *\n * 通过动态创建隐藏的 input[type=file] 元素来选择文件。\n * 内置并发防护，同一时间只允许一个文件选择操作。\n *\n * @example\n * ```tsx\n * const { selectJSONFile, selectFile } = useFileSelector();\n *\n * // 选择 JSON 文件\n * const data = await selectJSONFile();\n *\n * // 选择任意文件\n * const file = await selectFile({ accept: '.csv,.xlsx' });\n * ```\n */\nexport function useFileSelector(): UseFileSelectorReturn {\n  // 并发防护：同一时间只允许一个文件选择操作\n  const pendingRef = useRef(false);\n\n  const selectJSONFile = useCallback(\n    (options?: FileSelectOptions): Promise<unknown> =>\n      openFileDialog(\n        pendingRef,\n        options?.accept || '.json',\n        false,\n        async (files) => {\n          const file = files[0];\n          const text = await file.text();\n          try {\n            return JSON.parse(text);\n          } catch {\n            throw new Error('Invalid JSON file');\n          }\n        },\n      ),\n    [],\n  );\n\n  const selectFile = useCallback(\n    (options?: FileSelectOptions): Promise<File> =>\n      openFileDialog(\n        pendingRef,\n        options?.accept || '*',\n        false,\n        (files) => files[0],\n      ),\n    [],\n  );\n\n  const selectFiles = useCallback(\n    (options?: Omit<FileSelectOptions, 'multiple'>): Promise<File[]> =>\n      openFileDialog(pendingRef, options?.accept || '*', true, (files) =>\n        Array.from(files),\n      ),\n    [],\n  );\n\n  return { selectJSONFile, selectFile, selectFiles };\n}\n","/**\n * 文件上传 Hook\n */\n\nimport { useCallback, useRef, useState } from 'react';\nimport { useLatestRef } from './useLatestRef';\n\n/**\n * useFileUpload 配置\n */\nexport interface UseFileUploadOptions<R = unknown> {\n  /**\n   * 上传 API 函数\n   *\n   * @param file - 文件对象\n   * @param onProgress - 进度回调\n   * @param signal - AbortSignal，可用于取消上传\n   */\n  uploadApi: (\n    file: File,\n    onProgress?: (percent: number) => void,\n    signal?: AbortSignal,\n  ) => Promise<R>;\n  /** 允许的文件类型 (如 ['.jpg', '.png', 'image/*']) */\n  allowedTypes?: string[];\n  /** 最大文件大小 (字节) */\n  maxSize?: number;\n  /** 上传成功回调 */\n  onSuccess?: (result: R, file: File) => void;\n  /** 上传失败回调 */\n  onError?: (error: Error, file: File) => void;\n}\n\n/**\n * useFileUpload 返回值\n */\nexport interface UseFileUploadReturn<R = unknown> {\n  /** 上传中状态 */\n  uploading: boolean;\n  /** 上传进度 (0-100) */\n  progress: number;\n  /** 执行上传 */\n  upload: (file: File) => Promise<R | undefined>;\n  /** 取消上传 */\n  abort: () => void;\n  /** 重置状态 */\n  reset: () => void;\n}\n\n/**\n * 文件上传 Hook\n *\n * 管理文件上传的进度、类型验证、大小限制和取消功能。\n *\n * @example\n * ```tsx\n * const { uploading, progress, upload } = useFileUpload({\n *   uploadApi: (file) => uploadFile(file),\n *   allowedTypes: ['.jpg', '.png'],\n *   maxSize: 5 * 1024 * 1024, // 5MB\n *   onSuccess: (result) => message.success('上传成功'),\n *   onError: (err) => message.error(err.message),\n * });\n *\n * <Upload beforeUpload={(file) => { upload(file); return false; }}>\n *   <Button loading={uploading}>上传文件 {uploading && `${progress}%`}</Button>\n * </Upload>\n * ```\n */\nexport function useFileUpload<R = unknown>(\n  options: UseFileUploadOptions<R>,\n): UseFileUploadReturn<R> {\n  const { uploadApi } = options;\n\n  const [uploading, setUploading] = useState(false);\n  const [progress, setProgress] = useState(0);\n  const abortRef = useRef(false);\n  const abortControllerRef = useRef<AbortController | null>(null);\n\n  // 用 useLatestRef 稳定回调引用\n  const allowedTypesRef = useLatestRef(options.allowedTypes);\n  const maxSizeRef = useLatestRef(options.maxSize);\n  const onSuccessRef = useLatestRef(options.onSuccess);\n  const onErrorRef = useLatestRef(options.onError);\n\n  const upload = useCallback(\n    async (file: File) => {\n      const allowedTypes = allowedTypesRef.current;\n      const maxSize = maxSizeRef.current;\n\n      // 文件类型验证\n      if (allowedTypes?.length) {\n        const isValid = allowedTypes.some((type) => {\n          if (type.startsWith('.')) {\n            return file.name.toLowerCase().endsWith(type.toLowerCase());\n          }\n          if (type.includes('*')) {\n            const [mainType] = type.split('/');\n            return file.type.startsWith(`${mainType}/`);\n          }\n          return file.type === type;\n        });\n\n        if (!isValid) {\n          const error = new Error(\n            `Unsupported file type. Allowed: ${allowedTypes.join(', ')}`,\n          );\n          onErrorRef.current?.(error, file);\n          throw error;\n        }\n      }\n\n      // 文件大小验证\n      if (maxSize && file.size > maxSize) {\n        const sizeMB = (maxSize / 1024 / 1024).toFixed(1);\n        const error = new Error(`File size exceeds limit (${sizeMB}MB)`);\n        onErrorRef.current?.(error, file);\n        throw error;\n      }\n\n      abortRef.current = false;\n      // 创建新的 AbortController，供 abort() 方法使用\n      const controller = new AbortController();\n      abortControllerRef.current = controller;\n      setUploading(true);\n      setProgress(0);\n\n      try {\n        const result = await uploadApi(\n          file,\n          (percent) => {\n            if (!abortRef.current) {\n              setProgress(Math.round(percent));\n            }\n          },\n          controller.signal,\n        );\n\n        if (!abortRef.current) {\n          setProgress(100);\n          onSuccessRef.current?.(result, file);\n        }\n\n        return result;\n      } catch (error) {\n        if (!abortRef.current) {\n          const err = error instanceof Error ? error : new Error(String(error));\n          onErrorRef.current?.(err, file);\n          throw err;\n        }\n        return undefined;\n      } finally {\n        if (!abortRef.current) {\n          setUploading(false);\n        }\n      }\n    },\n    [uploadApi, allowedTypesRef, maxSizeRef, onErrorRef, onSuccessRef],\n  );\n\n  const abort = useCallback(() => {\n    abortRef.current = true;\n    // 真正取消网络请求\n    abortControllerRef.current?.abort();\n    abortControllerRef.current = null;\n    setUploading(false);\n    setProgress(0);\n  }, []);\n\n  const reset = useCallback(() => {\n    abortRef.current = false;\n    setUploading(false);\n    setProgress(0);\n  }, []);\n\n  return { uploading, progress, upload, abort, reset };\n}\n","/**\n * Form Modal 状态管理 Hook\n *\n * 将三个项目中大量重复的「Modal + Form + Loading + Create/Edit」模式\n * 抽象为一个统一的 hook。\n *\n * 功能:\n * - 自动管理 modal 的 open / close 状态\n * - 区分 create 和 edit 模式\n * - 编辑时自动回填 form 数据 (支持 transform)\n * - 提交时根据模式自动调用 create / update API\n * - 内置 loading 状态 + 防重复提交\n * - 成功 / 失败消息自动处理\n */\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { ANIMATION_DURATION } from '../constants/ui';\nimport type { ApiResponse } from '../types/api';\nimport { isApiSuccess } from '../utils/api-helpers';\nimport { handleOperationError } from './shared-async';\nimport { useLatestRef } from './useLatestRef';\n\n// ===== 类型定义 =====\n\n/**\n * 表单模式\n */\nexport type FormModalMode = 'create' | 'edit';\n\n/**\n * FormModal 文案配置（支持国际化）\n */\nexport interface FormModalMessages {\n  /** 创建模式标题，默认 'Create' */\n  createTitle: string;\n  /** 编辑模式标题，默认 'Edit' */\n  editTitle: string;\n  /** 创建成功提示，默认 'Created successfully' */\n  createSuccess: string;\n  /** 更新成功提示，默认 'Updated successfully' */\n  updateSuccess: string;\n  /** 操作失败提示，默认 'Operation failed' */\n  operationFailed: string;\n}\n\nconst DEFAULT_FORM_MODAL_MESSAGES: FormModalMessages = {\n  createTitle: 'Create',\n  editTitle: 'Edit',\n  createSuccess: 'Created successfully',\n  updateSuccess: 'Updated successfully',\n  operationFailed: 'Operation failed',\n};\n\n/**\n * useFormModal 配置\n */\nexport interface UseFormModalOptions<\n  FormValues extends Record<string, unknown> = Record<string, unknown>,\n  RecordType = FormValues,\n  CreateResult = unknown,\n  UpdateResult = unknown,\n> {\n  /** Ant Design Form 实例 */\n  form: {\n    setFieldsValue: (values: Partial<FormValues>) => void;\n    resetFields: () => void;\n    validateFields: () => Promise<FormValues>;\n  };\n\n  /** 创建 API */\n  createApi?: (data: FormValues) => Promise<ApiResponse<CreateResult>>;\n\n  /** 更新 API */\n  updateApi?: (data: FormValues) => Promise<ApiResponse<UpdateResult>>;\n\n  /** 成功状态码, 默认 '200' */\n  successCode?: string | number;\n\n  /**\n   * 将记录数据转换为表单初始值\n   * (编辑模式: record -> form values)\n   */\n  transformToForm?: (record: RecordType) => Partial<FormValues>;\n\n  /**\n   * 将表单值转换为提交数据\n   * (提交时: form values -> API params)\n   */\n  transformToSubmit?: (\n    values: FormValues,\n    mode: FormModalMode,\n    record: RecordType | null,\n  ) => FormValues;\n\n  /** 自定义文案（支持国际化） */\n  messages?: Partial<FormModalMessages>;\n\n  /** 消息展示函数 */\n  showMessage?: (content: string, type: 'success' | 'error') => void;\n\n  /** 提交成功回调 */\n  onSuccess?: (\n    mode: FormModalMode,\n    result: CreateResult | UpdateResult,\n  ) => void;\n\n  /** 提交失败回调 */\n  onError?: (error: Error) => void;\n\n  /** modal 关闭时是否重置表单, 默认 true */\n  resetOnClose?: boolean;\n}\n\n/**\n * useFormModal 返回值\n */\nexport interface UseFormModalReturn<RecordType = Record<string, unknown>> {\n  /** modal 是否可见 */\n  visible: boolean;\n  /** 当前模式 */\n  mode: FormModalMode;\n  /** 当前编辑的记录数据 (create 模式为 null) */\n  record: RecordType | null;\n  /** 提交中状态 */\n  loading: boolean;\n  /** 模态框标题 (根据 mode 自动生成 'Create' / 'Edit') */\n  title: string;\n  /** 打开 modal — 创建模式 */\n  openCreate: () => void;\n  /** 打开 modal — 编辑模式 */\n  openEdit: (record: RecordType) => void;\n  /** 关闭 modal */\n  close: () => void;\n  /** 执行提交 (校验表单 + 调 API) */\n  submit: () => Promise<boolean>;\n  /**\n   * 展开到 Modal 的 props\n   *\n   * @example\n   * ```tsx\n   * <Modal {...modalProps}>\n   *   <Form form={form}>...</Form>\n   * </Modal>\n   * ```\n   */\n  modalProps: {\n    open: boolean;\n    title: string;\n    confirmLoading: boolean;\n    onCancel: () => void;\n    onOk: () => Promise<boolean>;\n    destroyOnClose: boolean;\n  };\n}\n\n// ===== Hook 实现 =====\n\n/**\n * Form Modal 状态管理 Hook\n *\n * @example\n * ```tsx\n * const [form] = Form.useForm();\n *\n * const {\n *   modalProps,\n *   openCreate,\n *   openEdit,\n * } = useFormModal({\n *   form,\n *   createApi: createUser,\n *   updateApi: updateUser,\n *   showMessage: (content, type) => message[type](content),\n *   onSuccess: () => actionRef.current?.reload(),\n * });\n *\n * // 工具栏\n * <Button onClick={openCreate}>新增</Button>\n *\n * // 行操作\n * <a onClick={() => openEdit(record)}>编辑</a>\n *\n * // 弹窗\n * <Modal {...modalProps}>\n *   <Form form={form} layout=\"vertical\">\n *     <Form.Item name=\"name\" label=\"姓名\" rules={[{ required: true }]}>\n *       <Input />\n *     </Form.Item>\n *   </Form>\n * </Modal>\n * ```\n *\n * @example\n * ```tsx\n * // 带数据转换\n * const { modalProps, openEdit } = useFormModal({\n *   form,\n *   updateApi: updateUser,\n *   transformToForm: (record) => ({\n *     ...record,\n *     birthday: dayjs(record.birthday),\n *   }),\n *   transformToSubmit: (values) => ({\n *     ...values,\n *     birthday: values.birthday?.format('YYYY-MM-DD'),\n *   }),\n *   showMessage: (content, type) => message[type](content),\n *   onSuccess: () => reload(),\n * });\n * ```\n */\nexport function useFormModal<\n  FormValues extends Record<string, unknown> = Record<string, unknown>,\n  RecordType = FormValues,\n  CreateResult = unknown,\n  UpdateResult = unknown,\n>(\n  options: UseFormModalOptions<\n    FormValues,\n    RecordType,\n    CreateResult,\n    UpdateResult\n  >,\n): UseFormModalReturn<RecordType> {\n  const { form, successCode = '200', resetOnClose = true } = options;\n\n  const msg: FormModalMessages = {\n    ...DEFAULT_FORM_MODAL_MESSAGES,\n    ...options.messages,\n  };\n\n  const [visible, setVisible] = useState(false);\n  const [mode, setMode] = useState<FormModalMode>('create');\n  const [record, setRecord] = useState<RecordType | null>(null);\n  const [loading, setLoading] = useState(false);\n\n  // 防重复提交\n  const submittingRef = useRef(false);\n\n  // 用 useLatestRef 稳定回调引用 (避免 inline 函数导致 useCallback 频繁更新)\n  const createApiRef = useLatestRef(options.createApi);\n  const updateApiRef = useLatestRef(options.updateApi);\n  const showMessageRef = useLatestRef(options.showMessage);\n  const transformToFormRef = useLatestRef(options.transformToForm);\n  const transformToSubmitRef = useLatestRef(options.transformToSubmit);\n  const onSuccessRef = useLatestRef(options.onSuccess);\n  const onErrorRef = useLatestRef(options.onError);\n\n  // 关闭时清理\n  const timerRef = useRef<ReturnType<typeof setTimeout>>(undefined);\n  useEffect(() => () => clearTimeout(timerRef.current), []);\n\n  // --- 打开: 创建模式 ---\n  const openCreate = useCallback(() => {\n    clearTimeout(timerRef.current);\n    setMode('create');\n    setRecord(null);\n    form.resetFields();\n    setVisible(true);\n  }, [form]);\n\n  // --- 打开: 编辑模式 ---\n  const openEdit = useCallback(\n    (editRecord: RecordType) => {\n      clearTimeout(timerRef.current);\n      setMode('edit');\n      setRecord(editRecord);\n\n      // 回填表单数据\n      const formValues = transformToFormRef.current\n        ? transformToFormRef.current(editRecord)\n        : (editRecord as unknown as Partial<FormValues>);\n\n      // 先重置再填充，避免残留字段（antd Form store 同步更新，无需 setTimeout）\n      form.resetFields();\n      form.setFieldsValue(formValues);\n\n      setVisible(true);\n    },\n    [form, transformToFormRef],\n  );\n\n  // --- 关闭 ---\n  const close = useCallback(() => {\n    setVisible(false);\n    setLoading(false);\n    submittingRef.current = false;\n\n    if (resetOnClose) {\n      timerRef.current = setTimeout(() => {\n        form.resetFields();\n        setRecord(null);\n      }, ANIMATION_DURATION.NORMAL); // 等待关闭动画\n    }\n  }, [form, resetOnClose]);\n\n  // --- 提交 ---\n  const submit = useCallback(async (): Promise<boolean> => {\n    if (submittingRef.current) return false;\n\n    const createApi = createApiRef.current;\n    const updateApi = updateApiRef.current;\n\n    // 前置检查 API 可用性 (在表单校验之前)\n    if (mode === 'create' && !createApi) {\n      throw new Error('createApi is not provided');\n    }\n    if (mode === 'edit' && !updateApi) {\n      throw new Error('updateApi is not provided');\n    }\n\n    try {\n      submittingRef.current = true;\n      setLoading(true);\n\n      // 校验表单\n      const values = await form.validateFields();\n\n      // 转换提交数据\n      const submitData = transformToSubmitRef.current\n        ? transformToSubmitRef.current(values, mode, record)\n        : values;\n\n      // 调用 API\n      let response: ApiResponse<CreateResult | UpdateResult>;\n      if (mode === 'create') {\n        if (!createApi) {\n          throw new Error('createApi is not provided');\n        }\n        response = await createApi(submitData);\n      } else {\n        if (!updateApi) {\n          throw new Error('updateApi is not provided');\n        }\n        response = await updateApi(submitData);\n      }\n\n      const isSuccess = isApiSuccess(response, successCode);\n\n      if (isSuccess) {\n        const successMsg =\n          mode === 'create' ? msg.createSuccess : msg.updateSuccess;\n        showMessageRef.current?.(successMsg, 'success');\n        onSuccessRef.current?.(\n          mode,\n          response.data as CreateResult | UpdateResult,\n        );\n        close();\n        return true;\n      }\n\n      const errorMessage =\n        response.msg ||\n        response.message ||\n        response.errorMessage ||\n        msg.operationFailed;\n      showMessageRef.current?.(errorMessage, 'error');\n      return false;\n    } catch (error) {\n      // 表单校验失败不算错误\n      if (error && typeof error === 'object' && 'errorFields' in error) {\n        return false;\n      }\n      handleOperationError({\n        error,\n        fallbackMessage: msg.operationFailed,\n        showError: (message) => showMessageRef.current?.(message, 'error'),\n        onError: onErrorRef.current,\n      });\n      return false;\n    } finally {\n      submittingRef.current = false;\n      setLoading(false);\n    }\n  }, [\n    form,\n    mode,\n    record,\n    successCode,\n    msg.createSuccess,\n    msg.updateSuccess,\n    msg.operationFailed,\n    close,\n    createApiRef,\n    onErrorRef,\n    onSuccessRef,\n    showMessageRef,\n    transformToSubmitRef,\n    updateApiRef,\n  ]);\n\n  // --- 计算标题 ---\n  const title = mode === 'create' ? msg.createTitle : msg.editTitle;\n\n  // --- modalProps (memoized) ---\n  const modalProps = useMemo(\n    () => ({\n      open: visible,\n      title,\n      confirmLoading: loading,\n      onCancel: close,\n      onOk: submit,\n      destroyOnClose: true as const,\n    }),\n    [visible, title, loading, close, submit],\n  );\n\n  return {\n    visible,\n    mode,\n    record,\n    loading,\n    title,\n    openCreate,\n    openEdit,\n    close,\n    submit,\n    modalProps,\n  };\n}\n","/**\n * 表单提交 Hook\n *\n * 封装表单提交的常见逻辑：loading 状态管理、防重复提交、成功/失败回调。\n * 适用于各种表单场景（ProForm、Modal 表单、独立表单页等）。\n *\n * 通用表单提交处理\n */\n\nimport { useCallback, useRef, useState } from 'react';\nimport type { ApiResponse } from '../types/api';\nimport { isApiSuccess } from '../utils/api-helpers';\nimport { useLatestRef } from './useLatestRef';\n\n/**\n * useFormSubmit 配置\n */\nexport interface UseFormSubmitOptions<\n  T = Record<string, unknown>,\n  R = unknown,\n> {\n  /** 提交 API 函数 */\n  submitApi: (data: T) => Promise<ApiResponse<R>>;\n  /** 成功状态码，默认 '200' */\n  successCode?: string | number;\n  /** 提交前的数据转换 */\n  transformData?: (data: T) => T;\n  /** 成功提示消息 */\n  successMsg?: string;\n  /** 消息展示函数 */\n  showMessage?: (content: string, type: 'success' | 'error') => void;\n  /** 提交成功回调 */\n  onSuccess?: (data: R) => void;\n  /** 提交失败回调 */\n  onError?: (error: Error) => void;\n  /** 提交完成回调（无论成功或失败） */\n  onFinally?: () => void;\n}\n\n/**\n * useFormSubmit 返回值\n */\nexport interface UseFormSubmitReturn<T = Record<string, unknown>> {\n  /** 提交中状态 */\n  submitting: boolean;\n  /** 提交函数 */\n  submit: (data: T) => Promise<boolean>;\n  /** 重置提交状态 */\n  reset: () => void;\n}\n\n/**\n * 表单提交 Hook\n *\n * @example\n * ```tsx\n * // 基础用法\n * const { submitting, submit } = useFormSubmit({\n *   submitApi: createUser,\n *   successMsg: '创建成功',\n *   showMessage: (content, type) => message[type](content),\n *   onSuccess: () => history.push('/user/list'),\n * });\n *\n * <ProForm loading={submitting} onFinish={submit} />\n *\n * // Modal 表单\n * const { submitting, submit } = useFormSubmit({\n *   submitApi: (data) => updateUser(id, data),\n *   successMsg: '更新成功',\n *   showMessage: (content, type) => message[type](content),\n *   onSuccess: () => { modal.close(); actionRef.current?.reload(); },\n * });\n *\n * <ModalForm loading={submitting} onFinish={submit} />\n * ```\n */\nexport function useFormSubmit<T = Record<string, unknown>, R = unknown>(\n  options: UseFormSubmitOptions<T, R>,\n): UseFormSubmitReturn<T> {\n  const { submitApi, successCode = '200', successMsg } = options;\n\n  const [submitting, setSubmitting] = useState(false);\n  const submittingRef = useRef(false);\n\n  // 用 useLatestRef 稳定所有可能不稳定的回调\n  const transformDataRef = useLatestRef(options.transformData);\n  const onSuccessRef = useLatestRef(options.onSuccess);\n  const onErrorRef = useLatestRef(options.onError);\n  const showMessageRef = useLatestRef(options.showMessage);\n  const onFinallyRef = useLatestRef(options.onFinally);\n\n  const submit = useCallback(\n    async (data: T): Promise<boolean> => {\n      // 防重复提交\n      if (submittingRef.current) return false;\n\n      submittingRef.current = true;\n      setSubmitting(true);\n\n      try {\n        const submitData = transformDataRef.current\n          ? transformDataRef.current(data)\n          : data;\n\n        const response = await submitApi(submitData);\n        const isSuccess = isApiSuccess(response, successCode);\n\n        if (isSuccess) {\n          if (successMsg) {\n            showMessageRef.current?.(successMsg, 'success');\n          }\n          onSuccessRef.current?.(response.data);\n          return true;\n        }\n\n        const errorMessage =\n          response.msg ||\n          response.message ||\n          response.errorMessage ||\n          'Operation failed';\n        showMessageRef.current?.(errorMessage, 'error');\n        return false;\n      } catch (error) {\n        const err = error instanceof Error ? error : new Error(String(error));\n        showMessageRef.current?.(err.message || 'Operation failed', 'error');\n        onErrorRef.current?.(err);\n        return false;\n      } finally {\n        submittingRef.current = false;\n        setSubmitting(false);\n        onFinallyRef.current?.();\n      }\n    },\n    [\n      submitApi,\n      successCode,\n      successMsg,\n      onErrorRef,\n      onFinallyRef,\n      onSuccessRef,\n      showMessageRef,\n      transformDataRef,\n    ],\n  );\n\n  const reset = useCallback(() => {\n    submittingRef.current = false;\n    setSubmitting(false);\n  }, []);\n\n  return { submitting, submit, reset };\n}\n","/**\n * i18n 便捷 Hook\n *\n * 简化 UmiJS useIntl().formatMessage() 的调用，提供更简洁的 API。\n *\n */\n\nimport { useCallback, useMemo } from 'react';\n\n/**\n * 国际化函数类型\n */\ntype IntlFormatMessage = (\n  descriptor: { id: string; defaultMessage?: string },\n  values?: Record<string, string | number>,\n) => string;\n\n/**\n * useIntlText 配置\n */\nexport interface UseIntlTextOptions {\n  /** formatMessage 函数（通常来自 useIntl()） */\n  formatMessage: IntlFormatMessage;\n  /** key 前缀，自动拼接到所有 id 前面 */\n  prefix?: string;\n}\n\n/**\n * useIntlText 返回值\n */\nexport interface UseIntlTextReturn {\n  /** 获取国际化文本 */\n  t: (\n    id: string,\n    defaultMessage?: string,\n    values?: Record<string, string | number>,\n  ) => string;\n  /** 获取国际化文本（带前缀的简写） */\n  tp: (\n    id: string,\n    defaultMessage?: string,\n    values?: Record<string, string | number>,\n  ) => string;\n}\n\n/**\n * i18n 便捷 Hook\n *\n * @example\n * ```tsx\n * import { useIntl } from '@umijs/max';\n *\n * function MyComponent() {\n *   const intl = useIntl();\n *   const { t, tp } = useIntlText({\n *     formatMessage: intl.formatMessage,\n *     prefix: 'pages.user',\n *   });\n *\n *   return (\n *     <div>\n *       <h1>{t('app.title', '应用标题')}</h1>\n *       <p>{tp('name', '用户名')}</p>  {// => pages.user.name}\n *       <p>{tp('greeting', '你好, {name}', { name: 'Alice' })}</p>\n *     </div>\n *   );\n * }\n * ```\n */\nexport function useIntlText(options: UseIntlTextOptions): UseIntlTextReturn {\n  const { formatMessage, prefix } = options;\n\n  const t = useCallback(\n    (\n      id: string,\n      defaultMessage?: string,\n      values?: Record<string, string | number>,\n    ): string => {\n      return formatMessage(\n        { id, defaultMessage: defaultMessage ?? id },\n        values,\n      );\n    },\n    [formatMessage],\n  );\n\n  const tp = useCallback(\n    (\n      id: string,\n      defaultMessage?: string,\n      values?: Record<string, string | number>,\n    ): string => {\n      const fullId = prefix ? `${prefix}.${id}` : id;\n      return formatMessage(\n        { id: fullId, defaultMessage: defaultMessage ?? id },\n        values,\n      );\n    },\n    [formatMessage, prefix],\n  );\n\n  return useMemo(() => ({ t, tp }), [t, tp]);\n}\n","/**\n * 非分页列表数据 Hook\n *\n * 用于加载不需要分页的简单列表数据，如下拉选项、标签列表、分类列表等。\n * 与 useTableData（分页列表）互补。\n */\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport type { ApiResponse } from '../types/api';\nimport { isApiSuccess } from '../utils/api-helpers';\nimport {\n  handleAbortableRequestError,\n  handleApiFailure,\n  runAbortableTask,\n  startAbortableRequest,\n} from './shared-async';\nimport { useLatestRef } from './useLatestRef';\n\nfunction buildParamsKey(value: unknown): string {\n  if (value === undefined) return '__undefined__';\n  if (value === null) return '__null__';\n\n  try {\n    return JSON.stringify(value);\n  } catch {\n    return String(value);\n  }\n}\n\n/**\n * useListData 配置\n */\nexport interface UseListDataOptions<T, P = void> {\n  /** 列表数据请求 API */\n  fetchApi: (params?: P) => Promise<ApiResponse<T[]>>;\n  /** 请求参数（变化时自动重新请求） */\n  params?: P;\n  /** 是否在挂载时自动请求，默认 true */\n  autoLoad?: boolean;\n  /** 成功状态码，默认 '200' */\n  successCode?: string | number;\n  /** 数据转换 */\n  transformData?: (list: T[]) => T[];\n  /** 请求成功回调 */\n  onSuccess?: (list: T[]) => void;\n  /** 请求失败回调 */\n  onError?: (error: Error) => void;\n}\n\n/**\n * useListData 返回值\n */\nexport interface UseListDataReturn<T> {\n  /** 列表数据 */\n  data: T[];\n  /** 加载中状态 */\n  loading: boolean;\n  /** 错误信息 */\n  error: Error | null;\n  /** 手动刷新 */\n  refresh: () => Promise<void>;\n  /** 手动设置数据 */\n  setData: React.Dispatch<React.SetStateAction<T[]>>;\n}\n\n/**\n * 非分页列表数据 Hook\n *\n * @example\n * ```tsx\n * // 基础用法：下拉选项\n * const { data: categories, loading } = useListData({\n *   fetchApi: getCategoryList,\n * });\n *\n * // 带参数：按条件加载\n * const { data: tags, refresh } = useListData({\n *   fetchApi: (params) => getTagList(params),\n *   params: { type: 'article' },\n * });\n *\n * // 数据转换：转为 Select options\n * const { data: options } = useListData({\n *   fetchApi: getRoleList,\n *   transformData: (list) => list.map(r => ({ label: r.name, value: r.id })),\n * });\n * ```\n */\nexport function useListData<T, P = void>(\n  options: UseListDataOptions<T, P>,\n): UseListDataReturn<T> {\n  const { fetchApi, params, autoLoad = true, successCode = '200' } = options;\n\n  const [data, setData] = useState<T[]>([]);\n  const [loading, setLoading] = useState(false);\n  const [error, setError] = useState<Error | null>(null);\n\n  // AbortController 引用，用于取消进行中的请求\n  const abortControllerRef = useRef<AbortController | null>(null);\n\n  // 用 useLatestRef 稳定回调和参数引用，防止 inline 函数/对象导致无限重请求\n  const transformDataRef = useLatestRef(options.transformData);\n  const onSuccessRef = useLatestRef(options.onSuccess);\n  const onErrorRef = useLatestRef(options.onError);\n  const paramsRef = useLatestRef(params);\n  const paramsKey = useMemo(() => buildParamsKey(params), [params]);\n  const lastAutoLoadRef = useRef(autoLoad);\n  const lastLoadedParamsKeyRef = useRef<string | null>(null);\n\n  const fetchData = useCallback(async () => {\n    const controller = startAbortableRequest(abortControllerRef);\n\n    setLoading(true);\n    setError(null);\n\n    await runAbortableTask({\n      controller,\n      setLoading,\n      execute: async () => {\n        const response = await fetchApi(paramsRef.current as P);\n\n        // 请求已被取消，忽略结果\n        if (controller.signal.aborted) return;\n\n        const isSuccess = isApiSuccess(response, successCode);\n\n        if (isSuccess && response.data) {\n          const list = Array.isArray(response.data) ? response.data : [];\n          const result = transformDataRef.current\n            ? transformDataRef.current(list)\n            : list;\n          setData(result);\n          onSuccessRef.current?.(result);\n        } else {\n          handleApiFailure({\n            message: response.msg || response.message || response.errorMessage,\n            fallbackMessage: 'Failed to fetch list',\n            setError,\n            onError: onErrorRef.current,\n          });\n        }\n      },\n      onError: (error) =>\n        handleAbortableRequestError({\n          error,\n          controller,\n          setError,\n          onError: onErrorRef.current,\n        }),\n    });\n  }, [\n    fetchApi,\n    successCode,\n    onErrorRef,\n    onSuccessRef,\n    paramsRef,\n    transformDataRef,\n  ]);\n\n  useEffect(() => {\n    const autoLoadEnabled = autoLoad && !lastAutoLoadRef.current;\n    lastAutoLoadRef.current = autoLoad;\n\n    const shouldFetch =\n      autoLoad &&\n      (autoLoadEnabled || lastLoadedParamsKeyRef.current !== paramsKey);\n\n    if (shouldFetch) {\n      lastLoadedParamsKeyRef.current = paramsKey;\n      fetchData();\n    }\n    // 组件卸载或参数变化时取消进行中的请求\n    return () => {\n      abortControllerRef.current?.abort();\n    };\n  }, [autoLoad, fetchData, paramsKey]);\n\n  return { data, loading, error, refresh: fetchData, setData };\n}\n","/**\n * 模态框状态管理 Hook\n */\n\nimport type { Dispatch, SetStateAction } from 'react';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { ANIMATION_DURATION } from '../constants/ui';\nimport { useLatestRef } from './useLatestRef';\n\n/**\n * useModal 返回值\n */\nexport interface UseModalReturn<T = unknown> {\n  /** 模态框是否可见 */\n  visible: boolean;\n  /** 模态框携带的数据 */\n  data: T | null;\n  /** 加载中状态 */\n  loading: boolean;\n  /** 打开模态框 (可传入数据) */\n  open: (data?: T | undefined) => void;\n  /** 关闭模态框 */\n  close: () => void;\n  /** 切换模态框可见状态 */\n  toggle: () => void;\n  /** 设置加载状态 */\n  setLoading: (loading: boolean) => void;\n  /** 设置数据 */\n  setData: Dispatch<SetStateAction<T | null>>;\n}\n\n/**\n * 模态框状态管理 Hook\n *\n * @example\n * ```tsx\n * const editModal = useModal<User>();\n *\n * <Button onClick={() => editModal.open(record)}>编辑</Button>\n *\n * <Modal\n *   open={editModal.visible}\n *   onCancel={editModal.close}\n *   confirmLoading={editModal.loading}\n * >\n *   <UserForm initialValues={editModal.data} />\n * </Modal>\n * ```\n */\nexport function useModal<T = unknown>(): UseModalReturn<T> {\n  const [visible, setVisible] = useState(false);\n  const [data, setData] = useState<T | null>(null);\n  const [loading, setLoading] = useState(false);\n  const timerRef = useRef<ReturnType<typeof setTimeout>>(undefined);\n\n  // 组件卸载时清理 timer\n  useEffect(() => () => clearTimeout(timerRef.current), []);\n\n  const open = useCallback((modalData?: T | undefined) => {\n    clearTimeout(timerRef.current);\n    setData(modalData ?? null);\n    setVisible(true);\n  }, []);\n\n  const close = useCallback(() => {\n    setVisible(false);\n    setLoading(false);\n    // 延迟清空数据，避免关闭动画中数据闪烁\n    timerRef.current = setTimeout(\n      () => setData(null),\n      ANIMATION_DURATION.NORMAL,\n    );\n  }, []);\n\n  // 用 useLatestRef 追踪当前 visible 状态，使 toggle 无需依赖闭包中的 visible\n  const visibleRef = useLatestRef(visible);\n\n  const toggle = useCallback(() => {\n    if (visibleRef.current) {\n      setVisible(false);\n      setLoading(false);\n      timerRef.current = setTimeout(\n        () => setData(null),\n        ANIMATION_DURATION.NORMAL,\n      );\n    } else {\n      clearTimeout(timerRef.current);\n      setVisible(true);\n    }\n  }, [visibleRef]);\n\n  return {\n    visible,\n    data,\n    loading,\n    open,\n    close,\n    toggle,\n    setLoading,\n    setData,\n  };\n}\n","/**\n * 响应式断点检测 Hook\n */\n\nimport { useCallback, useEffect, useMemo, useState } from 'react';\n\n/**\n * 默认断点值 (像素)\n */\nconst DEFAULT_BREAKPOINTS = {\n  mobile: 576,\n  tablet: 768,\n  desktop: 1200,\n} as const;\n\n/**\n * 断点配置\n */\nexport interface Breakpoints {\n  /** 移动端最大宽度，默认 576 */\n  mobile?: number;\n  /** 平板最大宽度，默认 768 */\n  tablet?: number;\n  /** 桌面端最小宽度，默认 1200 */\n  desktop?: number;\n}\n\n/**\n * 响应式状态\n */\ninterface ResponsiveState {\n  /** 是否为移动端 (宽度 < mobile) */\n  isMobile: boolean;\n  /** 是否为平板 (mobile <= 宽度 < desktop) */\n  isTablet: boolean;\n  /** 是否为桌面端 (宽度 >= desktop) */\n  isDesktop: boolean;\n  /** 当前视口宽度 */\n  width: number;\n}\n\n/**\n * 响应式断点检测 Hook\n *\n * 监听窗口大小变化，返回当前设备类型。\n *\n * @param breakpoints - 自定义断点值\n * @returns 响应式状态\n *\n * @example\n * ```tsx\n * const { isMobile, isTablet, isDesktop } = useResponsive();\n *\n * return isMobile ? <MobileLayout /> : <DesktopLayout />;\n * ```\n */\nexport function useResponsive(breakpoints?: Breakpoints): ResponsiveState {\n  const bp = useMemo(\n    () => ({\n      mobile: breakpoints?.mobile ?? DEFAULT_BREAKPOINTS.mobile,\n      tablet: breakpoints?.tablet ?? DEFAULT_BREAKPOINTS.tablet,\n      desktop: breakpoints?.desktop ?? DEFAULT_BREAKPOINTS.desktop,\n    }),\n    [breakpoints?.mobile, breakpoints?.tablet, breakpoints?.desktop],\n  );\n\n  const getState = useCallback((): ResponsiveState => {\n    if (typeof window === 'undefined') {\n      return {\n        isMobile: false,\n        isTablet: false,\n        isDesktop: true,\n        width: 1920,\n      };\n    }\n\n    const width = window.innerWidth;\n    return {\n      isMobile: width < bp.mobile,\n      isTablet: width >= bp.mobile && width < bp.desktop,\n      isDesktop: width >= bp.desktop,\n      width,\n    };\n  }, [bp.mobile, bp.desktop]);\n\n  const [state, setState] = useState<ResponsiveState>(getState);\n\n  useEffect(() => {\n    let rafId: number | null = null;\n\n    const handleResize = () => {\n      // 使用 rAF 节流：每帧最多计算一次，避免高频 resize 事件导致性能问题\n      if (rafId !== null) return;\n      rafId = requestAnimationFrame(() => {\n        rafId = null;\n        setState(getState());\n      });\n    };\n\n    window.addEventListener('resize', handleResize);\n    // 初始化时同步更新一次\n    setState(getState());\n\n    return () => {\n      window.removeEventListener('resize', handleResize);\n      if (rafId !== null) cancelAnimationFrame(rafId);\n    };\n  }, [getState]);\n\n  return state;\n}\n","/**\n * 表格配置 Hook\n *\n * 为 ProTable 生成标准化的配置:\n * - 工具栏按钮 (新建、导出、回收站)\n * - 行操作 (查看、编辑、删除)\n * - 分页配置\n */\n\nimport { Button, Popconfirm, Space, Typography } from 'antd';\nimport type React from 'react';\nimport { useMemo } from 'react';\nimport { TABLE_DEFAULTS } from '../constants/ui';\n\n// ===== 模块级常量 (避免每次渲染创建新引用) =====\n\nconst EMPTY_ROW_ACTIONS: never[] = [];\nconst EMPTY_TOOLBAR: never[] = [];\n/** 从 TABLE_DEFAULTS 派生的可变数组（ProTable 需要 number[] 而非 readonly） */\nconst DEFAULT_PAGE_SIZE_OPTIONS: number[] = [\n  ...TABLE_DEFAULTS.PAGE_SIZE_OPTIONS,\n];\n\nfunction resolveFlag<T>(\n  value: boolean | ((record: T) => boolean) | undefined,\n  record: T,\n): boolean {\n  return typeof value === 'function' ? value(record) : Boolean(value);\n}\n\n// ===== 类型定义 =====\n\n/**\n * 行操作项\n */\nexport interface RowAction<T = Record<string, unknown>> {\n  /** 操作 key */\n  key: string;\n  /** 显示文本 */\n  label: React.ReactNode;\n  /** 点击回调 */\n  onClick?: (record: T) => void;\n  /** 是否危险操作 (红色) */\n  danger?: boolean;\n  /** 是否需要确认弹窗 */\n  confirm?: {\n    title: string;\n    content?: React.ReactNode | ((record: T) => React.ReactNode);\n  };\n  /** 确认后的回调 */\n  onConfirm?: (record: T) => void | Promise<void>;\n  /** 是否隐藏 */\n  hidden?: boolean | ((record: T) => boolean);\n  /** 是否禁用 */\n  disabled?: boolean | ((record: T) => boolean);\n}\n\n/**\n * 工具栏按钮\n */\nexport interface ToolbarAction {\n  /** 按钮 key */\n  key: string;\n  /** 显示文本 */\n  text: string;\n  /** 按钮类型 */\n  type?: 'primary' | 'default' | 'dashed' | 'link' | 'text';\n  /** 点击回调 */\n  onClick: () => void;\n  /** 图标 */\n  icon?: React.ReactNode;\n  /** 是否隐藏 */\n  hidden?: boolean;\n}\n\n/**\n * 表格配置文案（支持国际化）\n */\nexport interface TableConfigMessages {\n  /** 操作列标题，默认 'Actions' */\n  actionColumnTitle: string;\n  /** 总数展示函数，默认 (total) => `Total ${total}` */\n  showTotal: (total: number) => string;\n}\n\nconst DEFAULT_TABLE_CONFIG_MESSAGES: TableConfigMessages = {\n  actionColumnTitle: 'Actions',\n  showTotal: (total: number) => `Total ${total}`,\n};\n\n/**\n * useTableConfig 配置\n */\nexport interface UseTableConfigOptions<T = Record<string, unknown>> {\n  /** 行操作配置 */\n  rowActions?: ReadonlyArray<RowAction<T>>;\n  /** 工具栏按钮 */\n  toolbar?: ReadonlyArray<ToolbarAction>;\n  /** 默认每页条数, 默认 10 */\n  defaultPageSize?: number;\n  /** 可选每页条数, 默认 [10, 20, 50, 100] */\n  pageSizeOptions?: number[];\n  /** 表格行 key 字段, 默认 'id' */\n  rowKey?: string;\n  /** 表格滚动宽度, 默认 'max-content' */\n  scrollX?: number | string;\n  /** 操作列宽度 */\n  actionColumnWidth?: number;\n  /** 操作列固定, 默认 'right' */\n  actionColumnFixed?: 'left' | 'right' | false;\n  /** 自定义文案（支持国际化） */\n  messages?: Partial<TableConfigMessages>;\n  /** 确认弹窗函数 (需外部注入，未提供时使用 Popconfirm) */\n  showConfirm?: (options: {\n    title: string;\n    content?: React.ReactNode;\n    onOk: () => Promise<void> | void;\n  }) => void;\n}\n\n/**\n * useTableConfig 返回值\n */\nexport interface UseTableConfigReturn<T = Record<string, unknown>> {\n  /** 传给 ProTable 的 pagination 配置 */\n  pagination: {\n    pageSize: number;\n    pageSizeOptions: number[];\n    showSizeChanger: boolean;\n    showTotal: (total: number) => string;\n  };\n  /** 表格属性 */\n  tableProps: {\n    rowKey: string;\n    scroll: { x: number | string };\n  };\n  /** 工具栏渲染 — 传给 ProTable toolBarRender */\n  toolBarRender: () => React.ReactNode[];\n  /** 操作列配置 — 作为 columns 最后一列 */\n  actionColumn: {\n    title: string;\n    dataIndex: string;\n    key: string;\n    width?: number;\n    fixed?: 'left' | 'right';\n    render: (_: unknown, record: T) => React.ReactNode;\n  };\n  /** 生成行操作渲染 (给定 record) */\n  renderRowActions: (record: T) => React.ReactNode;\n}\n\n// ===== Hook 实现 =====\n\n/**\n * 表格配置 Hook\n *\n * @example\n * ```tsx\n * const {\n *   pagination,\n *   tableProps,\n *   toolBarRender,\n *   actionColumn,\n * } = useTableConfig<User>({\n *   toolbar: [\n *     { key: 'create', text: '新增', type: 'primary', onClick: () => openCreate() },\n *     { key: 'export', text: '导出', onClick: () => handleExport() },\n *   ],\n *   rowActions: [\n *     { key: 'view', label: '查看', onClick: (r) => goDetail(r.id) },\n *     { key: 'edit', label: '编辑', onClick: (r) => openEdit(r) },\n *     {\n *       key: 'delete', label: '删除', danger: true,\n *       confirm: { title: '确认删除', content: (r) => `确定要删除 ${r.name} 吗？` },\n *       onConfirm: (r) => handleDelete(r.id),\n *     },\n *   ],\n *   showConfirm: ({ title, content, onOk }) => Modal.confirm({ title, content, onOk }),\n * });\n *\n * const columns = [\n *   { title: '姓名', dataIndex: 'name' },\n *   { title: '邮箱', dataIndex: 'email' },\n *   actionColumn, // 操作列\n * ];\n *\n * <ProTable\n *   {...tableProps}\n *   columns={columns}\n *   pagination={pagination}\n *   toolBarRender={toolBarRender}\n * />\n * ```\n */\nexport function useTableConfig<\n  T extends Record<string, unknown> = Record<string, unknown>,\n>(options: UseTableConfigOptions<T> = {}): UseTableConfigReturn<T> {\n  const {\n    defaultPageSize = 10,\n    rowKey = 'id',\n    scrollX = 'max-content',\n    actionColumnWidth,\n    actionColumnFixed = 'right',\n    showConfirm,\n  } = options;\n\n  const msg: TableConfigMessages = {\n    ...DEFAULT_TABLE_CONFIG_MESSAGES,\n    ...options.messages,\n  };\n\n  const rowActions = options.rowActions ?? EMPTY_ROW_ACTIONS;\n  const toolbar = options.toolbar ?? EMPTY_TOOLBAR;\n  const pageSizeOptions = options.pageSizeOptions ?? DEFAULT_PAGE_SIZE_OPTIONS;\n\n  // 分页\n  const pagination = useMemo(\n    () => ({\n      pageSize: defaultPageSize,\n      pageSizeOptions,\n      showSizeChanger: true,\n      showTotal: msg.showTotal,\n    }),\n    [defaultPageSize, pageSizeOptions, msg.showTotal],\n  );\n\n  // 表格属性\n  const tableProps = useMemo(\n    () => ({\n      rowKey,\n      scroll: { x: scrollX },\n    }),\n    [rowKey, scrollX],\n  );\n\n  // 工具栏 — 使用 antd Button\n  const toolBarRender = useMemo(\n    () => () =>\n      toolbar\n        .filter((btn) => !btn.hidden)\n        .map((btn) => (\n          <Button\n            key={btn.key}\n            type={btn.type}\n            icon={btn.icon}\n            onClick={btn.onClick}\n          >\n            {btn.text}\n          </Button>\n        )),\n    [toolbar],\n  );\n\n  // 行操作渲染 — 使用 antd Space + Typography.Link + Popconfirm\n  const renderRowActions = useMemo(\n    () => (record: T) => {\n      const visibleActions = rowActions.filter((action) => {\n        return !resolveFlag(action.hidden, record);\n      });\n\n      return (\n        <Space size={4}>\n          {visibleActions.map((action) => {\n            const isDisabled = resolveFlag(action.disabled, record);\n            const confirmConfig = action.confirm;\n            const onConfirm = action.onConfirm;\n\n            // 带确认弹窗的操作\n            if (confirmConfig && onConfirm) {\n              const content =\n                typeof confirmConfig.content === 'function'\n                  ? confirmConfig.content(record)\n                  : confirmConfig.content;\n\n              // 优先使用 antd Popconfirm，提供原生体验\n              if (showConfirm) {\n                return (\n                  <Typography.Link\n                    key={action.key}\n                    type={action.danger ? 'danger' : undefined}\n                    disabled={isDisabled}\n                    onClick={() => {\n                      if (isDisabled) return;\n                      showConfirm({\n                        title: confirmConfig.title,\n                        content,\n                        onOk: () => Promise.resolve(onConfirm(record)),\n                      });\n                    }}\n                  >\n                    {action.label}\n                  </Typography.Link>\n                );\n              }\n\n              // 未注入 showConfirm 时，使用 Popconfirm 组件\n              return (\n                <Popconfirm\n                  key={action.key}\n                  title={confirmConfig.title}\n                  description={content}\n                  onConfirm={() => Promise.resolve(onConfirm(record))}\n                  disabled={isDisabled}\n                >\n                  <Typography.Link\n                    type={action.danger ? 'danger' : undefined}\n                    disabled={isDisabled}\n                  >\n                    {action.label}\n                  </Typography.Link>\n                </Popconfirm>\n              );\n            }\n\n            // 普通操作\n            return (\n              <Typography.Link\n                key={action.key}\n                type={action.danger ? 'danger' : undefined}\n                disabled={isDisabled}\n                onClick={() => {\n                  if (!isDisabled) action.onClick?.(record);\n                }}\n              >\n                {action.label}\n              </Typography.Link>\n            );\n          })}\n        </Space>\n      );\n    },\n    [rowActions, showConfirm],\n  );\n\n  // 操作列\n  const actionColumn = useMemo(\n    () => ({\n      title: msg.actionColumnTitle,\n      dataIndex: '_actions',\n      key: '_actions',\n      width: actionColumnWidth,\n      fixed: actionColumnFixed === false ? undefined : actionColumnFixed,\n      render: (_: unknown, record: T) => renderRowActions(record),\n    }),\n    [\n      msg.actionColumnTitle,\n      actionColumnWidth,\n      actionColumnFixed,\n      renderRowActions,\n    ],\n  );\n\n  return {\n    pagination,\n    tableProps,\n    toolBarRender,\n    actionColumn,\n    renderRowActions,\n  };\n}\n","/**\n * ProTable 数据请求 Hook\n *\n */\n\nimport { useCallback, useRef, useState } from 'react';\nimport type {\n  ApiResponse,\n  PaginatedData,\n  ProTableResponse,\n} from '../types/api';\nimport { normalizeError } from './shared-async';\nimport { fetchPaginatedData, type TableRequestParams } from './shared-request';\nimport { useLatestRef } from './useLatestRef';\n\n/**\n * useTableData 配置\n */\nexport interface UseTableDataOptions<T, P = Record<string, unknown>> {\n  /** API 请求函数 */\n  fetchApi: (params: P) => Promise<ApiResponse<PaginatedData<T>>>;\n  /** 成功状态码，默认 '200' */\n  successCode?: string | number;\n  /** 请求前的参数转换 */\n  transformParams?: (params: TableRequestParams) => P;\n  /** 响应后的数据转换 */\n  transformData?: (list: T[]) => T[];\n  /** 请求失败回调 */\n  onError?: (error: Error) => void;\n  /** 数据加载完成回调 */\n  onDataLoaded?: (data: T[], total: number) => void;\n  /** 默认额外查询参数 */\n  defaultParams?: Partial<P>;\n}\n\n/**\n * useTableData 返回值\n */\nexport interface UseTableDataReturn<T, P = Record<string, unknown>> {\n  /** 传递给 ProTable 的 request 函数 */\n  request: (\n    params: TableRequestParams,\n    sort?: Record<string, 'ascend' | 'descend' | null>,\n    filter?: TableRequestParams,\n  ) => Promise<ProTableResponse<T>>;\n  /** 刷新表格 (需要配合 actionRef) */\n  reload: (resetPageIndex?: boolean) => Promise<void>;\n  /** 刷新并重置分页到第一页 */\n  reloadAndRest: () => Promise<void>;\n  /** 设置额外参数并重新加载（重置分页） */\n  search: (params?: Partial<P>) => void;\n  /** 重置额外参数并重新加载 */\n  reset: () => void;\n  /** 设置额外查询参数（不触发请求） */\n  setExtraParams: (params: Partial<P>) => void;\n  /** 当前额外查询参数 */\n  extraParams: Partial<P>;\n  /** 加载中状态 */\n  loading: boolean;\n  /** actionRef - 传给 ProTable */\n  actionRef: React.MutableRefObject<TableActionRef | undefined>;\n}\n\ninterface TablePageInfo {\n  pageSize: number;\n  total: number;\n  current: number;\n}\n\ntype TableEditableKey = React.Key | React.Key[];\n\ntype TableEditableRecord = Record<string, unknown>;\n\ninterface TableEditableState {\n  recordKey: string;\n  isEditable: unknown;\n  preIsEditable: unknown;\n}\n\ninterface TableActionRef {\n  reload: (resetPageIndex?: boolean) => Promise<void>;\n  reloadAndRest?: () => Promise<void>;\n  reset?: () => void;\n  clearSelected?: () => void;\n  pageInfo?: TablePageInfo;\n  isEditable: (\n    row: TableEditableRecord & {\n      index: number;\n    },\n  ) => TableEditableState;\n  startEditable: (\n    recordKey: React.Key,\n    record?: TableEditableRecord,\n  ) => boolean;\n  cancelEditable: (\n    recordKey: TableEditableKey,\n    needReTry?: boolean,\n  ) => Promise<true | undefined>;\n  addEditRecord: (row: TableEditableRecord, options?: unknown) => boolean;\n  saveEditable: (\n    recordKey: TableEditableKey,\n    needReTry?: boolean,\n  ) => Promise<boolean>;\n  preEditableKeys: React.Key[] | undefined;\n  onValuesChange: (\n    value: TableEditableRecord,\n    values: TableEditableRecord,\n  ) => void;\n  getRealIndex: ((record: TableEditableRecord) => number) | undefined;\n}\n\n/**\n * ProTable 数据请求 Hook\n *\n * @example\n * ```tsx\n * const { request, actionRef, reload, loading } = useTableData({\n *   fetchApi: (params) => getUserList(params),\n *   transformParams: (params) => ({\n *     pageNo: params.current,\n *     pageSize: params.pageSize,\n *     ...params,\n *   }),\n *   onDataLoaded: (data, total) => console.log('loaded', total),\n * });\n *\n * <ProTable actionRef={actionRef} request={request} columns={columns} />\n * ```\n */\nexport function useTableData<T, P = Record<string, unknown>>(\n  options: UseTableDataOptions<T, P>,\n): UseTableDataReturn<T, P> {\n  const { fetchApi, successCode = '200' } = options;\n\n  const actionRef = useRef<TableActionRef | undefined>(undefined);\n  const defaultParamsRef = useLatestRef(options.defaultParams ?? {});\n  const [extraParams, setExtraParamsState] = useState<Partial<P>>(\n    (options.defaultParams ?? {}) as Partial<P>,\n  );\n  const [loading, setLoading] = useState(false);\n\n  // 用 useLatestRef 稳定回调引用，防止内联函数导致 ProTable 不必要的重渲染\n  const transformParamsRef = useLatestRef(options.transformParams);\n  const transformDataRef = useLatestRef(options.transformData);\n  const onErrorRef = useLatestRef(options.onError);\n  const onDataLoadedRef = useLatestRef(options.onDataLoaded);\n\n  const request = useCallback(\n    async (\n      params: TableRequestParams,\n      sort?: Record<string, 'ascend' | 'descend' | null>,\n      filter?: TableRequestParams,\n    ): Promise<ProTableResponse<T>> => {\n      setLoading(true);\n      try {\n        const mergedParams = { ...params, ...extraParams };\n        const result = await fetchPaginatedData<T, P>({\n          params: mergedParams,\n          sort,\n          filter,\n          fetchApi,\n          successCode,\n          transformParams: transformParamsRef.current,\n          transformData: transformDataRef.current,\n        });\n\n        if (result.success) {\n          onDataLoadedRef.current?.(result.data, result.total);\n        }\n\n        return result;\n      } catch (error) {\n        onErrorRef.current?.(normalizeError(error));\n        return { data: [], success: false, total: 0 };\n      } finally {\n        setLoading(false);\n      }\n    },\n    [\n      fetchApi,\n      successCode,\n      extraParams,\n      onDataLoadedRef,\n      onErrorRef,\n      transformDataRef,\n      transformParamsRef,\n    ],\n  );\n\n  const reload = useCallback(async (resetPageIndex?: boolean) => {\n    await actionRef.current?.reload(resetPageIndex);\n  }, []);\n\n  const reloadAndRest = useCallback(async () => {\n    await actionRef.current?.reloadAndRest?.();\n  }, []);\n\n  const search = useCallback((newParams?: Partial<P>) => {\n    if (newParams) {\n      setExtraParamsState((prev) => ({ ...prev, ...newParams }));\n    }\n    queueMicrotask(() => actionRef.current?.reloadAndRest?.());\n  }, []);\n\n  const reset = useCallback(() => {\n    const defaults = defaultParamsRef.current as Partial<P>;\n    setExtraParamsState(defaults);\n    queueMicrotask(() => actionRef.current?.reloadAndRest?.());\n  }, [defaultParamsRef]);\n\n  const setExtraParams = useCallback((params: Partial<P>) => {\n    setExtraParamsState((prev) => ({ ...prev, ...params }));\n  }, []);\n\n  return {\n    request,\n    reload,\n    reloadAndRest,\n    search,\n    reset,\n    setExtraParams,\n    extraParams,\n    loading,\n    actionRef,\n  };\n}\n","/**\n * 用户偏好管理 Hook\n *\n * 提供用户偏好设置的读写能力:\n * - 支持 localStorage 缓存 (离线可用)\n * - 支持可选的 API 同步 (云端持久化)\n * - 自动合并默认值 (浅合并)\n * - 防抖同步\n *\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport type { ApiResponse } from '../types/api';\nimport { useLatestRef } from './useLatestRef';\n\n// ===== 类型定义 =====\n\n/**\n * useUserPreference 配置\n */\nexport interface UseUserPreferenceOptions<T extends Record<string, unknown>> {\n  /** 偏好设置 key (localStorage 和 API 共用) */\n  key: string;\n  /** 默认值 */\n  defaultValue: T;\n  /** localStorage 缓存 key 前缀, 默认 'user-pref-' */\n  storagePrefix?: string;\n  /** 是否启用 localStorage 缓存, 默认 true */\n  enableCache?: boolean;\n  /** 读取 API (可选, 不传则仅使用 localStorage) */\n  fetchApi?: (key: string) => Promise<ApiResponse<T>>;\n  /** 保存 API (可选) */\n  saveApi?: (key: string, value: T) => Promise<ApiResponse<unknown>>;\n  /** API 成功状态码, 默认 '200' */\n  successCode?: string | number;\n  /** 保存防抖延迟 (ms), 默认 500 */\n  debounceMs?: number;\n  /** 值变化回调 */\n  onChange?: (value: T) => void;\n}\n\n/**\n * useUserPreference 返回值\n */\nexport interface UseUserPreferenceReturn<T> {\n  /** 当前偏好值 */\n  value: T;\n  /** 设置偏好值 */\n  setValue: (value: T | ((prev: T) => T)) => void;\n  /** 重置为默认值 */\n  reset: () => void;\n  /** 是否正在加载 */\n  loading: boolean;\n  /** 是否正在保存 */\n  saving: boolean;\n  /** 手动同步到服务器 */\n  sync: () => Promise<void>;\n}\n\n// ===== Hook 实现 =====\n\n/**\n * 用户偏好管理 Hook\n *\n * @example\n * ```tsx\n * // 纯本地偏好\n * const { value: theme, setValue: setTheme } = useUserPreference({\n *   key: 'theme',\n *   defaultValue: { mode: 'light', primaryColor: '#1677ff' },\n * });\n *\n * // 带 API 同步\n * const { value: layout, setValue: setLayout, loading } = useUserPreference({\n *   key: 'layout',\n *   defaultValue: { sidebarCollapsed: false, contentWidth: 'fluid' },\n *   fetchApi: (key) => getUserPreference(key),\n *   saveApi: (key, value) => saveUserPreference(key, value),\n * });\n *\n * // 使用\n * <Switch checked={!layout.sidebarCollapsed} onChange={(checked) =>\n *   setLayout(prev => ({ ...prev, sidebarCollapsed: !checked }))\n * } />\n * ```\n */\nexport function useUserPreference<T extends Record<string, unknown>>(\n  options: UseUserPreferenceOptions<T>,\n): UseUserPreferenceReturn<T> {\n  const {\n    key,\n    defaultValue,\n    storagePrefix = 'user-pref-',\n    enableCache = true,\n    fetchApi,\n    saveApi,\n    successCode = '200',\n    debounceMs = 500,\n  } = options;\n\n  const storageKey = `${storagePrefix}${key}`;\n\n  // 稳定引用\n  const defaultValueRef = useLatestRef(defaultValue);\n  const onChangeRef = useLatestRef(options.onChange);\n  const saveApiRef = useLatestRef(saveApi);\n  const fetchApiRef = useLatestRef(fetchApi);\n\n  // 安全访问 localStorage（SSR 保护）\n  const canUseStorage = typeof window !== 'undefined';\n\n  // 初始值: 尝试从缓存读取\n  const getInitialValue = (): T => {\n    if (!enableCache || !canUseStorage) return defaultValue;\n    try {\n      const cached = localStorage.getItem(storageKey);\n      if (cached) {\n        return { ...defaultValue, ...JSON.parse(cached) };\n      }\n    } catch {\n      // 解析失败, 使用默认值\n    }\n    return defaultValue;\n  };\n\n  const [value, setValueState] = useState<T>(getInitialValue);\n  const [loading, setLoading] = useState(false);\n  const [saving, setSaving] = useState(false);\n\n  // 防抖 timer\n  const debounceRef = useRef<ReturnType<typeof setTimeout>>(undefined);\n\n  // 缓存到 localStorage\n  const cacheToStorage = useCallback(\n    (val: T) => {\n      if (!enableCache || !canUseStorage) return;\n      try {\n        localStorage.setItem(storageKey, JSON.stringify(val));\n      } catch {\n        // 存储满了或不可用\n      }\n    },\n    [enableCache, canUseStorage, storageKey],\n  );\n\n  // 保存到 API\n  const saveToApi = useCallback(\n    async (val: T) => {\n      if (!saveApiRef.current) return;\n      setSaving(true);\n      try {\n        await saveApiRef.current(key, val);\n      } catch {\n        // 保存失败静默处理\n      } finally {\n        setSaving(false);\n      }\n    },\n    [key, saveApiRef],\n  );\n\n  // 纯 setValue — 无副作用\n  const setValue = useCallback((newValue: T | ((prev: T) => T)) => {\n    setValueState((prev) =>\n      typeof newValue === 'function'\n        ? (newValue as (prev: T) => T)(prev)\n        : newValue,\n    );\n  }, []);\n\n  // 副作用: value 变化时执行缓存、通知、防抖同步\n  const isInitialMount = useRef(true);\n  useEffect(() => {\n    // 跳过首次渲染 (初始值不需要触发副作用)\n    if (isInitialMount.current) {\n      isInitialMount.current = false;\n      return;\n    }\n\n    cacheToStorage(value);\n    onChangeRef.current?.(value);\n\n    if (saveApiRef.current) {\n      clearTimeout(debounceRef.current);\n      debounceRef.current = setTimeout(() => {\n        saveToApi(value);\n      }, debounceMs);\n    }\n  }, [value, cacheToStorage, saveToApi, debounceMs, onChangeRef, saveApiRef]);\n\n  // 重置\n  const reset = useCallback(() => {\n    setValue(defaultValueRef.current);\n  }, [setValue, defaultValueRef]);\n\n  // 手动同步\n  const sync = useCallback(async () => {\n    await saveToApi(value);\n  }, [saveToApi, value]);\n\n  // 首次加载: 从 API 获取（仅在 key 变化时重新请求）\n  useEffect(() => {\n    if (!fetchApiRef.current) return;\n\n    let cancelled = false;\n    setLoading(true);\n\n    fetchApiRef\n      .current(key)\n      .then((response) => {\n        if (cancelled) return;\n        const isSuccess = String(response.code) === String(successCode);\n        if (isSuccess && response.data) {\n          const merged = {\n            ...defaultValueRef.current,\n            ...(response.data as T),\n          };\n          setValueState(merged);\n          cacheToStorage(merged);\n        }\n      })\n      .catch(() => {\n        // 加载失败, 使用缓存值\n      })\n      .finally(() => {\n        if (!cancelled) setLoading(false);\n      });\n\n    return () => {\n      cancelled = true;\n    };\n  }, [key, successCode, cacheToStorage, defaultValueRef, fetchApiRef]);\n\n  // 清理防抖\n  useEffect(() => () => clearTimeout(debounceRef.current), []);\n\n  return {\n    value,\n    setValue,\n    reset,\n    loading,\n    saving,\n    sync,\n  };\n}\n"]}