# rc-components
**Repository Path**: jmfe/rc-components
## Basic Information
- **Project Name**: rc-components
- **Description**: 工作宝中后台组件库
- **Primary Language**: Unknown
- **License**: MIT
- **Default Branch**: dev
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 2
- **Forks**: 1
- **Created**: 2020-07-09
- **Last Updated**: 2024-08-03
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# React Components
React 组件库, 收集了工作宝中后台应用的常用组件或套件. 致力于减少应用开发的代码重复,提高维护效率
[DEMO](http://demo.ejiahe.com/api/rc-components/#/)
---
## Installation
```shell
yarn add @gdjiami/rc-components
# 依赖
yarn add react react-dom tslib react-router react-router-dom
```
---
## Usage
所有组件都在`es`目录下, es 使用 ES6 模块系统,另外每目录下面都有 Typescript 声明文件,所以支持类型检查,开发者可以按需导入需要的组件
`rc-components` 支持类似于`antd`的按需加载方式,如果你使用 typescript 可以使用[`ts-import-plugin`](https://github.com/Brooooooklyn/ts-import-plugin) 插件, 例如:
```js
// webpack.config.js
const tsImportPluginFactory = require('ts-import-plugin')
module.exports = {
// ...
module: {
rules: [
{
test: /\.(jsx|tsx|js|ts)$/,
loader: 'ts-loader',
options: {
transpileOnly: true,
getCustomTransformers: () => ({
before: [
tsImportPluginFactory([
// 按需导入antd组件
{
libraryName: 'antd',
libraryDirectory: 'es',
style: 'css',
},
// 按需导入rc-components组件
{
libraryName: '@gdjiami/rc-components',
libraryDirectory: 'es',
style: 'css',
},
]),
],
}),
},
exclude: /node_modules/,
},
],
},
// ...
}
```
> 对于`babel`可以使用[`babel-plugin-import`](https://github.com/ant-design/babel-plugin-import) 插件
使用示例
```typescript
import React from 'react'
import { Login } from '@gdjiami/rc-components'
import { message } from 'antd'
import { delay } from './utils'
export default class LoginPage extends React.Component {
public render() {
return (
)
}
private handleSubmit = async () => {
await delay(2000)
}
private handleSuccess = () => {
message.success('登录成功')
}
}
```
---
## 定位
rc-components 是基于 antd 组件库之上的高层组件库,旨在抽象重复的业务场景, 减少代码重复。其中耦合的东西有:
- antd
- react, react-dom
- tslib
- react-router v4
- lodash
这些耦合的技术是 rc-components 的构建基础,而且在团队内的应用是比较稳定的、静态的,近期不会有大的变动。相对的,有些东西是我们
要避免耦合的:
- 状态管理库,如 mobx,redux.
- Ajax 请求库
- 前端路由类型
---
## Components
这里列举各组件的使用方法和注意事项
- ### Title
用于修改浏览器 title
```typescript
import { Title } from '@gdjiami/rc-components'
import React, { FC } from 'react'
export const Page: FC = (props) => {
return
系统管理
}
```
- ### AdminLayout
后台应用布局组件
AdminLayout 为顶层父组件,其子组件分别有
1. AdminLayout.Action 位于顶部的右边展示? (当前用户)
2. AdminLayout.View 次顶层视图层,全局最外层用一次
3. AdminLayout.HeaderBar
4. AdminLayout.Footer 底部
5. AdminLayout.Body 内容层,当业务页面用这个组件,其内容会按 AdminLayout 布局正确展示
AdminLayout 常用参数(包括但不限于):
| 参数 | 格式 | 用途|
| ---- | ---- | ---- |
| siteName | string | 应用名称
| logo | string | 应用图标
| menus | () => Promise) \| MenuConfig[] | 菜单列表
| after | React.ReactNode | 头部右侧内容
```html
// layout.tsx
}
menus={[]}
after={
修改密码
安全退出
}
>
用户名
}
>
{props.children}
Version
```
AdminLayout.Body 一般用于业务子页面,里面直接添加页面内容
```html
应用管理
```
- ### FatTable
后台应用表格组件,高频组件之一,集成了翻页,搜索,多选,上移下移等基础功能。
FatTable 子组件有
1. FatTable.Actions 表格项功能按钮组,下为其子组件
2. FatTable.Action 表格项功能按钮
FatTable 常用参数(仅列举了常用,更多请查看源码):
| 参数 | 格式 | 用途|
| ---- | ---- | ---- |
| enableSelect | boolean | 是否开启可选
| enablePagination | boolean | 是否开启翻页
| onFetch | FetchHandler | 获取表格数据的方法(翻页搜索均调用此方法)
| header | HeaderRenderer | 表格头部内容 (一般为搜索功能)
| headerExtra | HeaderExtraRenderer | 表格头部额外内容 (一般表格功能按钮,导出、导出、删除、添加等)
| columns | ColumnsType | 列表数据展示
| idKey | string | 列表项的 key (如没有唯一的值可手动构造)
| className | string | 定义类名
| onShift | ShiftHandler | 顺序发生改变所调用的回调
| onRemove | RemoveHandler | 列表项删除所调用的回调
| onAction | ActionHandler | 操作表格的统一方法
```html
// 直接用就好啦
```
onAction 使用方法 和表格交互的重要途径
```jsx
// 示例内容
import { FatTable } from '@gdjiami/rc-components'
import { ColumnsType} from '@gdjiami/rc-components/es/fat-table'
const AppStore: FC = () => {
const { getDownloadUrl } = useRootModel()
const column: ColumnsType = [
{
title: '示例内容', // 列的标题
width: 80,
render: r => ( // 自定义展示内容 没有则展示dataIndex字段
自定义的展示内容{r.logo}
)
},
{
title: '示例内容2',
dataIndex: 'downloadUrl',
},
{
title: '操作',
width: 180,
render: (r, _, t) => {
// t.triggerAction('toggleOpen', r) 来触发handleAction 可传入 action类型和数据
// t.remove([r.id]) 来执行删除项的请求等方法
return (
t.remove([r.id])}>
删除
t.triggerAction('actionType', r)}>
启用
)
}
}
]
const handleAction = (async (name, data, t) => {
switch (name) {
case 'actionType':
// do something
break
}
}
return (
)
}
```
- ### UserSelect
员工选择的组件
首先在路由定义处使用 UserSelectProvider,为有需要使用的路由提供组件服务。
```jsx
import { UserSelectProvider } from '@gdjiami/rc-components/es/user-select'
;
```
随后需定义 UserSelectAdaptor.tsx(一般和 Route.tsx 同层)
```tsx
import {
UserSelectAdaptor,
DepartmentDesc,
UserDesc,
TenementDesc,
} from '@gdjiami/rc-components/es/user-select'
import { DepartmentSearchResult } from '@gdjiami/rc-components/es/user-select/Provider'
import rpc from '~/rpc'
interface DepartmentTreeItem {
children?: DepartmentTreeItem[]
departmentId: string
departmentName: string
tenementId: string
fullPath: string
parentIds: string[]
}
const Adaptor: UserSelectAdaptor = {
/**
* 获取部门树
*/
async getDepartmentTree(tenementId: string): Promise {
const res = await rpc.request<{ items: DepartmentTreeItem[] }>(
'org.department.getTree',
{
tenementId,
fetchFullPath: true,
},
)
const items = res.items.map(
({ departmentId: id, departmentName: name, ...others }) =>
({ id, name, ...others } as DepartmentDesc),
)
return items[0]
},
async getDepartmentChildren(tenementId: string, departmentId: string) {
const res = await rpc.request<{ items: DepartmentTreeItem[] }>(
'org.department.getTree',
{
tenementId,
parentId: departmentId,
fetchFullPath: true,
},
)
const items = res.items.map(
({ departmentId: id, departmentName: name, ...others }) =>
({ id, name, ...others } as DepartmentDesc),
)
return items
},
/**
* 获取部门成员
*/
async getDepartmentUsers(
tenementId: string,
departmentId: string,
page: number,
pageSize: number,
): Promise<{ items: UserDesc[]; total: number }> {
return { items: [], total: 0 }
},
/**
* 用户搜索
* tenementId不为空时,表示企业内搜索
*/
async searchUser(
query: string,
page: number,
pageSize: number,
tenementId?: string,
): Promise<{ items: UserDesc[]; total: number }> {
const params = {
key: query,
startIndex: (page - 1) * pageSize,
resultRows: pageSize,
tenementId,
}
const res = await rpc.request<{
items: Array
totalItems: number
}>('user.search', params)
return {
items: res.items.map((i) => ({ ...i, id: i.userId })),
total: res.totalItems,
}
},
/**
* 企业搜索
*/
async searchTenement(
query: string,
page: number,
pageSize: number,
): Promise<{ items: TenementDesc[]; total: number }> {
const params = {
searchKey: query,
startIndex: (page - 1) * pageSize,
resultRows: pageSize,
}
const res = await rpc.request<{
items: Array<{ tenementId: string; tenementName: string }>
totalItems: number
}>('tenement.lists', params)
return {
items: res.items.map((item) => {
const { tenementId, tenementName } = item
return { id: tenementId, name: tenementName, extra: item }
}),
total: res.totalItems,
}
},
async searchDepartment(
query: string,
page: number,
pageSize: number,
tenementId?: string,
) {
const res = await rpc.request<{
items: Array<{
userCount: string
parentId: string
parentIds: string[]
leaf: boolean
departmentId: string
departmentName: string
}>
totalItems: number
}>('org.department.search', {
tenementId,
key: query,
startIndex: (page - 1) * pageSize,
resultRows: pageSize,
fetchFullPath: true,
})
return {
items: res.items.map(
(i) =>
({
...i,
id: i.departmentId,
name: i.departmentName,
} as DepartmentSearchResult),
),
total: res.totalItems,
}
},
async normalizeDepartmentChecked(
currentSelected: DepartmentDesc[],
added: DepartmentDesc[],
removed: DepartmentDesc[],
): Promise {
const map = (i: DepartmentDesc) => ({
tenementId: i.tenement!.id,
departmentId: i.id,
})
const params = {
currentItems: currentSelected.map(map),
addItems: added.map(map),
delItems: removed.map(map),
}
const res = await rpc.request<{
currentItems: Array<{
userCount: string
parentId: string
parentIds: string[]
leaf: boolean
departmentId: string
departmentName: string
}>
}>('org.department.selectedChange', params)
return res.currentItems.map(
(i) =>
({
...i,
id: i.departmentId,
name: i.departmentName,
} as DepartmentSearchResult),
)
},
async getDepartmentDetail(
ids: string[],
tenementId?: string,
): Promise {
const params = {
items: ids.map((i) => ({ tenementId, departmentId: i })),
}
const res = await rpc.request<{
items: Array<{
userCount: string
parentId: string
parentIds: string[]
leaf: boolean
departmentId: string
departmentName: string
}>
}>('org.department.getDepartmentInfo', params)
return res.items.map(
(i) =>
({
...i,
id: i.departmentId,
name: i.departmentName,
} as DepartmentSearchResult),
)
},
}
export default Adaptor
```
## Demo
run: yarn parcel -- ./components/AdminLayout/example/index.html
## License
This project is licensed under the terms of the
[MIT license](LICENSE).