# 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).