index.jsx 12.5 KB
Newer Older
A
afc163 已提交
1
import React from 'react';
A
afc163 已提交
2
import jQuery from 'jquery';
A
afc163 已提交
3
import Table from 'rc-table';
A
afc163 已提交
4
import Dropdown from '../dropdown';
A
afc163 已提交
5
import Checkbox from '../checkbox';
A
afc163 已提交
6
import FilterMenu from './filterMenu';
7
import Pagination from '../pagination';
A
afc163 已提交
8
import objectAssign from 'object-assign';
Y
yiminghe 已提交
9
import equals from 'is-equal-shallow';
A
afc163 已提交
10

Y
yiminghe 已提交
11 12
function noop() {
}
13

Y
yiminghe 已提交
14 15 16
function defaultResolve(data) {
  return data || [];
}
17

Y
yiminghe 已提交
18 19
export default React.createClass({
  getInitialState() {
A
afc163 已提交
20
    return {
Y
yiminghe 已提交
21
      // 减少状态
A
afc163 已提交
22
      selectedRowKeys: [],
Y
yiminghe 已提交
23 24 25 26 27 28 29 30 31 32
      // only for remote
      data: [],
      filters: {},
      loading: !this.isLocalDataSource(),
      sortColumn: '',
      sortOrder: '',
      sorter: null,
      pagination: this.hasPagination() ? objectAssign({
        pageSize: 10
      }, this.props.pagination) : {}
A
afc163 已提交
33 34
    };
  },
Y
yiminghe 已提交
35

A
afc163 已提交
36 37
  getDefaultProps() {
    return {
A
afc163 已提交
38
      prefixCls: 'ant-table',
A
afc163 已提交
39
      useFixedHeader: false,
A
afc163 已提交
40 41
      rowSelection: null,
      size: 'normal'
A
afc163 已提交
42 43
    };
  },
Y
yiminghe 已提交
44 45 46

  componentWillReceiveProps(nextProps){
    if (('pagination' in nextProps) && nextProps.pagination !== false) {
A
afc163 已提交
47
      this.setState({
Y
yiminghe 已提交
48
        pagination: objectAssign({}, this.state.pagination, nextProps.pagination)
A
afc163 已提交
49 50
      });
    }
Y
yiminghe 已提交
51 52 53 54 55 56 57 58 59
    if (!this.isLocalDataSource()) {
      if (!equals(nextProps, this.props)) {
        this.setState({
          selectedRowKeys: [],
          loading: true
        }, this.fetch);
      }
    }
    if (nextProps.columns !== this.props.columns) {
A
afc163 已提交
60
      this.setState({
Y
yiminghe 已提交
61
        filters: {}
A
afc163 已提交
62 63 64
      });
    }
  },
Y
yiminghe 已提交
65 66 67
  hasPagination(pagination){
    if (pagination === undefined) {
      pagination = this.props.pagination;
A
afc163 已提交
68
    }
Y
yiminghe 已提交
69 70 71 72
    return pagination !== false;
  },
  isLocalDataSource(){
    return Array.isArray(this.props.dataSource);
A
afc163 已提交
73
  },
Y
yiminghe 已提交
74
  getRemoteDataSource(){
A
afc163 已提交
75
    return objectAssign({
Y
yiminghe 已提交
76 77 78 79
      resolve: defaultResolve,
      getParams: noop,
      getPagination: noop
    }, this.props.dataSource);
A
afc163 已提交
80
  },
A
afc163 已提交
81
  toggleSortOrder(order, column) {
82 83
    let sortColumn = this.state.sortColumn;
    let sortOrder = this.state.sortOrder;
J
jljsj 已提交
84
    let sorter;
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
    // 同时允许一列进行排序,否则会导致排序顺序的逻辑问题
    if (sortColumn) {
      sortColumn.className = '';
    }
    if (sortColumn !== column) {  // 当前列未排序
      sortOrder = order;
      sortColumn = column;
      sortColumn.className = 'ant-table-column-sort';
    } else {                      // 当前列已排序
      if (sortOrder === order) {  // 切换为未排序状态
        sortOrder = '';
        sortColumn = null;
      } else {                    // 切换为排序状态
        sortOrder = order;
        sortColumn.className = 'ant-table-column-sort';
      }
A
afc163 已提交
101
    }
Y
yiminghe 已提交
102 103
    if (this.isLocalDataSource()) {
      sorter = function () {
104
        let result = column.sorter.apply(this, arguments);
105
        if (sortOrder === 'ascend') {
106
          return result;
107
        } else if (sortOrder === 'descend') {
108 109 110
          return -result;
        }
      };
A
afc163 已提交
111
    }
Y
yiminghe 已提交
112
    this.fetch({
A
afc163 已提交
113
      sortOrder: sortOrder,
J
jljsj 已提交
114 115
      sortColumn: sortColumn,
      sorter: sorter
Y
yiminghe 已提交
116
    });
A
afc163 已提交
117
  },
Y
yiminghe 已提交
118 119 120 121 122 123 124 125
  handleFilter(column, filters) {
    filters = objectAssign({}, this.state.filters, {
      [this.getColumnKey(column)]: filters
    });
    this.fetch({
      selectedRowKeys: [],
      filters: filters
    });
A
afc163 已提交
126
  },
Y
yiminghe 已提交
127
  handleSelect(record, rowIndex, e) {
A
afc163 已提交
128
    let checked = e.target.checked;
Y
yiminghe 已提交
129 130
    let selectedRowKeys = this.state.selectedRowKeys.concat();
    let key = this.getRecordKey(record, rowIndex);
131
    if (checked) {
Y
yiminghe 已提交
132
      selectedRowKeys.push(this.getRecordKey(record, rowIndex));
133
    } else {
Y
yiminghe 已提交
134 135
      selectedRowKeys = selectedRowKeys.filter((i) => {
        return key !== i;
136 137 138
      });
    }
    this.setState({
Y
yiminghe 已提交
139
      selectedRowKeys: selectedRowKeys
140 141
    });
    if (this.props.rowSelection.onSelect) {
Y
yiminghe 已提交
142 143 144
      let data = this.getCurrentPageData();
      let selectedRows = data.filter((row, i) => {
        return selectedRowKeys.indexOf(this.getRecordKey(row, i)) >= 0;
A
afc163 已提交
145
      });
Y
yiminghe 已提交
146
      this.props.rowSelection.onSelect(record, checked, selectedRows);
147 148
    }
  },
A
afc163 已提交
149 150
  handleSelectAllRow(e) {
    let checked = e.target.checked;
Y
yiminghe 已提交
151 152 153 154
    let data = this.getCurrentPageData();
    let selectedRowKeys = checked ? data.map((item, i) => {
      return this.getRecordKey(item, i);
    }) : [];
A
afc163 已提交
155 156
    this.setState({
      selectedRowKeys: selectedRowKeys
157 158
    });
    if (this.props.rowSelection.onSelectAll) {
Y
yiminghe 已提交
159 160
      let selectedRows = data.filter((row, i) => {
        return selectedRowKeys.indexOf(this.getRecordKey(row, i)) >= 0;
A
afc163 已提交
161 162
      });
      this.props.rowSelection.onSelectAll(checked, selectedRows);
A
afc163 已提交
163
    }
A
afc163 已提交
164
  },
165
  handlePageChange(current) {
Y
yiminghe 已提交
166
    let pagination = objectAssign({}, this.state.pagination);
167 168 169 170 171
    if (current) {
      pagination.current = current;
    } else {
      pagination.current = pagination.current || 1;
    }
Y
yiminghe 已提交
172 173 174
    this.fetch({
      // 防止内存泄漏,只维持当页
      selectedRowKeys: [],
A
afc163 已提交
175
      pagination: pagination
Y
yiminghe 已提交
176
    });
177 178
  },
  renderSelectionCheckBox(value, record, index) {
Y
yiminghe 已提交
179
    let rowIndex = this.getRecordKey(record, index); // 从 1 开始
A
afc163 已提交
180
    let checked = this.state.selectedRowKeys.indexOf(rowIndex) >= 0;
Y
yiminghe 已提交
181 182 183 184
    return <Checkbox checked={checked} onChange={this.handleSelect.bind(this, record, rowIndex)}/>;
  },
  getRecordKey(record, index){
    return record.key || index;
185 186
  },
  renderRowSelection() {
Y
yiminghe 已提交
187
    let columns = this.props.columns.concat();
188
    if (this.props.rowSelection) {
Y
yiminghe 已提交
189 190 191 192 193 194 195 196 197 198 199
      let data = this.getCurrentPageData();
      let checked;
      if (!data.length) {
        checked = false;
      } else {
        checked = data.every((item, i) => {
          let key = this.getRecordKey(item, i);
          return this.state.selectedRowKeys.indexOf(key) >= 0;
        });
      }
      let checkboxAll = <Checkbox checked={checked} onChange={this.handleSelectAllRow}/>;
200 201 202 203
      let selectionColumn = {
        key: 'selection-column',
        title: checkboxAll,
        width: 60,
A
afc163 已提交
204 205
        render: this.renderSelectionCheckBox,
        className: 'ant-table-selection-column'
206 207
      };
      if (columns[0] &&
Y
yiminghe 已提交
208
        columns[0].key === 'selection-column') {
209 210 211 212 213 214 215
        columns[0] = selectionColumn;
      } else {
        columns.unshift(selectionColumn);
      }
    }
    return columns;
  },
Y
yiminghe 已提交
216 217 218 219 220 221 222 223 224 225 226 227 228

  getCurrentPageData(){
    return this.isLocalDataSource() ? this.getLocalDataPaging() : this.state.data;
  },

  getColumnKey(column){
    return column.key || column.dataIndex;
  },

  renderColumnsDropdown(columns) {
    return columns.map((column) => {
      column = objectAssign({}, column);
      let key = this.getColumnKey(column);
A
afc163 已提交
229
      let filterDropdown, menus, sortButton;
230
      if (column.filters && column.filters.length > 0) {
Y
yiminghe 已提交
231 232 233 234
        let colFilters = this.state.filters[key] || [];
        menus = <FilterMenu column={column}
                            selectedFilters={colFilters}
                            confirmFilter={this.handleFilter}/>;
A
afc163 已提交
235
        let dropdownSelectedClass = '';
Y
yiminghe 已提交
236
        if (colFilters.length > 0) {
A
afc163 已提交
237 238 239
          dropdownSelectedClass = 'ant-table-filter-selected';
        }
        filterDropdown = <Dropdown trigger="click"
Y
yiminghe 已提交
240 241
                                   closeOnSelect={false}
                                   overlay={menus}>
A
afc163 已提交
242
          <i title="筛选" className={'anticon anticon-bars ' + dropdownSelectedClass}></i>
A
afc163 已提交
243 244 245
        </Dropdown>;
      }
      if (column.sorter) {
246
        let isSortColumn = (this.state.sortColumn === column);
A
afc163 已提交
247 248
        sortButton = <div className="ant-table-column-sorter">
          <span className={'ant-table-column-sorter-up ' +
249
                           ((isSortColumn && this.state.sortOrder === 'ascend') ? 'on' : 'off')}
Y
yiminghe 已提交
250 251
                title="升序排序"
                onClick={this.toggleSortOrder.bind(this, 'ascend', column)}>
A
afc163 已提交
252 253 254
            <i className="anticon anticon-caret-up"></i>
          </span>
          <span className={'ant-table-column-sorter-down ' +
255
                           ((isSortColumn && this.state.sortOrder === 'descend') ? 'on' : 'off')}
Y
yiminghe 已提交
256 257
                title="降序排序"
                onClick={this.toggleSortOrder.bind(this, 'descend', column)}>
A
afc163 已提交
258 259 260 261
            <i className="anticon anticon-caret-down"></i>
          </span>
        </div>;
      }
Y
yiminghe 已提交
262
      let originalTitle = column.title;
A
afc163 已提交
263
      column.title = [
Y
yiminghe 已提交
264
        originalTitle,
A
afc163 已提交
265 266 267
        sortButton,
        filterDropdown
      ];
A
afc163 已提交
268
      return column;
A
afc163 已提交
269 270
    });
  },
271 272
  renderPagination() {
    // 强制不需要分页
Y
yiminghe 已提交
273 274
    if (!this.hasPagination()) {
      return null;
A
afc163 已提交
275
    }
A
afc163 已提交
276 277 278 279
    let classString = 'ant-table-pagination';
    if (this.props.size === 'small') {
      classString += ' mini';
    }
Y
yiminghe 已提交
280 281 282 283
    let total;
    if (this.isLocalDataSource()) {
      total = this.getLocalData().length;
    }
A
afc163 已提交
284
    return <Pagination className={classString}
Y
yiminghe 已提交
285 286 287
                       onChange={this.handlePageChange}
                       total={total}
                       pageSize={10}
288
      {...this.state.pagination} />;
A
afc163 已提交
289
  },
Y
yiminghe 已提交
290
  prepareParamsArguments(state) {
291 292 293
    // 准备筛选、排序、分页的参数
    let pagination;
    let filters = {};
A
afc163 已提交
294
    let sorter = {};
Y
yiminghe 已提交
295 296 297 298 299
    pagination = state.pagination;
    this.props.columns.forEach((column) => {
      let colFilters = state.filters[this.getColumnKey(column)] || [];
      if (colFilters.length > 0) {
        filters[this.getColumnKey(column)] = colFilters;
300 301
      }
    });
Y
yiminghe 已提交
302 303 304 305 306
    if (state.sortColumn &&
      state.sortOrder &&
      state.sortColumn.dataIndex) {
      sorter.field = state.sortColumn.dataIndex;
      sorter.order = state.sortOrder;
A
afc163 已提交
307 308
    }
    return [pagination, filters, sorter];
309
  },
Y
yiminghe 已提交
310 311 312 313 314 315 316 317 318 319 320 321 322

  fetch(newState) {
    if (this.isLocalDataSource()) {
      if (newState) {
        this.setState(newState);
      }
    } else {
      let state = objectAssign({}, this.state, newState);
      if (newState || !this.state.loading) {
        this.setState(objectAssign({
          loading: true
        }, newState));
      }
A
afc163 已提交
323
      // remote 模式使用 this.dataSource
Y
yiminghe 已提交
324
      let dataSource = this.getRemoteDataSource();
A
afc163 已提交
325
      jQuery.ajax({
326
        url: dataSource.url,
Y
yiminghe 已提交
327
        data: dataSource.getParams.apply(this, this.prepareParamsArguments(state)) || {},
A
afc163 已提交
328 329
        headers: dataSource.headers,
        dataType: 'json',
A
afc163 已提交
330 331
        success: (result) => {
          if (this.isMounted()) {
A
afc163 已提交
332
            let pagination = objectAssign(
Y
yiminghe 已提交
333
              state.pagination,
A
afc163 已提交
334 335
              dataSource.getPagination.call(this, result)
            );
A
afc163 已提交
336
            this.setState({
Y
yiminghe 已提交
337
              loading: false,
338
              data: dataSource.resolve.call(this, result),
Y
yiminghe 已提交
339
              pagination: pagination
A
afc163 已提交
340 341 342
            });
          }
        },
A
afc163 已提交
343
        error: () => {
A
afc163 已提交
344
          this.setState({
Y
yiminghe 已提交
345 346
            loading: false,
            data: []
A
afc163 已提交
347 348 349
          });
        }
      });
Y
yiminghe 已提交
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
    }
  },

  findColumn(myKey){
    return this.props.columns.filter((c) => {
      return this.getColumnKey(c) === myKey;
    })[0];
  },

  getLocalDataPaging(){
    let data = this.getLocalData();
    let current, pageSize;
    let state = this.state;
    // 如果没有分页的话,默认全部展示
    if (!this.hasPagination()) {
      pageSize = Number.MAX_VALUE;
      current = 1;
367
    } else {
Y
yiminghe 已提交
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401
      pageSize = state.pagination.pageSize;
      current = state.pagination.current;
    }
    // 分页
    // ---
    // 当数据量少于每页数量时,直接设置数据
    // 否则进行读取分页数据
    if (data.length > pageSize || pageSize === Number.MAX_VALUE) {
      data = data.filter((item, i) => {
        if (i >= (current - 1) * pageSize &&
          i < current * pageSize) {
          return item;
        }
      });
    }
    return data;
  },

  getLocalData(){
    let state = this.state;
    let data = this.props.dataSource;
    // 排序
    if (state.sortOrder && state.sorter) {
      data = data.sort(state.sorter);
    }
    // 筛选
    if (state.filters) {
      Object.keys(state.filters).forEach((columnKey) => {
        let col = this.findColumn(columnKey);
        let values = state.filters[columnKey] || [];
        data = data.filter((record) => {
          return values.some((v)=> {
            return col.onFilter(v, record);
          });
402
        });
A
afc163 已提交
403
      });
A
afc163 已提交
404
    }
Y
yiminghe 已提交
405
    return data;
A
afc163 已提交
406
  },
Y
yiminghe 已提交
407

A
afc163 已提交
408
  componentDidMount() {
Y
yiminghe 已提交
409 410 411
    if (!this.isLocalDataSource()) {
      this.fetch();
    }
A
afc163 已提交
412
  },
413

Y
yiminghe 已提交
414 415 416 417 418
  render() {
    let data = this.getCurrentPageData();
    let columns = this.renderRowSelection();
    let classString = '';
    if (this.state.loading && this.isLocalDataSource()) {
A
afc163 已提交
419 420 421 422 423
      classString += ' ant-table-loading';
    }
    if (this.props.size === 'small') {
      classString += ' ant-table-small';
    }
Y
yiminghe 已提交
424
    columns = this.renderColumnsDropdown(columns);
425
    return <div className="clearfix">
Y
yiminghe 已提交
426 427 428 429 430 431
      <Table
        {...this.props}
        data={data || []}
        columns={columns}
        className={classString}
        />
432 433
      {this.renderPagination()}
    </div>;
A
afc163 已提交
434 435
  }
});