npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@hw-component/hj

v1.10.94

Published

基于antd二次开发

Readme

@hw-component/hj 组件文档

基于 Ant Design 4.x 二次封装的 React 业务组件库。

环境要求

| 依赖 | 版本 | | --- | --- | | react | 17.0.0 | | react-dom | 17.0.2 | | antd | ^4.20.7 | | @ant-design/icons | 4.6.2 | | ahooks | 2.10.9 | | react-activation | ^0.12.1(使用 HXJ 系列组件时必须) |

快速开始

import React from "react";
import ReactDOM from "react-dom";
import { HJConfigProvider, HJIconSource, HJBody } from "@hw-component/hj";

// 1. 初始化 iconfont 图标源(全局仅需一次)
HJIconSource.create("/fontIcon/iconfont.js");

// 2. (可选)全局配置
ReactDOM.render(
  <HJConfigProvider bodyHeight={500}>
    <HJBody>内容</HJBody>
  </HJConfigProvider>,
  document.getElementById("root")
);

样式说明

  • 样式源码汇总于 src/components/styles/index.less,宿主项目引入该文件(或按组件目录单独引入对应 index.less)。
  • 所有类名基于 antd 的 prefixCls 生成(形如 ant-hj-xxx)。若宿主项目通过 ConfigProvider 修改了 antd 前缀,组件类名会自动跟随,无需额外处理。

全局配置

HJConfigProvider

全局配置容器,内部基于 React Context 实现,可配置项与组件默认配置递归深合并(组件自身传入的 props 优先级更高)。

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | bodyHeight | string \| number | - | 全局内容区最小高度,被 HJBody / HXJBody / HJTabPageLayout / HXJTabPageLayout 使用(作为 minHeight) | | errorPage | ErrorPageConfigModal | - | HJErrorPage 全局配置 | | emptyPage | EmptyPageConfigModal | - | HJEmptyPage 全局配置 |

interface ErrorPageConfigModal {
  image?: string; // 错误页图片
  sizeObj?: {
    middle?: { height?: number; defaultStyle?: React.CSSProperties };
    small?: { height?: number; defaultStyle?: React.CSSProperties };
  };
}
interface EmptyPageConfigModal {
  bgImgSrc?: string; // 空数据页背景图
  imageStyle?: React.CSSProperties; // 图片样式
}

HJIconSource

iconfont 图标源管理(单例)。基于 @ant-design/iconscreateFromIconfontCN 封装。

| 方法/属性 | 类型 | 说明 | | --- | --- | --- | | create(scriptUrl, prefix?) | (url: string, prefix?: string) => void | 创建全局图标源,全局只能调用一次,重复调用会告警并忽略 | | CustomIcon | React.FC | 创建成功后可用的图标组件(一般不直接使用) | | prefix | string | 图标 type 前缀 |


基础组件

HJSpace 间距容器

对 antd Space 的封装。默认 direction="vertical" 时自动占满宽度(width: 100%),适合表格单元格内的多行信息布局。

<HJSpace size={4}>
  <div>第一行</div>
  <div>第二行</div>
</HJSpace>

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | direction | "vertical" \| "horizontal" | "vertical" | 排列方向 | | 其余属性 | SpaceProps | - | 透传 antd Space |

HJModal 弹窗

对 antd Modal 的封装。去掉了右上角关闭按钮与底部按钮区,改为底部居中圆形关闭图标,内容区零内边距,适合自定义内容弹窗。

<HJModal visible={visible} onCancel={() => setVisible(false)}>
  自定义内容
</HJModal>

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | visible | boolean | - | 是否可见 | | onCancel | () => void | - | 点击底部关闭图标时的回调 | | 其余属性 | ModalProps | - | 透传 antd Modal(closablefooterbodyStyle 已被固定) |

HJCard 卡片

对 antd Card 的封装。提供标准化的**页头(title)/内容区/页脚(footer)**三段式结构,title 与 footer 既可以是 ReactNode,也可以是 { text, action, style } 对象(左文案 + 右操作自动两端对齐)。

// 对象写法:左侧标题 + 右侧操作
<HJCard title={{ text: "卡片标题", action: <a>更多</a> }} footer="页脚">
  内容
</HJCard>

// headerNoStyle:不套用头部样式,直接渲染原始节点
<HJCard title={<MyHeader />} headerNoStyle>
  内容
</HJCard>

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | title | ReactNode \| { text?: ReactNode; action?: ReactNode; style?: CSSProperties } | - | 页头 | | footer | 同 title | - | 页脚 | | headerNoStyle | boolean | false | 为 true 时页头不套用默认样式容器 | | bodyStyle | CSSProperties | - | 内容区样式 | | 其余属性 | CardProps | - | 透传 antd Card(bodyStyle.padding 固定为 0) |

