905 lines
21 KiB
Markdown
905 lines
21 KiB
Markdown
# FF 组件库
|
||
|
||
基于 React 的企业级组件库,提供完整的页面开发解决方案。
|
||
|
||
## 目录
|
||
|
||
- [核心模块](#核心模块)
|
||
- [主入口 - `ff`](#主入口---ff)
|
||
- [ff (default)](#ff-default)
|
||
- [http](#http)
|
||
- [cache](#cache)
|
||
- [func](#func)
|
||
- [route](#route)
|
||
- [Hooks - `ff/hooks`](#hooks---ffhooks)
|
||
- [工具函数 - `ff/utils`](#工具函数---ffutils)
|
||
- [数据转换器 - `ff/data-converter`](#数据转换器---ffdata-converter)
|
||
- [WebSocket 订阅 - `ff/res-ws`](#websocket-订阅---ffres-ws)
|
||
- [组件模块](#组件模块)
|
||
- [按钮 - `ff/button`](#按钮---ffbutton)
|
||
- [容器 - `ff/container`](#容器---ffcontainer)
|
||
- [数据列表 - `ff/data-list`](#数据列表---ffdata-list)
|
||
- [网格布局 - `ff/grid-layout`](#网格布局---ffgrid-layout)
|
||
- [网格表单 - `ff/grid-layout-form`](#网格表单---ffgrid-layout-form)
|
||
- [图标 - `ff/iconfont`](#图标---fficonfont)
|
||
- [技术栈](#技术栈)
|
||
- [Peer Dependencies](#peer-dependencies)
|
||
- [完整示例](#完整示例)
|
||
- [许可证](#许可证)
|
||
|
||
## 核心模块
|
||
|
||
### 主入口 - `ff`
|
||
|
||
> **详细文档:** [ff-core/README.md](src/ff-core/README.md)
|
||
|
||
```javascript
|
||
import ff, { http, cache, configure, func, route } from 'ff'
|
||
import { AppContext, AppGlobalParamsContext } from 'ff'
|
||
```
|
||
|
||
#### ff (default)
|
||
|
||
核心应用实例,管理用户认证、环境初始化、组件加载。
|
||
|
||
**主要方法:**
|
||
|
||
```javascript
|
||
// 注册组件供应商
|
||
ff.setVendor(key, vendor) // => ff
|
||
|
||
// 动态加载组件
|
||
ff.getWidgetComponent(widgetPath) // => Promise<Component>
|
||
// 示例: ff.getWidgetComponent('@pkg/components/Button')
|
||
|
||
// 获取路由配置
|
||
ff.getRoutes() // => Promise<Map>
|
||
|
||
// 获取菜单配置
|
||
ff.getMenus() // => Promise<Array>
|
||
|
||
// 获取应用配置
|
||
ff.getConfigure() // => Promise<Object>
|
||
|
||
// 获取权限配置
|
||
ff.getWidgetOperationAuth() // => Promise<Array>
|
||
|
||
// 用户登录
|
||
ff.signin(username, password) // => Promise
|
||
|
||
// 用户登出
|
||
ff.signout() // => Promise
|
||
|
||
// 获取当前用户信息
|
||
ff.getUser() // => Object | null
|
||
|
||
// 初始化应用
|
||
ff.init(params) // => Promise
|
||
```
|
||
|
||
#### http
|
||
|
||
HTTP 请求封装,支持缓存、去重、Base62 编解码。
|
||
|
||
**HttpResponse 类型:**
|
||
|
||
HttpResponse 实现了 Promise A+ 规范,支持链式调用。
|
||
|
||
> 请求失败时,如果没有主动处理错误(即未使用 `try-catch` 包裹,也未调用 `.msg()` 或 `.catch()` 方法),系统会通过 `unhandledrejection` 机制自动弹窗显示错误消息。
|
||
|
||
```typescript
|
||
interface HttpResponse extends Promise<any> {
|
||
code: number // 0 或 1 表示成功,其他表示失败
|
||
message: string // 响应消息
|
||
data: any // 响应数据
|
||
url: string // 请求 URL
|
||
res?: string // 数据资源 UUID (用于 useSubscribeRequest 订阅更新)
|
||
|
||
// Promise A+ 方法
|
||
then(onFulfilled, onRejected): Promise<any>
|
||
catch(onRejected): Promise<any>
|
||
|
||
// 扩展方法
|
||
resp(callback): Promise<any> // 接收完整响应对象
|
||
msg(callback, isResp?): Promise<any> // 弹窗显示消息后执行回调, isResp = true,回调接收完整响应对象
|
||
}
|
||
```
|
||
|
||
**API 方法:**
|
||
|
||
```javascript
|
||
// 基础请求 - 返回 HttpResponse 对象
|
||
http.request(config) // => HttpResponse
|
||
http.get(url, config) // => HttpResponse
|
||
http.post(url, data, config) // => HttpResponse
|
||
http.put(url, data, config) // => HttpResponse
|
||
http.delete(url, config) // => HttpResponse
|
||
|
||
// 列表请求 (自动处理 Base62 编码)
|
||
http.list(listCode, params) // => HttpResponse
|
||
|
||
// Base62 编解码
|
||
http.encode(data) // => string
|
||
http.decode(str) // => Object
|
||
|
||
// 缓存控制
|
||
http.cache(url, params) // => HttpResponse (永久缓存)
|
||
http.refreshCache(isSystem) // 清除缓存
|
||
```
|
||
**使用示例:**
|
||
|
||
```javascript
|
||
// 1. 基础请求 - then() 自动解析为 data
|
||
const users = await http.get('/api/users')
|
||
// users 是 response.data
|
||
|
||
// 2. 获取完整响应对象 - 使用 .resp()
|
||
const response = await http.get('/api/users').resp(resp => {
|
||
console.log('状态码:', resp.code) // 0 或 1
|
||
console.log('消息:', resp.message) // '操作成功'
|
||
console.log('资源UUID:', resp.res) // 用于订阅
|
||
console.log('URL:', resp.url) // '/api/users'
|
||
return resp.data
|
||
})
|
||
|
||
// 3. 成功后弹窗提示 - 使用 .msg()
|
||
await http.post('/api/users', userData).msg(() => {
|
||
console.log('用户创建成功,消息已弹窗显示')
|
||
})
|
||
|
||
// 4. 错误处理
|
||
try {
|
||
const data = await http.get('/api/users')
|
||
} catch (error) {
|
||
console.error('请求失败:', error)
|
||
}
|
||
```
|
||
|
||
#### cache
|
||
|
||
缓存管理器。
|
||
|
||
```javascript
|
||
// 设置缓存
|
||
cache.set(key, value, ttl) // ttl: 过期时间(秒)
|
||
|
||
// 获取缓存
|
||
cache.get(key) // => value | null
|
||
|
||
// 删除缓存
|
||
cache.delete(key)
|
||
|
||
// 清空所有缓存
|
||
cache.clear()
|
||
|
||
// 检查缓存是否存在
|
||
cache.has(key) // => boolean
|
||
```
|
||
|
||
#### func
|
||
|
||
函数执行器,支持 Web Worker 沙箱执行。
|
||
|
||
```javascript
|
||
// 执行 JavaScript 代码字符串
|
||
func.exec(code, params, helpers) // => Promise<result>
|
||
|
||
// 示例
|
||
await func.exec(
|
||
'return value * 2',
|
||
{ value: 10 },
|
||
{ getFieldValue: (name) => form.getFieldValue(name) }
|
||
) // => 20
|
||
```
|
||
|
||
#### route
|
||
|
||
路由管理器。
|
||
|
||
```javascript
|
||
// 路由跳转
|
||
route.push(path, params)
|
||
route.replace(path, params)
|
||
|
||
// 获取当前路由
|
||
route.getCurrentRoute()
|
||
```
|
||
|
||
---
|
||
|
||
### Hooks - `ff/hooks`
|
||
|
||
> **详细文档:** [ff-core/README.md#hooks-模块-hooksjs](src/ff-core/README.md#hooks-模块-hooksjs)
|
||
|
||
React Hooks 工具集。
|
||
|
||
```javascript
|
||
import {
|
||
useMergedState,
|
||
useUpdate,
|
||
usePrevious,
|
||
useStateWithCallback,
|
||
useDeepEqualEffect,
|
||
useOptions,
|
||
useSubscribeRequest
|
||
} from 'ff/hooks'
|
||
```
|
||
|
||
#### useMergedState(defaultValue, options)
|
||
|
||
合并状态管理,结合内部 state 和外部 props。
|
||
|
||
```javascript
|
||
const [value, setValue] = useMergedState(defaultValue, {
|
||
value: props.value,
|
||
onChange: props.onChange
|
||
})
|
||
```
|
||
|
||
#### useUpdate()
|
||
|
||
强制更新组件。
|
||
|
||
```javascript
|
||
const forceUpdate = useUpdate()
|
||
// 调用 forceUpdate() 强制组件重新渲染
|
||
```
|
||
|
||
#### usePrevious(state)
|
||
|
||
获取上一次的状态值。
|
||
|
||
```javascript
|
||
const prevValue = usePrevious(value)
|
||
```
|
||
|
||
#### useStateWithCallback(initialState)
|
||
|
||
带回调的状态管理。
|
||
|
||
```javascript
|
||
const [state, setState] = useStateWithCallback(initialState)
|
||
setState(newState, (currentState) => {
|
||
console.log('状态已更新:', currentState)
|
||
})
|
||
```
|
||
|
||
#### useDeepEqualEffect(callback, deps, compare)
|
||
|
||
深度对比的 useEffect,只在依赖真正变化时执行。
|
||
|
||
```javascript
|
||
useDeepEqualEffect(() => {
|
||
// 只有当 deps 深度对比不相等时才执行
|
||
}, [complexObject])
|
||
```
|
||
|
||
#### useOptions(options, language, type, form, basicForm)
|
||
|
||
选项数据处理,支持静态数组或动态 JS 代码。
|
||
|
||
```javascript
|
||
const options = useOptions(
|
||
fieldOptions, // 选项数据或 JS 代码
|
||
'javascript', // 'json' | 'javascript'
|
||
'string', // 值类型
|
||
form, // 表单实例
|
||
basicForm // 基础表单实例
|
||
)
|
||
```
|
||
|
||
#### useSubscribeRequest(param)
|
||
|
||
WebSocket 订阅请求。
|
||
|
||
```javascript
|
||
const data = useSubscribeRequest({
|
||
uri: '/api/subscribe',
|
||
params: { id: 123 }
|
||
})
|
||
```
|
||
|
||
---
|
||
|
||
### 工具函数 - `ff/utils`
|
||
|
||
> **详细文档:** [ff-core/README.md#工具函数模块-utilsjs](src/ff-core/README.md#工具函数模块-utilsjs)
|
||
|
||
通用工具函数集合。
|
||
|
||
```javascript
|
||
import {
|
||
toPrimitive,
|
||
getPrimitiveType,
|
||
uuid,
|
||
hashJSON,
|
||
replaceKeys,
|
||
deepSome,
|
||
getWidgetPropsData,
|
||
getPkgName,
|
||
getPkgCategory,
|
||
getPkgOwner,
|
||
makeUniqueIdGenerator,
|
||
hasUrlPrefix,
|
||
getUrlWithPrefix
|
||
} from 'ff/utils'
|
||
```
|
||
|
||
#### toPrimitive(data, type)
|
||
|
||
类型转换。
|
||
|
||
```javascript
|
||
toPrimitive('123', 'number') // => 123
|
||
toPrimitive('true', 'boolean') // => true
|
||
toPrimitive('[1,2]', 'array') // => [1, 2]
|
||
toPrimitive('{"a":1}', 'json') // => { a: 1 }
|
||
```
|
||
|
||
#### getPrimitiveType(value)
|
||
|
||
获取原始类型。
|
||
|
||
```javascript
|
||
getPrimitiveType(123) // => 'number'
|
||
getPrimitiveType('text') // => 'string'
|
||
getPrimitiveType([1, 2]) // => 'array'
|
||
```
|
||
|
||
#### uuid()
|
||
|
||
生成唯一标识符。
|
||
|
||
```javascript
|
||
const id = uuid() // => 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
|
||
```
|
||
|
||
#### hashJSON(obj, bits, algo)
|
||
|
||
计算 JSON 对象的哈希值。
|
||
|
||
```javascript
|
||
const hash = hashJSON({ name: 'test' }, 128, 'md5')
|
||
```
|
||
|
||
#### replaceKeys(obj, keyMap)
|
||
|
||
批量替换对象键名。
|
||
|
||
```javascript
|
||
replaceKeys(
|
||
{ oldKey: 'value' },
|
||
{ oldKey: 'newKey' }
|
||
) // => { newKey: 'value' }
|
||
```
|
||
|
||
---
|
||
|
||
### 数据转换器 - `ff/data-converter`
|
||
|
||
> **详细文档:** [ff-core/README.md#数据转换器-data-converterjs](src/ff-core/README.md#数据转换器-data-converterjs)
|
||
|
||
中间件模式的数据转换器。
|
||
|
||
```javascript
|
||
import DataConverter from 'ff/data-converter'
|
||
```
|
||
|
||
**使用方式:**
|
||
|
||
```javascript
|
||
const converter = new DataConverter([
|
||
[middleware1, options1],
|
||
[middleware2, options2]
|
||
])
|
||
|
||
// 转换为值
|
||
const value = await converter.toValue(rawData, context)
|
||
|
||
// 转换为渲染内容
|
||
const rendered = await converter.toRender(rawData, context, defaultValue)
|
||
```
|
||
|
||
---
|
||
|
||
### WebSocket 订阅 - `ff/res-ws`
|
||
|
||
> **详细文档:** [ff-core/README.md](src/ff-core/README.md)
|
||
|
||
WebSocket 资源订阅管理器。
|
||
|
||
```javascript
|
||
import ResWs from 'ff/res-ws'
|
||
|
||
// 创建订阅
|
||
const ws = new ResWs({
|
||
uri: '/api/subscribe',
|
||
params: { id: 123 },
|
||
onMessage: (data) => console.log(data)
|
||
})
|
||
|
||
// 发送消息
|
||
ws.send(data)
|
||
|
||
// 关闭连接
|
||
ws.close()
|
||
```
|
||
|
||
---
|
||
|
||
## 组件模块
|
||
|
||
### 按钮 - `ff/button`
|
||
|
||
> **详细文档:** [ff-button/README.md](src/ff-button/README.md)
|
||
|
||
```javascript
|
||
import Button, { auth, useButton } from 'ff/button'
|
||
```
|
||
|
||
**组件 Props:**
|
||
|
||
| 属性 | 类型 | 默认值 | 说明 |
|
||
|------|------|--------|------|
|
||
| type | `'primary'` \| `'default'` \| `'danger'` | `'default'` | 按钮类型 |
|
||
| size | `'large'` \| `'middle'` \| `'small'` | `'middle'` | 按钮大小 |
|
||
| name | `string` | - | 按钮文本 |
|
||
| icon | `string` | - | 图标名称 |
|
||
| loading | `boolean` | `false` | 加载状态 |
|
||
| disabled | `boolean` | `false` | 禁用状态 |
|
||
| data | `any` | - | 传递给点击事件的数据源 |
|
||
| widget | `string` \| `Component` \| `Function` | - | 组件路径、组件或函数 |
|
||
| widgetType | `'destroy'` \| `'redirect'` \| `'func'` \| `'component'` \| `'grid-layout-form'` \| `'data-list'` | - | 组件类型 |
|
||
| widgetData | `object` | - | 组件默认数据 |
|
||
| widgetProps | `object` | - | 数据结构映射 |
|
||
| widgetSetting | `object` | - | 组件设置 |
|
||
| widgetContainerProps | `WidgetContainerProps` | - | 容器配置 |
|
||
| tooltip | `TooltipConfig` | - | 提示配置 |
|
||
| confirm | `ConfirmConfig` | - | 确认对话框配置 |
|
||
| onBeforeClick | `(data) => void` | - | 点击前回调 |
|
||
| onAfterClick | `(result) => void` | - | 点击后回调 |
|
||
|
||
**TooltipConfig 类型:**
|
||
|
||
| 属性 | 类型 | 默认值 | 说明 |
|
||
|------|------|--------|------|
|
||
| title | `string` | - | 提示内容(必填) |
|
||
| placement | `string` | - | 位置 |
|
||
| enabled | `boolean \| number` | - | 是否启用 |
|
||
| getPopupContainer | `Function` | - | 自定义容器 |
|
||
|
||
**ConfirmConfig 类型:**
|
||
|
||
| 属性 | 类型 | 默认值 | 说明 |
|
||
|------|------|--------|------|
|
||
| title | `string` | - | 确认内容(必填) |
|
||
| okText | `string` | - | 确定按钮文本 |
|
||
| cancelText | `string` | - | 取消按钮文本 |
|
||
| okType | `string` | - | 确定按钮类型 |
|
||
| placement | `string` | - | 位置 |
|
||
| enabled | `boolean \| number` | - | 是否启用 |
|
||
| getPopupContainer | `Function` | - | 自定义容器 |
|
||
| arrow | `boolean \| object` | - | 箭头配置 |
|
||
|
||
**WidgetContainerProps 类型:**
|
||
|
||
| 属性 | 类型 | 默认值 | 说明 |
|
||
|------|------|--------|------|
|
||
| title | `string` | - | 标题 |
|
||
| placement | `string` | - | 位置(top/left/right/bottom 等) |
|
||
| width | `number` | `260` | 宽度 |
|
||
| height | `number` | - | 高度 |
|
||
| zIndex | `number` | - | 层级 |
|
||
| arrow | `boolean` \| `object` | `{ pointAtCenter: true }` | 箭头配置 |
|
||
| align | `object` | - | 对齐配置 |
|
||
| isPopupMountBodyContainer | `boolean` | `true` | 是否挂载到 body |
|
||
| getPopupContainer | `Function` | - | 自定义容器 |
|
||
| classNames | `object` | - | 自定义类名(header/body/footer) |
|
||
| className | `string` | - | 根元素类名 |
|
||
|
||
**组件:**
|
||
|
||
```jsx
|
||
// 默认按钮
|
||
<Button type="primary" name="点击" />
|
||
|
||
// 链接按钮
|
||
<Button.Link name="链接" />
|
||
|
||
// 圆形按钮
|
||
<Button.Circle icon="icon-add" />
|
||
|
||
// 圆角按钮
|
||
<Button.Round name="圆角" />
|
||
|
||
// 虚线按钮
|
||
<Button.Dashed name="虚线" />
|
||
|
||
// 气泡卡片按钮
|
||
<Button.Popover content={<div>内容</div>}>
|
||
气泡按钮
|
||
</Button.Popover>
|
||
```
|
||
|
||
**权限控制:**
|
||
|
||
```javascript
|
||
// 检查权限
|
||
auth.check(uuid) // => boolean
|
||
|
||
// 设置权限
|
||
auth.set(uuids) // uuids: Array<string>
|
||
```
|
||
|
||
**Hook:**
|
||
|
||
```javascript
|
||
const buttonProps = useButton(props)
|
||
```
|
||
|
||
---
|
||
|
||
### 容器 - `ff/container`
|
||
|
||
> **详细文档:** [ff-container/README.md](src/ff-container/README.md)
|
||
|
||
```javascript
|
||
import Container, { PageRender, PopupRender, Popup } from 'ff/container'
|
||
```
|
||
|
||
**FFContainer Props:**
|
||
|
||
| 属性 | 类型 | 默认值 | 说明 |
|
||
|------|------|--------|------|
|
||
| className | `string` | - | 容器类名 |
|
||
| rootClassName | `string` | - | 根容器类名 |
|
||
| style | `object` | `{}` | 容器样式 |
|
||
| title | `ReactNode` | - | 标题内容 |
|
||
| subTitle | `ReactNode` | - | 副标题内容 |
|
||
| actions | `ReactNode` | - | 操作按钮区域 |
|
||
| extras | `ReactNode` | - | 扩展区域 |
|
||
| children | `ReactNode` | - | 主体内容 |
|
||
|
||
**页面容器:**
|
||
|
||
```jsx
|
||
<Container
|
||
title="页面标题"
|
||
subTitle="副标题"
|
||
actions={<Button>操作</Button>}
|
||
extras={<div>扩展区</div>}
|
||
>
|
||
页面内容
|
||
</Container>
|
||
```
|
||
|
||
**Popup API:**
|
||
|
||
```javascript
|
||
// 打开模态框
|
||
Popup.modal(component, props, containerProps) // => Promise
|
||
|
||
// 通知消息
|
||
Popup.notification(content, options) // => Promise
|
||
|
||
// 成功提示
|
||
Popup.success(content, options) // => Promise
|
||
|
||
// 错误提示
|
||
Popup.error(content, options) // => Promise
|
||
|
||
// 确认对话框
|
||
Popup.confirm(content, options) // => Promise<boolean>
|
||
|
||
// 表单弹窗
|
||
Popup.form(fields, containerProps, formProps) // => Promise<object>
|
||
```
|
||
|
||
---
|
||
|
||
### 数据列表 - `ff/data-list`
|
||
|
||
> **详细文档:** [ff-data-list/README.md](src/ff-data-list/README.md)
|
||
|
||
```javascript
|
||
import DataList, {
|
||
DataListHelper,
|
||
DataListFilter,
|
||
DataListToolbar,
|
||
DataListTable,
|
||
DataListFramework
|
||
} from 'ff/data-list'
|
||
|
||
import { useDataListHelper } from 'ff/data-list/utils'
|
||
```
|
||
|
||
**DataList Props:**
|
||
|
||
| 属性 | 类型 | 默认值 | 说明 |
|
||
|------|------|--------|------|
|
||
| listCode | `string` | - | 列表资源代码(必填) |
|
||
| isItemGridLayout | `boolean` | `false` | 是否使用网格布局 |
|
||
| theme | `string` | - | 自定义主题组件路径 |
|
||
| themeProps | `object` | - | 传递给主题组件的属性 |
|
||
| total | `number` | `0` | 数据总条数 |
|
||
| page | `number` | `0` | 当前页码 |
|
||
| pageSize | `number` | `30` | 每页条数 |
|
||
| tab | `string` | - | 当前选中的 Tab |
|
||
| keyword | `string` | - | 搜索关键字 |
|
||
| condition | `object` | - | 筛选条件对象 |
|
||
| sider | `string` | - | 侧边栏选中项 |
|
||
| payload | `object` | `{}` | 额外的请求参数 |
|
||
| layouts | `object \| false` | - | 自定义布局组件配置 |
|
||
| classNames | `object` | `{}` | 各部分的类名配置 |
|
||
| onReload | `function` | - | 重新加载回调 |
|
||
| onClickCallback | `function` | - | 操作按钮点击回调 |
|
||
| onPageChange | `function` | - | 页码变化回调 |
|
||
| onPageSizeChange | `function` | - | 每页条数变化回调 |
|
||
| onTabChange | `function` | - | Tab 变化回调 |
|
||
| onKeywordChange | `function` | - | 关键字变化回调 |
|
||
| onConditionChange | `function` | - | 筛选条件变化回调 |
|
||
| onSiderChange | `function` | - | 侧边栏变化回调 |
|
||
|
||
**基础使用:**
|
||
|
||
```jsx
|
||
<DataList
|
||
listCode="user-list"
|
||
theme="@pkg/themes/TableTheme"
|
||
/>
|
||
```
|
||
|
||
**使用 Hook:**
|
||
|
||
```javascript
|
||
const helper = useDataListHelper('user-list', {
|
||
page: 1,
|
||
pageSize: 20,
|
||
condition: {}
|
||
})
|
||
|
||
// helper 包含:
|
||
// - dataSource: 数据源
|
||
// - total: 总数
|
||
// - page, pageSize: 分页信息
|
||
// - onPageChange: 分页回调
|
||
// - onConditionChange: 筛选回调
|
||
// - onReload: 刷新方法
|
||
```
|
||
|
||
---
|
||
|
||
### 网格布局 - `ff/grid-layout`
|
||
|
||
> **详细文档:** [ff-grid-layout/README.md](src/ff-grid-layout/README.md)
|
||
|
||
```javascript
|
||
import GridLayout, { GridLayoutWidget, GridLayoutFramework } from 'ff/grid-layout'
|
||
import { useStructure, useField, useFnRun } from 'ff/grid-layout/utils'
|
||
```
|
||
|
||
**GridLayout Props:**
|
||
|
||
| 属性 | 类型 | 默认值 | 说明 |
|
||
|------|------|--------|------|
|
||
| name | `string` | - | 表单名称 |
|
||
| form | `FormInstance` | `null` | rc-field-form 实例 |
|
||
| basicForm | `FormInstance` | `null` | 基础表单实例 |
|
||
| style | `object` | `{}` | 容器样式 |
|
||
| className | `string` | - | 容器类名 |
|
||
| cols | `number` | `12` | 网格列数 |
|
||
| rowHeight | `number` | `21` | 行高(px) |
|
||
| containerPadding | `[number, number]` | `[0, 0]` | 容器内边距 [y, x] |
|
||
| itemMargin | `[number, number]` | `[4, 0]` | 元素间距 [y, x] |
|
||
| formProps | `object` | `{}` | 表单额外属性 |
|
||
| formFields | `array` | `[]` | 表单字段配置 |
|
||
| fields | `array` | `[]` | 布局字段配置 |
|
||
| data | `object` | - | 表单数据 |
|
||
| theme | `string` | - | 主题框架路径 |
|
||
| themeProps | `object` | `{}` | 主题框架属性 |
|
||
| groups | `array` | `[{key:'default',label:'默认'}]` | 分组配置 |
|
||
|
||
**基础使用:**
|
||
|
||
```jsx
|
||
<GridLayout
|
||
cols={12}
|
||
rowHeight={21}
|
||
fields={fields}
|
||
data={data}
|
||
/>
|
||
```
|
||
|
||
**使用 Hook:**
|
||
|
||
```javascript
|
||
// 获取远程配置
|
||
const structure = useStructure('layout-code')
|
||
|
||
// 字段值处理
|
||
const [displayValue, rawValue] = useField(name, fieldConfig)
|
||
|
||
// 执行动态函数
|
||
const [result, error] = useFnRun(jsCode, initialValue, params, helpers)
|
||
```
|
||
|
||
---
|
||
|
||
### 网格表单 - `ff/grid-layout-form`
|
||
|
||
> **详细文档:** [ff-grid-layout-form/README.md](src/ff-grid-layout-form/README.md)
|
||
|
||
```javascript
|
||
import GridLayoutForm, { GridLayoutFormHelper } from 'ff/grid-layout-form'
|
||
import {
|
||
useFormAction,
|
||
useFormData,
|
||
useFormSubmit,
|
||
useRules
|
||
} from 'ff/grid-layout-form/utils'
|
||
```
|
||
|
||
**GridLayoutForm Props:**
|
||
|
||
| 属性 | 类型 | 默认值 | 说明 |
|
||
|------|------|--------|------|
|
||
| name | `string` | - | 表单名称 |
|
||
| form | `FormInstance` | `null` | rc-field-form 实例 |
|
||
| basicForm | `FormInstance` | `null` | 基础表单实例 |
|
||
| style | `object` | `{}` | 自定义样式 |
|
||
| className | `string` | - | 自定义类名 |
|
||
| cols | `number` | `24` | 网格列数 |
|
||
| rowHeight | `number` | `16` | 行高(px) |
|
||
| itemMargin | `[number, number]` | `[8, 16]` | 字段间距 [x, y] |
|
||
| containerPadding | `[number, number]` | `[0, 0]` | 容器内边距 [y, x] |
|
||
| fields | `array` | `[]` | 字段配置数组 |
|
||
| hides | `array` | `[]` | 隐藏字段数组 |
|
||
| primaryKey | `number \| string` | `0` | 主键值(编辑模式) |
|
||
| formProps | `object` | `{}` | 表单额外属性 |
|
||
| formFields | `array` | `[]` | 表单额外字段 |
|
||
| listenChangeFields | `array` | - | 监听变化的字段名数组 |
|
||
| listenChangeFieldsFunc | `string` | - | 字段变化回调函数 |
|
||
| onValuesChange | `function` | - | 表单值变化回调 |
|
||
| theme | `string` | - | 主题框架组件路径 |
|
||
| themeProps | `object` | `{}` | 主题框架属性 |
|
||
| groups | `array` | `[{key:'default',label:'默认'}]` | 分组配置 |
|
||
|
||
**基础使用:**
|
||
|
||
```jsx
|
||
const [form] = Form.useForm()
|
||
|
||
<GridLayoutForm
|
||
form={form}
|
||
formCode="user-form"
|
||
primaryKey={userId}
|
||
/>
|
||
```
|
||
|
||
**使用 Hook:**
|
||
|
||
```javascript
|
||
// 表单操作 (获取数据 + 提交)
|
||
const submit = useFormAction(form, 'user-form', userId)
|
||
await submit({
|
||
serialize: (values) => values,
|
||
onSuccess: () => console.log('成功'),
|
||
onFail: (err) => console.error(err)
|
||
})
|
||
|
||
// 仅获取数据
|
||
const formData = useFormData('user-form', userId)
|
||
|
||
// 仅提交
|
||
const submit = useFormSubmit('user-form', userId)
|
||
await submit(form, options)
|
||
|
||
// 校验规则
|
||
const rules = useRules({
|
||
required: true,
|
||
type: 'string',
|
||
max: 100,
|
||
message: '必填且不超过100字符'
|
||
})
|
||
```
|
||
|
||
---
|
||
|
||
### 图标 - `ff/iconfont`
|
||
|
||
> **详细文档:** [ff-iconfont/README.md](src/ff-iconfont/README.md)
|
||
|
||
```javascript
|
||
import Iconfont from 'ff/iconfont'
|
||
```
|
||
|
||
**Iconfont Props:**
|
||
|
||
| 属性 | 类型 | 默认值 | 说明 |
|
||
|------|------|--------|------|
|
||
| type | `string` | - | 图标类型(iconfont 图标名称,必填) |
|
||
| className | `string` | - | 自定义类名 |
|
||
| style | `object` | `{}` | 自定义样式 |
|
||
|
||
**初始化:**
|
||
|
||
```javascript
|
||
// 应用启动时初始化
|
||
Iconfont.init([
|
||
'//at.alicdn.com/t/font_xxx.js',
|
||
'//at.alicdn.com/t/font_yyy.js'
|
||
])
|
||
```
|
||
|
||
**使用:**
|
||
|
||
```jsx
|
||
<Iconfont
|
||
type="icon-home"
|
||
style={{ fontSize: '24px', color: '#1890ff' }}
|
||
/>
|
||
```
|
||
|
||
---
|
||
|
||
## 技术栈
|
||
|
||
- **框架:** React 18.2+
|
||
- **构建:** Vite 5.2+
|
||
- **表单:** rc-field-form 1.44+
|
||
- **UI:** Ant Design 5.17+
|
||
- **样式:** Less
|
||
|
||
## Peer Dependencies
|
||
|
||
```json
|
||
{
|
||
"react": "^18.2.0",
|
||
"react-dom": "^18.2.0",
|
||
"antd": "^5.17.0",
|
||
"rc-field-form": "^1.44.0",
|
||
"lodash": "^4.17.21",
|
||
"classnames": "^2.5.1"
|
||
}
|
||
```
|
||
|
||
## 完整示例
|
||
|
||
```jsx
|
||
import React from 'react'
|
||
import ff, { http } from 'ff'
|
||
import { useDataListHelper } from 'ff/data-list/utils'
|
||
import Button from 'ff/button'
|
||
import Container from 'ff/container'
|
||
import DataList from 'ff/data-list'
|
||
import Iconfont from 'ff/iconfont'
|
||
|
||
// 初始化
|
||
Iconfont.init(['//at.alicdn.com/t/font_xxx.js'])
|
||
|
||
function App() {
|
||
const helper = useDataListHelper('users', { page: 1 })
|
||
|
||
const handleAdd = async () => {
|
||
await http.post('/api/users', { name: 'New User' })
|
||
helper.onReload()
|
||
}
|
||
|
||
return (
|
||
<Container
|
||
title="用户管理"
|
||
actions={<Button onClick={handleAdd}>添加</Button>}
|
||
>
|
||
<DataList
|
||
listCode="users"
|
||
{...helper}
|
||
/>
|
||
</Container>
|
||
)
|
||
}
|
||
```
|
||
|
||
## 许可证
|
||
|
||
作者: what-00@qq.com
|