v0.6.22
This commit is contained in:
912
README.md
912
README.md
@@ -1,12 +1,904 @@
|
||||
### ff, 集成以下项目的开发环境
|
||||
# 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/button
|
||||
@ff/container
|
||||
@ff/core
|
||||
@ff/data-list
|
||||
@ff/grid-layout
|
||||
@ff/grid-layout-form
|
||||
@ff/iconfont
|
||||
@ff/pages
|
||||
|
||||
#### 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
|
||||
```
|
||||
### 最终打包到 [ff](https://git.fsdpf.net/npm/ff-dist.git).
|
||||
|
||||
#### 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
|
||||
|
||||
2
dist/button.js
vendored
2
dist/button.js
vendored
@@ -1,4 +1,4 @@
|
||||
import { aj as s, ai as u, ak as e } from "./common/main-BEaQ6Xnt.js";
|
||||
import { aj as s, ai as u, ak as e } from "./common/main-C0CYfBDd.js";
|
||||
export {
|
||||
s as auth,
|
||||
u as default,
|
||||
|
||||
1185
dist/common/main-BEaQ6Xnt.js
vendored
1185
dist/common/main-BEaQ6Xnt.js
vendored
File diff suppressed because it is too large
Load Diff
1456
dist/common/main-C0CYfBDd.js
vendored
Normal file
1456
dist/common/main-C0CYfBDd.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2
dist/components.js
vendored
2
dist/components.js
vendored
@@ -1,4 +1,4 @@
|
||||
import { aq as s, ah as p, ar as n, as as r, ap as t } from "./common/main-BEaQ6Xnt.js";
|
||||
import { aq as s, ah as p, ar as n, as as r, ap as t } from "./common/main-C0CYfBDd.js";
|
||||
export {
|
||||
s as Empty,
|
||||
p as Icon,
|
||||
|
||||
2
dist/container.js
vendored
2
dist/container.js
vendored
@@ -1,4 +1,4 @@
|
||||
import { am as s, aq as e, ar as p, as as n, an as t, ap as d, ao as r, al as u } from "./common/main-BEaQ6Xnt.js";
|
||||
import { am as s, aq as e, ar as p, as as n, an as t, ap as d, ao as r, al as u } from "./common/main-C0CYfBDd.js";
|
||||
export {
|
||||
s as Context,
|
||||
e as Empty,
|
||||
|
||||
2
dist/data-converter.js
vendored
2
dist/data-converter.js
vendored
@@ -1,6 +1,6 @@
|
||||
import "lodash";
|
||||
import "react";
|
||||
import { D as p } from "./common/main-BEaQ6Xnt.js";
|
||||
import { D as p } from "./common/main-C0CYfBDd.js";
|
||||
export {
|
||||
p as default
|
||||
};
|
||||
|
||||
2
dist/data-list.js
vendored
2
dist/data-list.js
vendored
@@ -1,4 +1,4 @@
|
||||
import { L as t, J as e, B as r, F as o, M as i, I as l, E as u, K as D, C as n, N as L, A as C, P as m, O as p, W as b, S as c, U as F, T as d, V as O, Q as S } from "./common/main-BEaQ6Xnt.js";
|
||||
import { L as t, J as e, B as r, F as o, M as i, I as l, E as u, K as D, C as n, N as L, A as C, P as m, O as p, W as b, S as c, U as F, T as d, V as O, Q as S } from "./common/main-C0CYfBDd.js";
|
||||
export {
|
||||
t as DataListContent,
|
||||
e as DataListContext,
|
||||
|
||||
2
dist/data-list/utils.js
vendored
2
dist/data-list/utils.js
vendored
@@ -1,5 +1,5 @@
|
||||
import "lodash";
|
||||
import { p as t } from "../common/main-BEaQ6Xnt.js";
|
||||
import { p as t } from "../common/main-C0CYfBDd.js";
|
||||
export {
|
||||
t as getDefaultExpandRowKeys
|
||||
};
|
||||
|
||||
2
dist/grid-layout-form.js
vendored
2
dist/grid-layout-form.js
vendored
@@ -1,4 +1,4 @@
|
||||
import { a7 as s, a9 as r, a8 as u, a6 as o, z as t, ae as m, ac as d, ad as F, ag as i, ab as g, aa as c, af as l } from "./common/main-BEaQ6Xnt.js";
|
||||
import { a7 as s, a9 as r, a8 as u, a6 as o, z as t, ae as m, ac as d, ad as F, ag as i, ab as g, aa as c, af as l } from "./common/main-C0CYfBDd.js";
|
||||
export {
|
||||
s as GridLayoutForm,
|
||||
r as GridLayoutFormHelper,
|
||||
|
||||
2
dist/grid-layout-form/utils.js
vendored
2
dist/grid-layout-form/utils.js
vendored
@@ -1,5 +1,5 @@
|
||||
import "lodash";
|
||||
import { a as o, g } from "../common/main-BEaQ6Xnt.js";
|
||||
import { a as o, g } from "../common/main-C0CYfBDd.js";
|
||||
export {
|
||||
o as getNormalizeWidget,
|
||||
g as getOptionItemByValue
|
||||
|
||||
2
dist/grid-layout.js
vendored
2
dist/grid-layout.js
vendored
@@ -1,4 +1,4 @@
|
||||
import { q as u, v as e, s as r, H as t, G as d, x as i, z as o, y, w as G } from "./common/main-BEaQ6Xnt.js";
|
||||
import { q as u, v as e, s as r, H as t, G as d, x as i, z as o, y, w as G } from "./common/main-C0CYfBDd.js";
|
||||
export {
|
||||
u as GridLayout,
|
||||
e as GridLayoutFramework,
|
||||
|
||||
2
dist/grid-layout/utils.js
vendored
2
dist/grid-layout/utils.js
vendored
@@ -1,4 +1,4 @@
|
||||
import { l as t, o as a, n as l } from "../common/main-BEaQ6Xnt.js";
|
||||
import { l as t, o as a, n as l } from "../common/main-C0CYfBDd.js";
|
||||
export {
|
||||
t as getBoxStyle,
|
||||
a as getNormalizeFields,
|
||||
|
||||
2
dist/hooks.js
vendored
2
dist/hooks.js
vendored
@@ -1,7 +1,7 @@
|
||||
import "lodash";
|
||||
import "rc-field-form";
|
||||
import "react";
|
||||
import { a3 as r, a2 as o, a4 as p, a0 as f, a1 as i, a5 as m, $ as c } from "./common/main-BEaQ6Xnt.js";
|
||||
import { a3 as r, a2 as o, a4 as p, a0 as f, a1 as i, a5 as m, $ as c } from "./common/main-C0CYfBDd.js";
|
||||
import { default as b } from "rc-util/lib/hooks/useMergedState";
|
||||
export {
|
||||
r as useDeepEffect,
|
||||
|
||||
2
dist/iconfont.js
vendored
2
dist/iconfont.js
vendored
@@ -2,7 +2,7 @@ import "react/jsx-runtime";
|
||||
import "react";
|
||||
import "prop-types";
|
||||
import "classnames";
|
||||
import { ah as a } from "./common/main-BEaQ6Xnt.js";
|
||||
import { ah as a } from "./common/main-C0CYfBDd.js";
|
||||
export {
|
||||
a as default
|
||||
};
|
||||
|
||||
2
dist/index.js
vendored
2
dist/index.js
vendored
@@ -1,4 +1,4 @@
|
||||
import { aB as s, aC as e, ax as o, ay as n, at as p, az as r, aw as c, av as u, au as f, aA as l } from "./common/main-BEaQ6Xnt.js";
|
||||
import { aB as s, aC as e, ax as o, ay as n, at as p, az as r, aw as c, av as u, au as f, aA as l } from "./common/main-C0CYfBDd.js";
|
||||
export {
|
||||
s as AppContext,
|
||||
e as AppGlobalParamsContext,
|
||||
|
||||
2
dist/pages.js
vendored
2
dist/pages.js
vendored
@@ -1,4 +1,4 @@
|
||||
import { Y as t, X as e, Z as o, _ as g } from "./common/main-BEaQ6Xnt.js";
|
||||
import { Y as t, X as e, Z as o, _ as g } from "./common/main-C0CYfBDd.js";
|
||||
export {
|
||||
t as CustomPage,
|
||||
e as DataListPage,
|
||||
|
||||
2
dist/res-ws.js
vendored
2
dist/res-ws.js
vendored
@@ -1,5 +1,5 @@
|
||||
import "lodash";
|
||||
import { R as a } from "./common/main-BEaQ6Xnt.js";
|
||||
import { R as a } from "./common/main-C0CYfBDd.js";
|
||||
export {
|
||||
a as default
|
||||
};
|
||||
|
||||
2
dist/utils.js
vendored
2
dist/utils.js
vendored
@@ -1,5 +1,5 @@
|
||||
import "lodash";
|
||||
import { d as s, f as i, e as g, h as m, b as o, k as P, c as p, j as d, i as h, m as k, r as f, t as u, u as l } from "./common/main-BEaQ6Xnt.js";
|
||||
import { d as s, f as i, e as g, h as m, b as o, k as P, c as p, j as d, i as h, m as k, r as f, t as u, u as l } from "./common/main-C0CYfBDd.js";
|
||||
import "./common/vender-FNiQWFaA.js";
|
||||
export {
|
||||
s as deepSome,
|
||||
|
||||
6
dist/virtual-fs.js
vendored
Normal file
6
dist/virtual-fs.js
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
import "pathe";
|
||||
import { aD as o, aE as r } from "./common/main-C0CYfBDd.js";
|
||||
export {
|
||||
o as default,
|
||||
r as toTreePaths
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "ff",
|
||||
"private": true,
|
||||
"version": "0.6.21",
|
||||
"version": "0.6.22",
|
||||
"author": "www.fsdpf.com",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
@@ -25,6 +25,7 @@
|
||||
"classnames": "^2.5.1",
|
||||
"immutability-helper": "^3.1.1",
|
||||
"lodash": "^4.17.21",
|
||||
"pathe": "^2.0.3",
|
||||
"rc-dialog": "^9.5.2",
|
||||
"rc-drawer": "^7.2.0",
|
||||
"rc-field-form": "^1.44.0",
|
||||
@@ -72,4 +73,4 @@
|
||||
"rc-util/lib/hooks/useMergedState"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user