HJAlert 警告提示

对 antd Alert 的扩展。新增 content / danger 两种业务类型,支持展开/收起长文案。

// danger 类型:使用自定义错误图标与浅橙背景
<HJAlert type="danger" message="错误提示" showIcon />

// 支持展开/收起
<HJAlert
  type="content"
  message="提示内容"
  description={<>很长很长的描述…</>}
  showAlert={{ defaultVisible: false }}
/>

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | type | AlertProps["type"] \| "content" \| "danger" | - | content 映射为 antd warning(浅橙背景 #FFF7F0);danger 映射为 error(自定义错误图标) | | showAlert | boolean \| { visible?: boolean; defaultVisible?: boolean; onChange?: (v: boolean) => void } | - | 开启展开/收起功能;受控/非受控均可 | | 其余属性 | AlertProps | - | 透传 antd Alert(type 除外) |

HJLabel 标题标签

带左侧色条的标题组件,常用于区块标题。支持主标题、副标题、悬浮说明、右侧操作区。

<HJLabel
  title="基础信息"
  dec="(选填)"
  hover={["说明一", "说明二"]}
  size="middle"
  action={<a>编辑</a>}
/>

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | title | ReactNode | - | 主标题(必填) | | dec | ReactNode | - | 副标题(secondary 弱化样式) | | size | "small" \| "middle" \| "lg" | "small" | 字号 | | hover | string \| string[] | - | 标题旁问号图标的悬浮提示内容(复用 HJTooltip) | | fontWeight | string \| number | "normal" | 主标题字重 | | spaceSize | number | 8 | 主标题右侧间距 | | action | ReactNode | - | 右侧操作区 | | style | CSSProperties | - | 容器样式 |

HJTooltip 文字提示

对 antd Tooltip 的封装。三种形态:包裹子元素 / 独立问号图标 / 纯图标模式;title 支持数组自动竖排展示。

// 1) 子元素 + 问号图标
<HJTooltip title={["提示一", "提示二"]}>设置</HJTooltip>

// 2) 独立问号图标
<HJTooltip title="说明文案" />

// 3) 无图标纯包裹(icon={false})
<HJTooltip icon={false} title="说明文案"><span>文字</span></HJTooltip>

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | title | string \| string[] \| ReactNode | - | 提示内容;数组时竖排展示 | | icon | ReactNode \| false | 问号图标 | 自定义提示图标;false 表示不渲染图标(纯包裹模式) | | iconStyle | CSSProperties | - | 图标样式 | | iconStopPropagation | boolean | false | 点击图标时是否阻止事件冒泡(表格行内常用) | | 其余属性 | TooltipProps | - | 透传 antd Tooltip(title 除外) |

HJCopy 复制

点击复制文本,支持单条 / 多条两种形态。多条时以 Link 列表展示并用分隔符隔开,各自独立复制。

// 单条
<HJCopy text="123456">订单号</HJCopy>

// 多条:字符串数组或对象数组
<HJCopy
  text={[
    { copyText: "A123", content: "单号A" },
    { copyText: "B456", content: "单号B" },
  ]}
/>

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | text | string \| string[] \| { copyText: string; content: ReactNode; successMsg?: string }[] | - | 待复制内容(必填) | | separate | ReactNode | "," | 多条之间的分隔符 | | wrap | boolean | true | 多条是否可换行 | | label | ReactNode | - | 多条模式下的前置标签 | | successMsg | string | "复制成功!" | 复制成功提示文案 | | itemRender | (item) => item | - | 自定义每条 item 的转换逻辑 | | onClick | (data: string, item) => void | - | 覆盖默认复制行为 |

HJImage 图片

带加载态、空态、悬浮预览的图片容器。支持四种自适应模式(imgMode),其中 fullBody / fullImg 会先加载图片获取真实尺寸,再与容器尺寸比较自动选择铺满方向。

// 固定尺寸 + 悬浮预览
<HJImage width={80} height={80} src={url} />

// 通过请求获取图片地址
<HJImage width={60} request={() => fetchImgUrl()} imgMode={HJImgMode.fullBody} />

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | src | string | - | 图片地址;与 request 二选一 | | request | () => Promise<string> | - | 异步获取图片地址 | | width / height | number | - | 容器尺寸;height 缺省时取 width | | imgMode | HJImgMode | "height" | width:按宽铺满;height:按高铺满;fullBody:图完全在容器内且铺满一边;fullImg:图铺满整个容器(可能裁切) | | preview | boolean | true | 是否开启悬浮"预览"遮罩(点击打开大图) | | loading | boolean | - | 外部控制加载态 | | emptyNode | ReactNode | 内置空图 | 无图时的占位节点 | | className / style | - | - | 容器样式 |

HJIcon iconfont 图标

渲染通过 HJIconSource.create() 注册的 iconfont 图标。

<HJIconSource.create("/fontIcon/iconfont.js"); />
<HJIcon iconType="edit" onClick={...} />

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | iconType | string | - | 图标名(会自动拼接 HJIconSource.create 时设置的 prefix)(必填) | | onClick | MouseEventHandler | - | 点击事件 | | className / style | - | - | 样式 | | 其余属性 | CustomIconOptions | - | 透传 antd IconFont |


按钮组件

HJBtn 按钮

对 antd Button 的封装。新增 request 能力:传入请求函数后点击自动发起请求并管理 loading,成功后触发 onSuccess;未传 request 时行为同原生按钮。默认圆角 4px。

// 请求按钮:自动 loading
<HJBtn
  type="primary"
  request={() => api.save()}
  onSuccess={() => message.success("保存成功")}
>
  保存
</HJBtn>

// 普通按钮
<HJBtn onClick={handleClick}>取消</HJBtn>

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | request | () => Promise<any> | - | 点击后自动执行的请求;传入后 onClick 不再生效 | | onSuccess | (data) => void | - | 请求成功回调 | | 其余属性 | ButtonProps | - | 透传 antd Button |

HJIconBtn 图标按钮

HJBtn 之上叠加 iconfont 图标 + 文案的组合按钮,图标与文字间距 4。

<HJIconBtn iconType="edit" onClick={...}>
  编辑
</HJIconBtn>

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | iconType | string | - | HJIcon 图标名 | | 其余属性 | HJBtnProps | - | 透传 HJBtn |

HJCountdownBtn 倒计时按钮

点击(或请求成功)后进入倒计时禁用状态,结束后恢复。通过 ref 暴露 start / reset

const ref = useRef<HJCountdownBtnRefModal>(null);

<HJCountdownBtn ref={ref} countdownNum={60} onClick={sendSms}>
  发送验证码
</HJCountdownBtn>;
// ref.current.start() 手动开始倒计时

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | countdownNum | number | 10 | 倒计时秒数 | | countdownRender | (num: number \| null) => ReactNode | 确定 / 确定(Ns) | 按钮文案渲染 | | ref(HJCountdownBtnRefModal) | { start: () => void; reset: () => void } | - | 命令式控制 | | 其余属性 | HJBtnProps | - | 透传 HJBtn(内部会透传 onSuccess 驱动倒计时) |

HJPopconfirmBtn 气泡确认按钮

Popconfirm + 按钮的组合。确认后可自动发请求(ok 按钮带 loading),支持完全自定义触发节点。

// 默认形态:link 小按钮
<HJPopconfirmBtn
  node="删除"
  request={() => api.del(id)}
  onSuccess={reload}
/>

// 自定义确认文案 / 位置 / 触发节点
<HJPopconfirmBtn title="确定下架吗?" placement="top" btnProps={{ iconType: "close" }} node="下架" />

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | title | ReactNode | "删除将无法恢复,确定删除吗?" | 确认提示文案 | | request | () => Promise<any> | - | 确认后自动执行的请求(ok 按钮自动 loading) | | onSuccess | (data) => void | - | 请求成功回调 | | node | ReactNode | - | 按钮内容 | | btnProps | IconBtnProps | {} | 透传给内部 HJIconBtn / HJBtn;传了 iconType 用图标按钮 | | render | (loading: boolean) => ReactNode | - | 完全自定义触发节点(优先级最高) | | 其余属性 | PopconfirmProps | - | 透传 antd Popconfirm(title 除外) |

HJPopCountdown 气泡确认倒计时

PopconfirmBtn 的倒计时版本:气泡展开后确认按钮进入倒计时禁用,收起即重置。适用于"高风险操作需阅读"场景。

<HJPopCountdown
  node="删除"
  countdownNum={5}
  request={() => api.del(id)}
  onSuccess={reload}
/>

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | countdownNum | number | 10 | 确认按钮倒计时秒数 | | countdownRender | (num: number \| null) => ReactNode | 确定 / 确定(Ns) | 确认按钮文案 | | onVisibleChange | (visible: boolean) => boolean \| Promise<boolean> | - | 返回 false 可拦截气泡显隐 | | 其余属性 | HJPopconfirmBtnProps | - | 透传 HJPopconfirmBtn |

HJOperateBtn 操作按钮组

表格"操作"列标准组件。根据 config 渲染一组 link 小按钮,项之间自动加竖线分隔符;支持按行数据动态显隐、删除类操作自动套 Popconfirm、按钮级请求。

<HJOperateBtn
  data={record} // 行数据,传给 show / request / onClick
  config={[
    { key: "edit", node: "编辑", show: (data) => data.canEdit },
    { key: "del", node: "删除", delTips: true, placement: "top" },
    { key: "copy", node: "复制", noBtn: true }, // node 自渲染,不加按钮样式
  ]}
  onClick={(key, data) => {
    if (key === "edit") openModal(data);
  }}
  requestConfig={{ del: (data) => api.del(data.id) }}
  onSuccess={reload}
/>

config 项(ConfigModal):

| 字段 | 类型 | 说明 | | --- | --- | --- | | node | ReactNode | 按钮内容(必填) | | key | string | 唯一标识,onClick / requestConfig 依据 | | delTips | string \| boolean | 传 true 用默认删除确认语;传字符串自定义;配置后自动套 Popconfirm | | show | boolean \| (data) => boolean | 动态显隐 | | placement | TooltipPlacement | Popconfirm 弹出位置 | | noBtn | boolean | 为 true 时不套按钮样式,直接 clone node 并注入 btnStyle(用于嵌套 DropdownBtn 等) |

组件 props(HJOperateBtnProps):

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | config | ConfigModal[] | - | 按钮配置(必填) | | data | Record<string, any> | {} | 行数据 | | onClick | (key, data) => void | - | 无 request 时的点击回调 | | requestConfig | Record<string, (data) => Promise> | {} | 按 key 配置按钮请求,确认后自动执行并 loading | | onSuccess | () => void | - | 任一请求成功回调 | | hr | boolean | true | 按钮间是否显示竖线分隔 | | containerRender | (node, config) => ReactNode | - | 包裹每个按钮的自定义渲染(如套 Tooltip) | | emptyNode | ReactNode | "-" | 过滤后无按钮时的占位 |

HJOperateBtnMaxCount 限额操作按钮组

HJOperateBtn 的数量上限版本:可见按钮超过 maxCount 时,前 maxCount - 1 个正常展示,剩余收进"更多"下拉(内部使用 HJDropdownBtn,delTips 转为 confirmText)。

<HJOperateBtnMaxCount
  maxCount={3}
  actionNode="更多"
  data={record}
  config={[{ key: "a", node: "操作A" }, ...]}
  requestConfig={{ a: (data) => api.a(data.id) }}
  onSuccess={reload}
/>

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | maxCount | number | - | 最大可见按钮数(含"更多") | | config | CountConfigModal[] | - | 同 HJOperateBtn 的 config | | actionNode | ReactNode | - | "更多"下拉触发按钮文案 | | actionPosition | OperateBtnPosition | end | "更多"收起位置:start(第一位)/ end(最后一位) | | 其余属性 | HJOperateBtnProps | - | 透传 HJOperateBtn |

HJDropdownBtn 下拉操作按钮

表格"操作"列下拉形态。菜单项支持二级嵌套、按行数据显隐、点击直接执行请求、确认弹窗(confirmText)与确认倒计时(countdown)。

<HJDropdownBtn
  data={record}
  config={[
    { key: "edit", label: "编辑" },
    {
      key: "more",
      label: "更多",
      children: [
        { key: "del", label: "删除", confirmText: "删除后无法恢复", countdown: 3, request: (d) => api.del(d.id) },
      ],
    },
  ]}
  onClick={(checkData, data) => console.log(checkData.key, data)}
  onSuccess={reload}
/>

config 项(DropdownBtnConfigData):

| 字段 | 类型 | 说明 | | --- | --- | --- | | label | ReactNode | 菜单名(必填) | | key | string | 唯一标识(必填) | | children | DropdownBtnConfigData[] | 二级菜单 | | show | (data) => boolean | 动态显隐(注意:接收的是整个 config 数据) | | confirmText | ReactNode | 配置后点击弹出确认弹窗 | | countdown | number | 确认弹窗确定按钮的倒计时秒数 | | request | (data) => Promise | 点击(确认后)自动执行的请求 |

组件 props(HJDropdownBtnProps):

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | config | DropdownBtnConfigData[] | - | 菜单配置(必填) | | data | T | - | 行数据,传给 request / onClick | | onClick | (checkData: { key, keyPath }, data) => void | - | 无 request/confirmText 项的点击回调 | | requestConfig | Record<string, (params) => Promise> | {} | 按 key 集中配置请求(与 config.request 二选一,支持嵌套对象按层级配置) | | onSuccess | () => void | - | 请求成功回调 | | btnStyle | CSSProperties | - | 触发按钮样式 | | hideIcon | boolean | - | 隐藏默认的下拉箭头 | | arrow | boolean | true | 下拉箭头(antd) | | emptyNode | ReactNode | "-" | 菜单为空时的占位 | | 其余属性 | DropdownProps | - | 透传 antd Dropdown(overlay 除外) |


布局组件

HJBody 页面容器

标准页面容器:操作区(action)+ 内容区 + 底部区(footer),内容区自动接管 loading / error / 空数据状态(内部使用 HJLoadingHandler)。高度自动应用 HJConfigProvider.bodyHeight(作为 minHeight)。

<HJBody
  action={<Space>...筛选区</Space>}
  footer={<HJAffixFooter />}
  loadingHandler={{ loading, error, data, reload }}
>
  <Table ... />
</HJBody>

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | action | ReactNode | - | 顶部操作区(自带底部内边距) | | footer | ReactNode | - | 底部区域 | | noPadding | boolean | false | 内容区去除内边距 | | bodyStyle | CSSProperties | - | 内容区样式 | | actionStyle | CSSProperties | - | 操作区样式 | | loadingHandler | LoadingHandlerProps | - | 内容区状态配置(loading/error/data 等,见 HJLoadingHandler) | | className / style | - | - | 容器样式 |

HXJBody 页面容器(留白变体)

HJBody 的变体,类名与默认留白不同:noPadding 时内容区上下留白 20px、操作区去除内边距,适合内嵌 Tab 等场景。

<HXJBody noPadding footer={...}>
  <SourceTabBar />
</HXJBody>

Props 同 HJBody

HJTabPage 页签页容器

Body + Tabs 的组合:顶部 antd Tabs 页签,外层带 action / footer 插槽。

<HJTabPage
  config={[
    { key: "base", label: "基础设置", node: <BasePanel /> },
    { key: "adv", label: "高级设置", node: <AdvPanel />, forceRender: true },
  ]}
  footer={<HJAffixFooter />}
/>

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | config | ConfigModal[] | - | 页签配置(必填) | | contentNoPd | boolean | - | 内容区去除内边距 | | forceRender | boolean | - | 所有面板默认预渲染 | | 其余属性 | TabsProps | - | 透传 antd Tabs |

config 项(ConfigModal,HJBody 系列通用):

| 字段 | 类型 | 说明 | | --- | --- | --- | | node | ReactNode | 面板内容(必填) | | label | ReactNode | 页签名(必填) | | key | string | 唯一标识,缺省取索引 | | forceRender | boolean | 预渲染 |

HXJTabPage 页签页容器(留白变体)

HJTabPage 的变体(内部使用 HXJBody),适合内嵌在其它容器中的二级页签。

Props 同 HJTabPage

HJTabPageLayout 侧边页签布局

左侧菜单 + 右侧内容的双栏布局。面板用 react-activation 的 KeepAlive 缓存,切换页签不丢状态;卸载时自动清理缓存,通过 ref 可手动刷新缓存。

const ref = useRef<HJTabPageLayoutRef>(null);

<HJTabPageLayout
  ref={ref}
  config={[
    { key: "base", label: "基础设置", node: <BasePanel /> },
    { key: "adv", label: "高级设置", node: <AdvPanel />, noPd: true },
  ]}
  activeKey={key}
  onChange={setKey}
  action={<Breadcrumb />}
  footer={<HJAffixFooter />}
/>;
// ref.current.refresh() 手动刷新当前缓存

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | config | ConfigModal[] | - | 页签配置(同上,另支持 noPdbodyStyle) | | activeKey | string | 首项 | 受控选中 key | | onChange | (key: string) => void | - | 切换回调(受控模式必传) | | action | ReactNode | - | 顶部操作区 | | footer | ReactNode | - | 底部区域 | | contentNoPd | boolean | - | 所有内容区去内边距 | | menuStyle | CSSProperties | - | 左侧菜单样式 | | className / style | - | - | 容器样式 | | ref(HJTabPageLayoutRef) | { refresh: () => void } | - | 刷新 KeepAlive 缓存 |

HXJTabPageLayout 侧边页签布局(增强版)

在 HJTabPageLayout 基础上增强:菜单搜索、拖拽排序、菜单项自定义渲染(编辑/删除),config 支持受控更新。适合"自定义工作台页签"场景。

<HXJTabPageLayout
  drag
  config={config}
  onChange={setConfig} // 受控:拖拽/删除/编辑后回传新 config
  menuItemRender={({ data, dragNode, del, edit, actived }) => (
    <div onClick={del}>...</div>
  )}
  searchRender={(inputNode, onSearch) => inputNode}
  activeChange={(key) => ...}
/>

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | config | TabPageLayoutConfig[](label 为 string) | - | 页签配置,支持受控 | | onChange | (config) => void | - | config 变更回调(拖拽排序/删除/编辑时触发) | | activeKey | string | 首项 | 受控选中 key | | activeChange | (key: string) => void | - | 切换回调(与 onChange 职责分离) | | drag | boolean | - | 开启菜单拖拽排序 | | menuItemRender | (params: { data; dragNode; del: (index) => void; edit: (index, patch) => void; actived }) => ReactNode | - | 自定义菜单项渲染;del/edit 由组件提供 | | searchRender | (inputNode, onSearch) => ReactNode | - | 菜单搜索区渲染(按 label 过滤) | | emptyMenuRender | (emptyNode) => ReactNode | - | 菜单为空时渲染 | | emptyContentRender | (emptyNode) => ReactNode | - | 内容区为空时渲染 | | footer | ReactNode | - | 底部区域 | | contentNoPd | boolean | - | 内容区去内边距 | | ref(HJTabPageLayoutRef) | { refresh: () => void } | - | 刷新 KeepAlive 缓存 |

注意:del 删除项时会同步清理对应 KeepAlive 缓存,若删除的是当前激活项会自动切换到相邻项。

HJAffixSource 底部吸附容器

对 antd Affix 的封装:吸底时自动切换为全宽白色带阴影样式。

<HJAffixSource target={() => window} affixedStyle={{ padding: 16 }}>
  自定义底部内容
</HJAffixSource>

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | hideAffix | boolean | - | 为 true 时不吸附,直接渲染 | | affixedStyle | CSSProperties | - | 吸附后的样式 | | safeNoShadow | boolean | - | 未吸附时是否去除阴影 | | target | () => HTMLElement | window | 滚动容器(antd) | | 其余属性 | AffixProps | - | 透传 antd Affix |

HJAffixFooter 底部吸附保存栏

吸附容器 + 提示文案 + 保存按钮的标准组合。

<HJAffixFooter message="设置完成,记得保存哦!" btnProps={{ request: save, onSuccess }} />
// 或完全自定义按钮
<HJAffixFooter btnNode={<MyBtn />} />

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | message | string | "设置完成,记得保存哦!" | 左侧提示文案,传空串隐藏 | | icon | ReactNode | - | 提示文案前图标 | | btnNode | ReactNode | 默认保存按钮 | 完全自定义右侧按钮 | | btnProps | HJBtnProps | - | 默认保存按钮的 props(type 默认 primary) | | 其余属性 | HJAffixProps | - | 透传 HJAffixSource |


页面状态组件

HJShowChild 条件渲染

最简单的显隐容器,常用于动态插槽。

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | show | boolean | - | 为 true 时渲染 children |

HJPageLoading 加载中

带遮罩的全页加载容器。

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | spinning | boolean | - | 显示加载遮罩 | | tip | string | "拼命加载中..." | 加载文案 | | loadingStyle | CSSProperties | - | 遮罩样式(如背景色) | | wrapperClassName / style | - | - | 容器样式 | | 其余属性 | SpinProps | - | 透传 antd Spin |

HJLoadingHandler 页面状态处理

页面加载/错误/空数据三态自动切换的标准容器(loading 遮罩 + 错误页 + 空数据占位)。

<HJLoadingHandler loading={loading} error={error} data={data} reload={reload}>
  <Table dataSource={list} />
</HJLoadingHandler>

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | loading | boolean | false | 加载中 | | error | Error | - | 错误对象(展示 error.message 与刷新按钮) | | data | any | - | 业务数据,空值时按空数据处理 | | reload / run | () => void | - | 错误页"刷新"按钮回调 | | loadingHideInData | boolean | - | 有数据时隐藏 loading 遮罩(避免遮挡列表) | | noDataEmpty | boolean | true | 无数据时是否渲染空占位(高度 368 的空白块) | | destroyOnLoading | boolean | false | 加载中是否卸载 children | | loadingStyle / errorStyle / style | CSSProperties | - | 各区域样式 |

HJAutoPageHandler 请求页面容器

"请求 + 三态处理 + 页面容器"一体化:内部用 ahooks useRequest 发起请求,自动接管 loading/error/data,外层套 HJBody。

<HJAutoPageHandler
  request={() => api.getDetail(id)}
  options={{ refreshDeps: [id] }}
  render={({ data, reload }) => (
    <Detail data={data} onSaved={reload} />
  )}
/>

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | request | (...args) => Promise<R> | - | 请求函数(必填) | | render | (result: { data; reload }) => ReactNode | - | 内容渲染(必填);reload 即重新请求 | | options | BaseOptions | - | ahooks useRequest 配置 | | bodyProps | HJBodyProps | {} | 透传 HJBody | | noWrapper | boolean | - | - | | 其余属性 | LoadingHandlerProps | - | 透传 HJLoadingHandler |

HJSkeletonLoading 骨架屏容器

加载中显示骨架屏,有数据渲染内容,出错显示错误页。

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | data | any | - | 业务数据(必填) | | loading | boolean | - | 加载中 | | error | Error | - | 错误对象 | | reload | () => void | - | 错误页刷新回调 | | 其余属性 | SkeletonProps | - | 透传 antd Skeleton |

HJEmptyPage 空数据页

基于 antd Empty 的空数据页,支持通过 HJConfigProvider.emptyPage 全局定制背景图与尺寸。

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | description | string | "暂无数据~" | 描述文案 | | bgImgSrc | string | 内置背景图 | 背景图(可全局配置) | | imageStyle | CSSProperties | { height: 167 } | 图片样式(可全局配置) | | className / style | - | - | 容器样式 |

HJEmptyPageHandler 空数据处理器

isEmpty 为 true 时渲染 HJEmptyPage,否则渲染 children。

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | isEmpty | boolean | - | 是否为空 | | 其余属性 | IEmptyPageProps | - | 透传 HJEmptyPage |

HJErrorPage 错误页

错误信息 + 刷新按钮的标准错误页,支持通过 HJConfigProvider.errorPage 全局定制图片与尺寸。

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | error | Error | - | 错误对象,message 作为描述(必填) | | reload | () => void | - | 刷新按钮回调 | | size | "middle" \| "small" | "middle" | 尺寸(决定图片高度与留白) | | style | CSSProperties | - | 容器样式 |


页签组件

HJBtnTab 按钮组页签

Radio.Button 风格的页签切换(按钮组形态),面板复用 antd Tabs 渲染。

<HJBtnTab
  config={[
    { key: "day", label: "日榜", node: <DayTable /> },
    { key: "week", label: "周榜", node: <WeekTable /> },
  ]}
  activeKey={key}
  onChange={setKey}
/>

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | config | { label; key?; node?; forceRender? }[] | - | 页签配置(必填) | | activeKey | string | 首项 | 受控选中 key | | defaultActiveKey | string | 首项 | 初始选中 key | | onChange | (key: string) => void | - | 切换回调(受控模式必传) | | tabBarStyle | CSSProperties | - | 按钮组容器样式 | | bodyNoPd | boolean | - | 内容区去内边距 |

HJBtnTabBar 按钮组页签栏

HJBtnTab 的按钮组部分(不含面板),用于自定义面板场景。

Props 同 HJBtnTab(仅渲染按钮组)。


表格业务渲染组件(HJTableRender)

电商/订单类后台表格的标准单元格渲染器。

HJProductMsg 商品信息

商品图 + 标题(可链接、溢出提示)+ 店铺/付费信息 + 来源图标组(Tooltip 说明)+ 底部插槽。

<HJProductMsg
  img={record.img}
  link={record.url}
  title={record.title}
  shopName={record.shopName}
  payNum={record.payNum}
  sourceIcons={[SourceIconType.tm, SourceIconType.jhs]}
  footer={<div>...</div>}
/>

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | title | string | - | 商品标题(必填),溢出省略 + 悬浮全文 | | img | string | 内置占位图 | 商品图 | | link | string | - | 标题跳转链接(新窗口) | | shopName | string | - | 店铺名(溢出省略) | | payNum | string \| null | - | 付费金额,渲染为 付费:¥xx;传 null 不渲染 | | sourceIcons | SourceIconType[] | - | 来源图标组,枚举见下 | | content | ReactNode | - | 覆盖默认的店铺/付费信息区域 | | footer | ReactNode | - | 底部插槽 |

SourceIconType 枚举(28 项,含图标与内置提示语):appsuperRed(超红)、cmsdirectional(定向)、elm(饿了么)、fliggy(飞猪)、officialAccount(公众号)、group(社群发单)、jhs(聚划算)、pcRobot / androidRobot / pcEnterpriseRobot / ipadRobot(各类机器人)、kill(杀熟)、freeOrder(免单)、crossStore(跨店)、tb(淘宝)、tbSpecialOffer(淘宝特价)、there(三方)、recommend(推荐)、sameStore(同店)、tm(天猫)、tmgj(天猫国际)、wxPyq(微信朋友圈)、minApp(小程序)、dy(抖音)、dyGroup(抖团)、ks(快手)、pdd(拼多多)、vph(唯品会)、jd(京东)。

HJSingleProductMsg 商品信息(精简)

仅图 + 标题(点击跳转)的精简版。

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | title | string | - | 标题(必填) | | img | string | 内置占位图 | 商品图 | | link | string | - | 点击图/标题新窗口打开 |

HJProductSourceMsg 佣金信息渲染器

通用两列布局渲染器:将 config 按每行 2 项切分,项间竖线分隔,key 交给 render 产出节点。

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | config | { key: string; node?: ReactNode }[] | - | 渲染项;有 node 用 node,否则调 render(必填) | | render | (key: string) => ReactNode | - | 按 key 渲染内容(必填) |

HJProductRebateMsg 佣金信息(标准)

收入 / 提成 / 买家收入 / 利润(正绿负红)/ 其他(可展开下拉明细)五项,每行 2 项布局。

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | income | number | - | 收入:¥xx | | commission | number | - | 提成:xx% | | buyIncome | number | - | 买家:¥xx | | profit | number | - | 利润:¥xx(>0 绿色,<0 红色) | | other | number | - | 其他:¥xx(配合 dropdownConfig 可展开明细) | | dropdownConfig | { label: string; key?: string }[] | - | “其他”下拉明细 | | render | (key, node) => ReactNode | 原样返回 | 每项内容的二次包装 |

HJTCRebate 佣金信息(团长)

团长版:收入 / 买家收入 / 利润 / 其他 四项。Props 同 HJProductRebateMsg

HJProductVphRebateMsg 佣金信息(唯品会)

唯品会版:收入 / 提成 / 买家 / 礼金支出 / 补贴 / 利润 / 其他 七项。在标准版基础上新增:

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | vphReward | number | - | 礼金支出:¥xx | | 其余 | HJProductRebateProps | - | 同标准版(另渲染补贴 subsidyCommission) |

HJDUMsg / HJDUMsgHideRemark 用户信息

表格中"用户/推广者"单元格:名字 + 备注 + ID 复制。HJDUMsgHideRemark 不展示备注。

<HJDUMsg id={record.duId} name={record.duName} remark={record.remark} onClick={...} />

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | id | string | - | 用户 ID(必填),展示为可复制链接 | | name | string | - | 名字,缺省 - | | remark | string | - | 备注,缺省 -(仅 HJDUMsg) | | onClick | () => void | - | 名字点击回调 |

HJRowMsg 多行文本

多个字符串竖排展示,空值补 -

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | text | string[] | - | 文本数组(必填) |


拖拽排序组件(HJSortComponent)

基于 react-sortable-hoc 封装的列表拖拽排序方案。

HJSortContainer 拖拽排序容器

受控数据驱动:拖拽结束自动计算新顺序并回调 onChangerender 内提供每项的 add / del 增删能力。

<HJSortContainer
  data={list}
  onChange={setList}
  render={({ data, index, add, del }) => (
    <div>
      <HJDragHandle>拖拽把手</HJDragHandle>
      {data.name}
      <a onClick={() => add({ id: Date.now(), name: "新项" })}>插入</a>
      <a onClick={() => del()}>删除</a>
    </div>
  )}
/>

| Prop | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | data | T[] | - | 列表数据(必填);建议每项含 id 作为 key | | render | (params: { data: T; index: number; add: (value, index?) => void; del: (index?) => void }) => ReactNode | - | 每项渲染(必填);add 默认插到当前项之后,del 默认删除当前项 | | onChange | (data: T[]) => void | - | 排序/增删后的新数据回调 | | sortableItemProps | { style?: CSSProperties } | - | 每项包裹层样式 | | 其余属性 | SortableContainerProps | - | 透传 react-sortable-hoc(如 useDragHandlehelperClassonSortEnd) |

HJSortableItem 可排序项

SortableElement 包裹的项容器(HJSortContainer 内部已使用,一般不单独使用)。

HJDragHandle 拖拽把手

SortableHandle 包裹的把手容器。配合容器的 useDragHandle 使用,可实现"仅把手可拖拽"。

<HJSortContainer useDragHandle ... render={({ data }) => (
  <HJDragHandle style={{ cursor: move}}>{data.name}</HJDragHandle>
)} />