@gdjiami/rc-components

mygzb.com React Components

Downloads in past

Stats

StarsIssuesVersionUpdatedCreatedSize
@gdjiami/rc-components
0.4.283 months ago4 years agoMinified + gzip package size for @gdjiami/rc-components in KB

Readme

React Components
React 组件库, 收集了工作宝中后台应用的常用组件或套件. 致力于减少应用开发的代码重复,提高维护效率 DEMO ---

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 插件, 例如: ```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 插件
使用示例 ```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 (
<Login
title="登录页面"
onSubmit={this.handleSubmit}
onSuccess={this.handleSuccess}
/>
)
} 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 siteName="后台管理系统"
title={<Title.Display breadcrumb inline />}
menus={[]}
after={
<Dropdown
overlay={
<Menu>
<Menu.Item key="resetPassword">修改密码</Menu.Item>
<Menu.Item key="logout">安全退出</Menu.Item>
</Menu>
}
>
<AdminLayout.Action>用户名</AdminLayout.Action>
</Dropdown>
}
>
<AdminLayout.View>
{props.children}
<AdminLayout.Footer>Version</AdminLayout.Footer>
</AdminLayout.View>
``` AdminLayout.Body 一般用于业务子页面,里面直接添加页面内容 ```html
<title>应用管理</title>
<FatTable
enableSelect
enablePersist="{false}"
columns="{column}"
header="{renderHeader}"
headerExtra="{renderHeaderExtra}"
onRemove="{handleRemove}"
onFetch="{handleFetch}"
onAction="{handleAction}"
/>
```
  • 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字段
<span>
自定义的展示内容{r.logo}
</span>
)
},
{
title: '示例内容2',
dataIndex: 'downloadUrl',
},
{
title: '操作',
width: 180,
render: (r, _, t) => {
// t.triggerAction('toggleOpen', r) 来触发handleAction 可传入 action类型和数据
// t.remove([r.id]) 来执行删除项的请求等方法
return (
<FatTable.Actions className="Container__TagGroup">
<FatTable.Action onClick={() => t.remove([r.id])}>
删除
</FatTable.Action>
<FatTable.Action onClick={() => t.triggerAction('actionType', r)}>
启用
</FatTable.Action>
</FatTable.Actions>
)
}
}
const handleAction = (async (name, data, t) => {
switch (name) {
case 'actionType':
// do something
break
}
} return (
<FatTable
enableSelect
enablePersist={false}
columns={column}
header={renderHeader}
headerExtra={renderHeaderExtra}
onRemove={handleRemove}
onFetch={handleFetch}
onAction={handleAction}
/>
) } ```
  • 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<UserDesc & { userId: string }>
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.