| /** | ||
| * @desc 分页列表组件, 行为与antd中table基本保持一致,封装的目的在于简化antd中table的属性配置, | ||
| * 提供自动数据刷新的功能以及更好的交互效果 | ||
| */ | ||
| import React, { Component } from 'react'; | ||
| import { Table, Pagination, Button, Input } from 'antd'; | ||
| // 组件需要用到plutus-util/corsPromise 工具来访问网络 | ||
| import CorsPromise from 'plutus-utils'; | ||
| import './Component.scss'; | ||
| export default class UIComponent extends Component { | ||
| constructor(props) { | ||
| super(props); | ||
| // 提取父组件属性值,BBDTable主要是对以下几个参数做操作 | ||
| let { url, params, pageNum, pageSize, domain, localFilter, key } = this.props; | ||
| // 组件的分页属性,分页属性不暴露给外部, 需要区别antd本身的pagination | ||
| let _pagination = { | ||
| total: 0, // 数据总页数 | ||
| count: 0, // 数据总条数 | ||
| curSize: 0, // 当前页条数 | ||
| curNum: 1, // 当前页数 | ||
| goNum: '' // 跳转页数 | ||
| }; | ||
| this.state = { | ||
| url: url || '', | ||
| params: params || {}, | ||
| pageNum: pageNum || 0, | ||
| pageSize: pageSize || 20, | ||
| domain: domain, | ||
| pagination: !(this.props.pagination === false), // antd属性, 默认开启分页 | ||
| _pagination: _pagination, | ||
| localFilter: localFilter || false, // 是否开启本地筛选 | ||
| _key: this.props.key || Math.random() + new Date().toString + (url || '') | ||
| }; | ||
| // 定义ref | ||
| this._ComponentDomRef = React.createRef(); | ||
| } | ||
| componentDidMount() { | ||
| this._updateView(); | ||
| } | ||
| /** | ||
| * 私有方法,更新列表视图 | ||
| */ | ||
| _updateView() { | ||
| if (this.state.localFilter) { | ||
| this._updateViewByLocal(); | ||
| }else { | ||
| this._updateViewByNet(); | ||
| } | ||
| } | ||
| /** | ||
| * 私有方法,从已有数据集合中筛选出新的数据集合, 通过setState更新视图 | ||
| * @param callback:视图更新后的回调 | ||
| */ | ||
| _updateViewByLocal(callback) { | ||
| // 获取数据源并创建副本,避免多次筛选时数据源不一致 | ||
| let _newDataSource = this.state._originDataSource || this.props.dataSource || []; | ||
| // 获取到最新的条件参数 | ||
| let { params, pageSize, pageNum } = this.state; | ||
| // step1:按照额外参数条件筛选 | ||
| _newDataSource = _newDataSource.filter(item => { | ||
| // 遍历params的键 | ||
| let _suitableCollection = []; | ||
| if (Object.keys(params).length > 0) { | ||
| for (let key of params) { | ||
| _suitableCollection.push(item[key] === params[key]); | ||
| } | ||
| return _suitableCollection.every(suitable => suitable === true); | ||
| } | ||
| return true; | ||
| }); | ||
| // step2:按照分页参数筛选当页数据 | ||
| let dataSource = _newDataSource; | ||
| let { _pagination } = this.state; | ||
| if (this.state.pagination) { | ||
| dataSource = _newDataSource.slice((pageNum - 1) * pageSize, pageNum * pageSize); | ||
| // 更新分页参数 | ||
| _pagination.total = _newDataSource.length === 0 ? 0 : Math.ceil(_newDataSource.length / pageSize); | ||
| _pagination.count = _newDataSource.length; | ||
| _pagination.curNum = pageNum + 1; | ||
| _pagination.goNum = ''; | ||
| if (pageNum > _pagination.total) { | ||
| _pagination.curSize = 0; | ||
| } else if(pageNum > _pagination.total) { | ||
| _pagination.curSize = pageNum * pageSize - _pagination.count; | ||
| }else { | ||
| _pagination.curSize = pageSize; | ||
| } | ||
| } | ||
| // 更新视图 | ||
| this.setState({ | ||
| dataSource, | ||
| _pagination | ||
| }, () => callback && callback()); | ||
| this._resetHeight(); | ||
| } | ||
| /** | ||
| * 私有方法,通过网络获取最新条件下的数据, 通过setState更新视图 | ||
| * @param callback: 视图更新后的回调 | ||
| */ | ||
| _updateViewByNet(callback) { | ||
| // 需要依赖plutus-util/corsPromise工具 | ||
| let { url, domain, params, pageSize, pageNum } = this.state; | ||
| let _data = Object.assign({}, params, {pageSize: pageSize, pageNum: pageNum}); | ||
| let self = this; | ||
| new CorsPromise({ | ||
| url: url, | ||
| type: 'get', | ||
| data: _data, | ||
| domain: domain | ||
| }).then(res => { | ||
| // 解析网络数据 | ||
| let { dataSource, _pagination } = this.state; | ||
| let totalElements = 0; | ||
| if (Array.isArray(res.data)) { | ||
| dataSource = res.data; | ||
| totalElements = res.totalElements || 0; | ||
| } else if (res.data && Array.isArray(res.data.content)) { | ||
| dataSource = res.data.content; | ||
| totalElements = res.data.totalElements || 0; | ||
| }else { | ||
| dataSource = []; | ||
| totalElements = 0; | ||
| } | ||
| // 更新分页参数 | ||
| _pagination.total = totalElements === 0 ? 0 : Math.ceil(totalElements / pageSize); | ||
| _pagination.count = totalElements; | ||
| _pagination.curNum = pageNum + 1; | ||
| _pagination.curSize = dataSource.length; | ||
| _pagination.goNum = ''; | ||
| // 更新视图 | ||
| self.setState({ | ||
| dataSource, | ||
| _pagination, | ||
| _originDataSource: dataSource // 设置originDataSource, 以便在本地筛选时做为原始值 | ||
| }, () => callback && callback()); | ||
| this._resetHeight(); | ||
| }); | ||
| } | ||
| /** | ||
| * 根据父组件设定的高度重设table组件高度 | ||
| * */ | ||
| _resetHeight() { | ||
| if (!this._ComponentDomRef) { | ||
| return; | ||
| } | ||
| if (!this._ComponentDomRef.current) { | ||
| return; | ||
| } | ||
| try { | ||
| let current = this._ComponentDomRef.current; | ||
| if (current.childNodes[0] && current.childNodes[0].className.includes('table-table')) { | ||
| let componentHeight = current.clientHeight < 400 ? 400 : current.clientHeight; | ||
| let paginationHeight = current.childNodes[1] && current.childNodes[1].clientHeight || 0; | ||
| let tableStyle = {}; | ||
| tableStyle.minHeight = componentHeight - paginationHeight - 10; | ||
| this.setState({ | ||
| tableStyle: tableStyle, | ||
| scroll: Object.assign({}, {y: tableStyle.minHeight - 70}, this.props.scroll) | ||
| }); | ||
| } | ||
| }catch (e) { | ||
| throw new Error(e); | ||
| } | ||
| } | ||
| /** | ||
| * 公有方法,当外部需要按照条件筛选数据的时候可以调用次方法 | ||
| * @param local: 是否本地筛选 | ||
| * @param outParam: 筛选条件 | ||
| * @param callback: 视图更新后的回调 | ||
| */ | ||
| dataNotifyChange(outParam = {}, callback = new Function()) { | ||
| // 外部触发筛选时,pageNum需要重置 | ||
| let innerParams = this.state.params; | ||
| let params = Object.assign({}, innerParams, outParam); | ||
| let pageNum = 0; | ||
| let self = this; | ||
| this.setState({ | ||
| params, | ||
| pageNum | ||
| }, () => { | ||
| if (self.state.localFilter) { | ||
| self._updateViewByLocal(callback); | ||
| } else { | ||
| self._updateViewByNet(callback); | ||
| } | ||
| }); | ||
| } | ||
| /** | ||
| * 私有方法,当分页组件改变时,通知数据更新 | ||
| */ | ||
| _changePage = (page) => { | ||
| let self = this; | ||
| this.setState({ | ||
| pageNum: page - 1 | ||
| }, () => { | ||
| self._updateView(); | ||
| }); | ||
| }; | ||
| /** | ||
| * 私有方法,手动输入跳转页 | ||
| */ | ||
| _inputPage = (e) => { | ||
| if (e.target.value) { | ||
| let inputValue = e.target.value; | ||
| let { _pagination} = this.state; | ||
| let reg = /^(0|[1-9][0-9]*)(\.[0-9]*)?$/; | ||
| if (reg.test(inputValue)) { | ||
| _pagination.goNum = inputValue; | ||
| this.setState({ | ||
| _pagination | ||
| }); | ||
| } | ||
| } | ||
| }; | ||
| /** | ||
| * 私有方法,当有手动输入分页值后,点击跳转按钮刷新视图 | ||
| */ | ||
| _jumpPage = () => { | ||
| if (this.state._pagination.goNum) { | ||
| let goNum = this.state._pagination.goNum - 1; | ||
| let self = this; | ||
| this.setState({ | ||
| pageNum: goNum | ||
| }, () => { | ||
| self._updateView(); | ||
| }); | ||
| } | ||
| }; | ||
| render() { | ||
| let { _pagination, _key, pageSize, dataSource, tableStyle } = this.state; | ||
| const {style, scroll, rowKey} = this.props; | ||
| return (<div className="plutus-ui-table-root" ref={this._ComponentDomRef} key={_key}> | ||
| <Table className="table-table" style={style} {...this.props} loading={false} pagination={false} | ||
| rowKey={'id'} dataSource={dataSource} scroll={scroll} key={_key + 'table'}/> | ||
| {this.state.pagination && <div className="table-pagination"> | ||
| <Pagination className="pagination-content" total={_pagination.count} current={_pagination.curNum} onChange={this._changePage} | ||
| pageSize={pageSize} showTotal={ (total) => `总计 ${total} 条,当页${_pagination.curSize}条`}/> | ||
| <div className="pagination-jump"> | ||
| <Input className="pagination-jump-input" type="text" value={_pagination.goNum} onChange={this._inputPage}/> | ||
| <Button className="pagination-jump-button" onClick={this._jumpPage}>跳转</Button> | ||
| </div> | ||
| </div>} | ||
| </div>); | ||
| } | ||
| } |
| .plutus-ui-table-root{ | ||
| position: relative; | ||
| width: 100%; | ||
| height: 100%; | ||
| overflow-x: hidden; | ||
| text-align: right; | ||
| .table-pagination{ | ||
| margin-top: 10px; | ||
| .pagination-content{ | ||
| display: inline-block; | ||
| width: auto; | ||
| margin-right: 10px; | ||
| vertical-align: middle; | ||
| } | ||
| .pagination-jump{ | ||
| display: inline-block; | ||
| vertical-align: middle; | ||
| .pagination-jump-input{ | ||
| display: inline-block; | ||
| width: 100px; | ||
| margin-right: 5px; | ||
| } | ||
| .pagination-jump-button{ | ||
| display: inline-block; | ||
| vertical-align: top; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| .ant-table-header{ | ||
| padding-bottom: 0 !important; | ||
| } |
+6
-6
@@ -7,8 +7,8 @@ /** | ||
| import 'antd/dist/antd.css'; | ||
| import BBDTable from './bbd/table/component.jsx'; | ||
| import BBDMenu from './bbd/menu/component.jsx'; | ||
| import BBDButton from './bbd/button/component.jsx'; | ||
| import BBDSearches from './bbd/table/component.jsx'; | ||
| import BBDMessage from './bbd/message/component.jsx'; | ||
| import BBDTabs from './bbd/tabs/component.jsx'; | ||
| import BBDTable from './bbd/table/Component.jsx'; | ||
| import BBDMenu from './bbd/menu/Component.jsx'; | ||
| import BBDButton from './bbd/button/Component.jsx'; | ||
| import BBDSearches from './bbd/table/Component.jsx'; | ||
| import BBDMessage from './bbd/message/Component.jsx'; | ||
| import BBDTabs from './bbd/tabs/Component.jsx'; | ||
@@ -15,0 +15,0 @@ module.exports = { |
+1
-1
@@ -44,3 +44,3 @@ { | ||
| }, | ||
| "version": "0.2.36" | ||
| "version": "0.2.37" | ||
| } |
| /** | ||
| * @desc 分页列表组件, 行为与antd中table基本保持一致,封装的目的在于简化antd中table的属性配置, | ||
| * 提供自动数据刷新的功能以及更好的交互效果 | ||
| */ | ||
| import React, { Component } from 'react'; | ||
| import { Table, Pagination, Button, Input } from 'antd'; | ||
| // 组件需要用到plutus-util/corsPromise 工具来访问网络 | ||
| import CorsPromise from 'plutus-utils'; | ||
| import './component.scss'; | ||
| export default class UIComponent extends Component { | ||
| constructor(props) { | ||
| super(props); | ||
| // 提取父组件属性值,BBDTable主要是对以下几个参数做操作 | ||
| let { url, params, pageNum, pageSize, domain, localFilter, key } = this.props; | ||
| // 组件的分页属性,分页属性不暴露给外部, 需要区别antd本身的pagination | ||
| let _pagination = { | ||
| total: 0, // 数据总页数 | ||
| count: 0, // 数据总条数 | ||
| curSize: 0, // 当前页条数 | ||
| curNum: 1, // 当前页数 | ||
| goNum: '' // 跳转页数 | ||
| }; | ||
| this.state = { | ||
| url: url || '', | ||
| params: params || {}, | ||
| pageNum: pageNum || 0, | ||
| pageSize: pageSize || 20, | ||
| domain: domain, | ||
| pagination: !(this.props.pagination === false), // antd属性, 默认开启分页 | ||
| _pagination: _pagination, | ||
| localFilter: localFilter || false, // 是否开启本地筛选 | ||
| _key: this.props.key || Math.random() + new Date().toString + (url || '') | ||
| }; | ||
| // 定义ref | ||
| this._ComponentDomRef = React.createRef(); | ||
| } | ||
| componentDidMount() { | ||
| this._updateView(); | ||
| } | ||
| /** | ||
| * 私有方法,更新列表视图 | ||
| */ | ||
| _updateView() { | ||
| if (this.state.localFilter) { | ||
| this._updateViewByLocal(); | ||
| }else { | ||
| this._updateViewByNet(); | ||
| } | ||
| } | ||
| /** | ||
| * 私有方法,从已有数据集合中筛选出新的数据集合, 通过setState更新视图 | ||
| * @param callback:视图更新后的回调 | ||
| */ | ||
| _updateViewByLocal(callback) { | ||
| // 获取数据源并创建副本,避免多次筛选时数据源不一致 | ||
| let _newDataSource = this.state._originDataSource || this.props.dataSource || []; | ||
| // 获取到最新的条件参数 | ||
| let { params, pageSize, pageNum } = this.state; | ||
| // step1:按照额外参数条件筛选 | ||
| _newDataSource = _newDataSource.filter(item => { | ||
| // 遍历params的键 | ||
| let _suitableCollection = []; | ||
| if (Object.keys(params).length > 0) { | ||
| for (let key of params) { | ||
| _suitableCollection.push(item[key] === params[key]); | ||
| } | ||
| return _suitableCollection.every(suitable => suitable === true); | ||
| } | ||
| return true; | ||
| }); | ||
| // step2:按照分页参数筛选当页数据 | ||
| let dataSource = _newDataSource; | ||
| let { _pagination } = this.state; | ||
| if (this.state.pagination) { | ||
| dataSource = _newDataSource.slice((pageNum - 1) * pageSize, pageNum * pageSize); | ||
| // 更新分页参数 | ||
| _pagination.total = _newDataSource.length === 0 ? 0 : Math.ceil(_newDataSource.length / pageSize); | ||
| _pagination.count = _newDataSource.length; | ||
| _pagination.curNum = pageNum + 1; | ||
| _pagination.goNum = ''; | ||
| if (pageNum > _pagination.total) { | ||
| _pagination.curSize = 0; | ||
| } else if(pageNum > _pagination.total) { | ||
| _pagination.curSize = pageNum * pageSize - _pagination.count; | ||
| }else { | ||
| _pagination.curSize = pageSize; | ||
| } | ||
| } | ||
| // 更新视图 | ||
| this.setState({ | ||
| dataSource, | ||
| _pagination | ||
| }, () => callback && callback()); | ||
| this._resetHeight(); | ||
| } | ||
| /** | ||
| * 私有方法,通过网络获取最新条件下的数据, 通过setState更新视图 | ||
| * @param callback: 视图更新后的回调 | ||
| */ | ||
| _updateViewByNet(callback) { | ||
| // 需要依赖plutus-util/corsPromise工具 | ||
| let { url, domain, params, pageSize, pageNum } = this.state; | ||
| let _data = Object.assign({}, params, {pageSize: pageSize, pageNum: pageNum}); | ||
| let self = this; | ||
| new CorsPromise({ | ||
| url: url, | ||
| type: 'get', | ||
| data: _data, | ||
| domain: domain | ||
| }).then(res => { | ||
| // 解析网络数据 | ||
| let { dataSource, _pagination } = this.state; | ||
| let totalElements = 0; | ||
| if (Array.isArray(res.data)) { | ||
| dataSource = res.data; | ||
| totalElements = res.totalElements || 0; | ||
| } else if (res.data && Array.isArray(res.data.content)) { | ||
| dataSource = res.data.content; | ||
| totalElements = res.data.totalElements || 0; | ||
| }else { | ||
| dataSource = []; | ||
| totalElements = 0; | ||
| } | ||
| // 更新分页参数 | ||
| _pagination.total = totalElements === 0 ? 0 : Math.ceil(totalElements / pageSize); | ||
| _pagination.count = totalElements; | ||
| _pagination.curNum = pageNum + 1; | ||
| _pagination.curSize = dataSource.length; | ||
| _pagination.goNum = ''; | ||
| // 更新视图 | ||
| self.setState({ | ||
| dataSource, | ||
| _pagination, | ||
| _originDataSource: dataSource // 设置originDataSource, 以便在本地筛选时做为原始值 | ||
| }, () => callback && callback()); | ||
| this._resetHeight(); | ||
| }); | ||
| } | ||
| /** | ||
| * 根据父组件设定的高度重设table组件高度 | ||
| * */ | ||
| _resetHeight() { | ||
| if (!this._ComponentDomRef) { | ||
| return; | ||
| } | ||
| if (!this._ComponentDomRef.current) { | ||
| return; | ||
| } | ||
| try { | ||
| let current = this._ComponentDomRef.current; | ||
| if (current.childNodes[0] && current.childNodes[0].className.includes('table-table')) { | ||
| let componentHeight = current.clientHeight < 400 ? 400 : current.clientHeight; | ||
| let paginationHeight = current.childNodes[1] && current.childNodes[1].clientHeight || 0; | ||
| let tableStyle = {}; | ||
| tableStyle.minHeight = componentHeight - paginationHeight - 10; | ||
| this.setState({ | ||
| tableStyle: tableStyle, | ||
| scroll: Object.assign({}, {y: tableStyle.minHeight - 70}, this.props.scroll) | ||
| }); | ||
| } | ||
| }catch (e) { | ||
| throw new Error(e); | ||
| } | ||
| } | ||
| /** | ||
| * 公有方法,当外部需要按照条件筛选数据的时候可以调用次方法 | ||
| * @param local: 是否本地筛选 | ||
| * @param outParam: 筛选条件 | ||
| * @param callback: 视图更新后的回调 | ||
| */ | ||
| dataNotifyChange(outParam = {}, callback = new Function()) { | ||
| // 外部触发筛选时,pageNum需要重置 | ||
| let innerParams = this.state.params; | ||
| let params = Object.assign({}, innerParams, outParam); | ||
| let pageNum = 0; | ||
| let self = this; | ||
| this.setState({ | ||
| params, | ||
| pageNum | ||
| }, () => { | ||
| if (self.state.localFilter) { | ||
| self._updateViewByLocal(callback); | ||
| } else { | ||
| self._updateViewByNet(callback); | ||
| } | ||
| }); | ||
| } | ||
| /** | ||
| * 私有方法,当分页组件改变时,通知数据更新 | ||
| */ | ||
| _changePage = (page) => { | ||
| let self = this; | ||
| this.setState({ | ||
| pageNum: page - 1 | ||
| }, () => { | ||
| self._updateView(); | ||
| }); | ||
| }; | ||
| /** | ||
| * 私有方法,手动输入跳转页 | ||
| */ | ||
| _inputPage = (e) => { | ||
| if (e.target.value) { | ||
| let inputValue = e.target.value; | ||
| let { _pagination} = this.state; | ||
| let reg = /^(0|[1-9][0-9]*)(\.[0-9]*)?$/; | ||
| if (reg.test(inputValue)) { | ||
| _pagination.goNum = inputValue; | ||
| this.setState({ | ||
| _pagination | ||
| }); | ||
| } | ||
| } | ||
| }; | ||
| /** | ||
| * 私有方法,当有手动输入分页值后,点击跳转按钮刷新视图 | ||
| */ | ||
| _jumpPage = () => { | ||
| if (this.state._pagination.goNum) { | ||
| let goNum = this.state._pagination.goNum - 1; | ||
| let self = this; | ||
| this.setState({ | ||
| pageNum: goNum | ||
| }, () => { | ||
| self._updateView(); | ||
| }); | ||
| } | ||
| }; | ||
| render() { | ||
| let { _pagination, _key, pageSize, dataSource, tableStyle } = this.state; | ||
| const {style, scroll, rowKey} = this.props; | ||
| return (<div className="plutus-ui-table-root" ref={this._ComponentDomRef} key={_key}> | ||
| <Table className="table-table" style={style} {...this.props} loading={false} pagination={false} | ||
| rowKey={'id'} dataSource={dataSource} scroll={scroll} key={_key + 'table'}/> | ||
| {this.state.pagination && <div className="table-pagination"> | ||
| <Pagination className="pagination-content" total={_pagination.count} current={_pagination.curNum} onChange={this._changePage} | ||
| pageSize={pageSize} showTotal={ (total) => `总计 ${total} 条,当页${_pagination.curSize}条`}/> | ||
| <div className="pagination-jump"> | ||
| <Input className="pagination-jump-input" type="text" value={_pagination.goNum} onChange={this._inputPage}/> | ||
| <Button className="pagination-jump-button" onClick={this._jumpPage}>跳转</Button> | ||
| </div> | ||
| </div>} | ||
| </div>); | ||
| } | ||
| } |
| .plutus-ui-table-root{ | ||
| position: relative; | ||
| width: 100%; | ||
| height: 100%; | ||
| overflow-x: hidden; | ||
| text-align: right; | ||
| .table-pagination{ | ||
| margin-top: 10px; | ||
| .pagination-content{ | ||
| display: inline-block; | ||
| width: auto; | ||
| margin-right: 10px; | ||
| vertical-align: middle; | ||
| } | ||
| .pagination-jump{ | ||
| display: inline-block; | ||
| vertical-align: middle; | ||
| .pagination-jump-input{ | ||
| display: inline-block; | ||
| width: 100px; | ||
| margin-right: 5px; | ||
| } | ||
| .pagination-jump-button{ | ||
| display: inline-block; | ||
| vertical-align: top; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| .ant-table-header{ | ||
| padding-bottom: 0 !important; | ||
| } |