@stoly/react-component
v1.0.6
Published
antd6.x 组件封装
Readme
@stoly/react-component
基于 antd 6.x 封装的 React 业务组件库,提供表格查询、弹窗、布局、Excel 导出等开箱即用的能力。
安装
npm install @stoly/react-component
# 或
pnpm add @stoly/react-component安装 Agent Skill
本库附带 Agent Skill,安装后 AI 编码助手(Cursor / Claude Code 等)能自动获得组件用法指引。
# 安装到当前项目
npx skills add ./node_modules/@stoly/react-component
# 全局安装(跨项目可用)
npx skills add ./node_modules/@stoly/react-component -gPeer Dependencies
请确保项目中已安装以下依赖:
{
"@ant-design/icons": ">=6",
"antd": ">=6",
"react": ">=19",
"react-dom": ">=19",
"styled-components": "6.x",
"lodash-es": ">=4.17.21",
"rc-scrollbars": "^1.1.6",
"react-router-dom": "6.x",
"copy-to-clipboard": "^3.3.3",
"exceljs": "^4.4.0",
"react-draggable": "^4.4.6",
"scroll-into-view-if-needed": "^3.1.0"
}快速开始
一个典型的「表格查询 + 弹窗」页面:
import { useRef } from 'react'
import { Form, Input, Space } from 'antd'
import { RcTable, RcTableForm, RcModal, type RcTableRef, type RcQueryData } from '@stoly/react-component'
interface Query extends RcQueryData {
name?: string
}
interface Row {
id: number
name: string
}
const ListPage = () => {
const query = RcTableForm.useQuery<Query>()
const controller = RcTableForm.useController()
const modal = RcModal.useModal<Row>()
const tableRef = useRef<RcTableRef<Row>>(null)
const columns = [
{ title: '姓名', dataIndex: 'name', key: 'name' },
{
...RcTable.OperateColumnProps,
render: (_: unknown, record: Row) => (
<Space>
<a onClick={() => modal.open(record)}>编辑</a>
<a onClick={() => RcModal.confirm({ api: deleteApi, params: record.id, query })}>
删除
</a>
</Space>
),
},
]
return (
<>
<RcTableForm<Query> query={query} controller={controller}>
<Form.Item name="name" label="姓名">
<Input placeholder="请输入姓名" />
</Form.Item>
</RcTableForm>
<RcTable<Row, any, any, Query>
ref={tableRef}
query={query}
api={fetchList}
queryFormat={(q) => q}
dataFormat={(res) => ({ rows: res.data.list, total: res.data.total })}
columns={columns}
rowKey="id"
/>
<RcModal title="编辑" open={modal.visable} onCancel={modal.close} fullScreenModal>
{/* 弹窗内容 */}
</RcModal>
</>
)
}组件
RcTable 数据表格
对 antd Table 的增强封装,集成数据请求、分页、排序、右键菜单、列配置、密度切换等功能。
Props
继承 antd
TableProps<T>(移除dataSource/loading/components/onChange)
| 属性 | 类型 | 必传 | 说明 |
|------|------|:----:|------|
| query | SearchQuery<Q> | ✅ | 查询条件,由 RcTableForm.useQuery 创建 |
| api | (params: P) => Promise<R> | ✅ | 数据请求接口 |
| queryFormat | (q: Q) => P | ✅ | 查询条件 → 接口参数的转换函数 |
| dataFormat | (res: R) => { rows: T[], total: number } | ✅ | 接口返回值 → 表格数据的转换函数 |
| showIndex | boolean | - | 显示序号列(按当前页计算) |
| exported | boolean | - | 启用右键导出 Excel(仅适用于简单表头) |
Ref
通过 ref 获取表格实例:
const tableRef = useRef<RcTableRef<Row>>(null)
const data = tableRef.current?.getCurrentData() // { rows, total }静态属性
RcTable.OperateColumnProps— 操作列默认配置:{ align: 'center', title: '操作', width: 120, fixed: 'right', className: 'noCopy' }RcTable.Context— 通过 render props 获取当前表格数据
内置功能
- 右键菜单:刷新、复制单元格、复制行、导出行/导出当前页(需开启
exported) - 列配置:通过底部齿轮按钮切换列可见性,拖拽排序
- 密度切换:默认 / 紧凑
- 回到顶部:滚动超过 100px 时显示
RcTableForm 查询表单
与 RcTable 配合使用的查询表单,自动管理查询/重置/分页逻辑。
Props
继承 antd
FormProps<T>(移除form)
| 属性 | 类型 | 必传 | 说明 |
|------|------|:----:|------|
| query | SearchQuery<T> | ✅ | 查询条件 |
| controller | TableFormController | ✅ | 表单控制器 |
| customButtons | ReactNode | - | 替换默认的查询/重置按钮 |
| extra | ReactNode | - | 按钮区域的额外内容 |
| defaultShowMore | boolean | - | 默认展开更多筛选条件 |
静态方法
// 创建查询条件,默认 { pageNum: 1, pageSize: 20 }
const query = RcTableForm.useQuery<Query>(initValues?)
// 创建表单控制器
const controller = RcTableForm.useController()
// 控制器方法
controller.submit() // 触发查询
controller.clear(fields?) // 重置表单(可指定字段)自动展开/收起
当表单内容高度超过一行时,自动出现「展开/收起筛选」按钮。
RcModal 可拖拽弹窗
对 antd Modal 的增强,支持拖拽标题栏移动和全屏切换。
Props
继承 antd
ModalProps(移除modalRender)
| 属性 | 类型 | 必传 | 说明 |
|------|------|:----:|------|
| fullScreenModal | boolean | - | 显示全屏/退出全屏按钮 |
| autoFullScreen | boolean | - | 默认以全屏打开 |
| onFullScreenChange | (fullScreen: boolean) => void | - | 全屏状态变化回调 |
RcModal.useModal
管理弹窗的打开/关闭状态及参数传递:
const modal = RcModal.useModal<{ id: number }>()
modal.open({ id: 1 }) // 打开并传参
modal.close() // 关闭
modal.visable // 是否可见
modal.params // 当前参数 { id: 1 }RcModal.confirm
确认操作弹窗,内置成功提示和表格刷新逻辑:
// 推荐:对象参数形式
RcModal.confirm({
api: deleteUser,
params: { id: record.id },
query, // 可选,成功后刷新查询
tableData, // 可选,用于删除最后一条数据后自动翻页
callback: (res) => {}, // 可选,自定义成功回调
}, {
title: '删除', // 可选,默认 '删除'
content: '确认删除该用户?', // 可选,默认 '确认是否删除该数据?'
})弹窗页面 Props
弹窗内的表单页面建议实现此接口:
interface RcModalProps<P = unknown> {
modal: ModalProps<P> // { visable, params, open, close }
query?: SearchQuery<QueryData>
}布局组件
RcLayoutHeader
页面头部布局,左右 flex 排列。
<RcLayoutHeader actions={<Button>设置</Button>}>
<h1>页面标题</h1>
</RcLayoutHeader>| 属性 | 类型 | 说明 |
|------|------|------|
| children | ReactNode | 左侧内容 |
| actions | ReactNode | 右侧操作区 |
RcLayoutSider
侧栏布局,内置 Menu 和 Scrollbars。
| 属性 | 类型 | 说明 |
|------|------|------|
| menuProps | MenuProps(排除 theme/mode) | 菜单配置 |
| header | (collapsed) => ReactNode | 侧栏顶部 |
| footer | (collapsed) => ReactNode | 侧栏底部 |
| trigger | (collapsed) => ReactNode | 折叠按钮 |
| scrollBarProps | ScrollbarsProps | 滚动条配置 |
RcLayoutTabPage
标签页布局,支持两种模式:
hasSider={true}— 侧栏 + 内容区hasSider={false}— 头部 + 内容区
| 属性 | 类型 | 说明 |
|------|------|------|
| siderProps | RcLayoutSiderProps | 侧栏配置 |
| headerProps | RcLayoutHeaderProps | 头部配置 |
| tabPageProps | TabsProps(扩展 tabBarHorizontalMargin) | 标签页配置 |
| onTabChange | (key) => void | 标签切换 |
| onClose | (key) => void | 关闭标签 |
| onCloseOther | (key) => void | 关闭其他标签 |
| onRefresh | (key) => void | 刷新标签 |
子组件:
RcLayoutTabPage.TabLabel— 可关闭的 tab 标签RcLayoutTabPage.TabContextMenu— tab 右键菜单(关闭/关闭其他/刷新)RcLayoutTabPage.PageContainer— 页面容器(小尺寸 Card + 可选滚动区域)
工具
RcExcel
Excel 导出工具,基于 exceljs(动态导入,不影响首屏加载)。
import { RcExcel, type RcExcelData } from '@stoly/react-component'
// 导出数据到 .xlsx
await RcExcel.export({
header: [
{ header: '姓名', key: 'name' },
{ header: '年龄', key: 'age' },
],
data: [{ name: '张三', age: 28 }],
}, '用户列表')
// 下载已有的 Blob 数据
RcExcel.downloadExcel(blob, '文件名')Hooks
useSimpleReducer
轻量级 state 合并更新,类似 class 组件的 setState。
const [state, dispatch, reset] = useSimpleReducer({ loading: false, count: 0 })
dispatch({ loading: true }) // 合并更新
reset() // 恢复初始值useOnlyAsync
防止异步函数并发执行(上次未完成时忽略新的调用)。
const safeSubmit = useOnlyAsync(async () => {
await submitForm()
})usePage
分页状态管理。
const [pager, setPager] = usePage({ page: 1, size: 20 })
// pager: { page: number, size: number, total: number }
setPager({ total: 100 })useRenderRef
ref + 触发重渲染的更新函数,兼顾同步读取和 React 响应式。
const [ref, setRef] = useRenderRef<string>('初始值')
ref.current // 同步读取最新值
setRef('新值') // 更新值并触发重渲染类型导出
import type {
RcBaseResult, // BaseResult<T>: { success, data? }
RcBaseResultData, // NonNullable<T[K]>
RcListPager, // { page, size, total? }
RcQueryData, // { pageNum, pageSize, sort? }
RcTableProps,
RcTableRef,
RcTableFormProps,
RcModalProps,
RcExcelData,
RcLayoutHeaderProps,
RcLayoutSiderProps,
RcLayoutTabPageProps,
} from '@stoly/react-component'注意事项
- 所有接口返回值必须包含
success: boolean字段,组件通过此字段判断请求是否成功 RcTable的exported功能仅适用于简单表头,复杂嵌套表头请直接使用RcExcel.export()RcModal.confirm传入tableData时会自动处理「删除最后一条数据后翻页到上一页」的逻辑- 主题通过 styled-components 的
ThemeProvider注入,包含 antdGlobalToken和prefixCls RcTable不支持多字段排序,多列排序会提示错误
License
ISC
