Open dlrandy opened 4 years ago
import React from 'react'; import { findDOMNode } from 'react-dom'; import ReactDataGrid from 'react-data-grid-6-revision'; import { range, debounce } from 'lodash'; import { Spin } from 'antd';
import Toolbar from './components/Toolbar'; import { formatDate, PRIORITY_MAP } from './../TableUtils/helpers'; function formatCellCopyData(cellData, key) { if (key.toLowerCase().indexOf('date') >= 0) { return formatDate(cellData[key]); } else if (key == 'isLock') { return cellData[key] == 1 ? '是' : '否'; } else if (key == 'priority') { return PRIORITY_MAP[cellData[key]]; } return cellData[key]; } export default class RecordsTable extends React.Component { constructor(props) { super(props); this.canvas = null; this.copyRef = React.createRef(); this.scrollListener = debounce(() => { if (this.canvas.scrollHeight === this.canvas.scrollTop + this.canvas.clientHeight) { this.props.loadNextPage(); } }, 200); this.state = {}; }
componentDidMount() {
this.canvas = findDOMNode(this).querySelector('.react-grid-Canvas');
this.canvas.addEventListener('scroll', this.scrollListener);
document.addEventListener('copy', this.handleCopy);
}
componentWillUnmount() {
if (this.canvas) {
this.canvas.removeEventListener('scroll', this.scrollListener);
}
document.removeEventListener('copy', this.handleCopy);
}
handleCopy = e => {
console.debug('handleCopy Called');
e.preventDefault();
const text = this.parseCopyData(this.state.copyData);
console.debug('text', text);
e.clipboardData.setData('text/plain', text);
};
parseCopyData = copyData => {
const { topLeft, bottomRight } = copyData;
if (!topLeft || !bottomRight) {
return;
}
console.log(topLeft, bottomRight, '00000999999999');
const copyDataKeyTransformer = this.props.copyDataKeyTransformer || (key => key);
const text = range(topLeft.rowIdx, bottomRight.rowIdx + 1)
.map(rowIdx =>
this.props.columns
.slice(topLeft.idx, bottomRight.idx + 1)
.map(col =>
this.rowGetter(rowIdx)
? formatCellCopyData(
this.rowGetter(rowIdx),
copyDataKeyTransformer(col.key)
)
: ''
)
.join('\t')
)
.join('\n');
return text;
};
executeCopy = copyData => {
const text = this.parseCopyData(copyData);
this.copyRef.current.value = text;
this.copyRef.current.select();
document.execCommand('copy');
};
onGridRowsUpdated = ({ fromRow, toRow, updated }) => {
this.setState(state => {
const rows = state.rows.slice();
for (let i = fromRow; i <= toRow; i++) {
rows[i] = { ...rows[i], ...updated };
}
return { rows };
});
};
rowGetter = i => this.props.records[i];
rowRenderer = ({ renderBaseRow, ...props }) => {
const { validateFn = () => void 0 } = this.props;
return <div style={validateFn(props)}>{renderBaseRow(props)}</div>;
};
render() {
return (
<div>
<textarea ref={this.copyRef} style={{ width: 0, height: 0, opacity: 0 }} />
<Spin tip="加载中..." spinning={this.props.loading}>
{this.props.showToolBar && <Toolbar onAddRow={this.props.addLine} />}
<ReactDataGrid
ref={'grid'}
minHeight={this.props.minHeight}
rowHeight={this.props.rowHeight || 30}
enableCellSelect={true}
headerRowHeight={this.props.headerRowHeight || 40}
rowRenderer={this.rowRenderer}
cellRangeSelection={
this.props.enableCellRangeSelection
? {
onComplete: args => {
// this.executeCopy(args);
this.setState(state => ({
copyData: args
}));
}
}
: undefined
}
onGridRowsUpdated={this.props.onGridRowsUpdated}
columns={this.props.columns}
rowGetter={this.props.rowGetter || this.rowGetter}
rowsCount={this.props.records.length}
rowSelection={
this.props.enableRowSelection
? {
showCheckbox: true,
enableShiftSelect: true,
onRowsSelected: rows => {
const ids = rows.map(({ row }) => row.id);
const records = this.props.records.filter(
r => ids.indexOf(r.id) > -1
);
this.props.selectRecords(records);
},
onRowsDeselected: rows => {
const ids = rows.map(({ row }) => row.id);
const records = this.props.records.filter(
r => ids.indexOf(r.id) > -1
);
this.props.deselectRecords(records);
},
selectBy: {
// indexes: this.props.selectedRecords.map((r) =>
// this.props.records.indexOf(r)
// )
}
}
: undefined
}
getCellActions={this.props.getCellActions}
/>{' '}
</Spin>
</div>
);
}
} import React, { useState } from 'react'; import ReactDOM from 'react-dom'; import { debounce } from 'lodash'; import { useAbortableEffect } from '../../../common/Hooks'; import { useGetApi, getApi } from '../../../common/Api';
import { Select } from 'antd'; const Option = Select.Option; export class SelectEditor extends React.Component { constructor(props) { super(props); const data = typeof props.column.data === 'function' ? props.column.data(props.rowData) : props.column.data || []; this.state = { value: props.value, relateData: {}, options: data.map(option => ({ ...option, text: option.text || option.label })) }; const { onChange, url, placeholder = '请选择' } = this.props.column; this.onChange = onChange; this.url = url; this.placeholder = placeholder; this.status = { aborted: false }; this.searchVal = ''; }
getValue = async () => {
return {
...this.state.relateData,
[this.props.column.key]: this.state.value
};
};
getInputNode = () => {
return ReactDOM.findDOMNode(this).querySelector('.ant-select-selection-selected-value');
};
disableContainerStyles = () => {
return true;
};
handleChangeComplete = async (value, option) => {
const data = this.props.column.onChange
? await this.props.column.onChange(
option.props,
this.props.rowData,
this.state.options.find(op => op.value === value)
)
: {};
this.setState({ value, relateData: data }, () => {
this.props.onCommit();
});
};
async componentDidMount() {}
componentWillUnmount() {
this.status.aborted = true;
}
searchData = debounce(_value => {
this.searchVal = _value;
this.getOptions();
}, 500);
getOptions = async () => {
if (!this.url) {
return;
}
const url = typeof this.url === 'function' ? this.url(this.props.rowData) : this.url;
const data = await getApi(url, { key: this.searchVal });
this.setState({
options: data.map(m => {
return {
...m,
value: m.fvalue || m.value,
label: m.text || m.ftext || m.fvalue,
text: m.text || m.ftext || m.fvalue
};
})
});
};
render() {
return (
<Select
autoFocus
style={{ width: '100%' }}
defaultValue={this.state.value && String(this.state.value)}
onChange={this.handleChangeComplete}
onFocus={() => this.getOptions()}
filterOption={false}
onSearch={
this.props.column.showSearch //&& onSearch
? this.searchData
: undefined
}
showSearch
>
{this.state.options.map(option => (
<Option value={option.value} key={option.value}>
{option.text}
</Option>
))}
</Select>
);
}
} import React, { useRef, useLayoutEffect } from 'react'; import ReactDOM from 'react-dom';
import { debounce } from 'lodash'; import { Input, InputNumber, DatePicker } from 'antd';
const InputArea = Input.TextArea;
export class TextEditor extends React.Component { constructor(props) { super(props); this.state = { value: props.value }; }
getValue = () => {
return { [this.props.column.key]: this.state.value };
};
getInputNode() {
return ReactDOM.findDOMNode(this).getElementsByTagName('input')[0];
}
disableContainerStyles = () => {
return true;
};
handleChangeComplete = e => {
this.setState({ value: e });
};
// handleChangeComplete = debounce(e => {
// this.setState({ value: e }, () => this.props.onCommit());
// }, 2000);
render() {
return (
<Input
autoFocus
onPressEnter={() => this.props.onCommit()}
defaultValue={this.state.value}
onChange={e => this.handleChangeComplete(e.target.value)}
/>
);
}
}
export class TextNumEditor extends React.Component { constructor(props) { super(props); this.state = { value: props.value, relateData: {} }; }
getValue = () => {
return { [this.props.column.key]: this.state.value, ...this.state.relateData };
};
getInputNode = () => {
return ReactDOM.findDOMNode(this).getElementsByTagName('input')[0];
};
disableContainerStyles = () => {
return true;
};
// handleChangeComplete = debounce(async e => {
// const data = this.props.column.onChange
// ? await this.props.column.onChange(e, this.props.rowData)
// : {};
// this.setState({ value: e, relateData: data }, () => this.props.onCommit());
// }, 2000);
handleChangeComplete = async e => {
const data = this.props.column.onChange
? await this.props.column.onChange(e, this.props.rowData)
: {};
this.setState({ value: e, relateData: data });
};
render() {
return (
<InputNumber
autoFocus
onPressEnter={() => this.props.onCommit()}
style={{ width: '80%', paddingLeft: 6, fontSize: 14 }}
defaultValue={this.state.value}
onChange={val => this.handleChangeComplete(val)}
/>
);
}
}
const dateFormat = 'YYYY-MM-DD HH:mm:ss'; export class TextDateEditor extends React.Component { constructor(props) { super(props); this.state = { value: props.value }; }
getValue = () => {
return { [this.props.column.key]: this.state.value };
};
getInputNode() {
return ReactDOM.findDOMNode(this).getElementsByTagName('input')[0];
}
disableContainerStyles = () => {
return true;
};
handleChangeComplete = (value, dateString) => {
this.setState({ value: dateString }, () => this.props.onCommit());
};
render() {
return (
<DatePicker
placeholder="选择时间"
format={dateFormat}
onChange={this.handleChangeComplete}
/>
);
}
}
` import React, { useReducer, useState } from "react"; import ReactDOM, { findDOMNode } from "react-dom"; import ReactDataGrid from "react-data-grid"; import { range } from "lodash"; import { Icon } from 'antd' // import { Menu } from "react-data-grid-addons";
import createRowData, { createFakeRow } from "./createRowData";
// import "./styles.css";
class RecordsTable extends React.Component { constructor(props) { super(props); this.canvas = null; this.copyRef = React.createRef(); this.scrollListener = () => { if ( this.canvas.scrollHeight === this.canvas.scrollTop + this.canvas.clientHeight ) { this.props.loadNextPage(); } }; }
canvas = null; state = { copyData: {} };
componentDidMount() { this.canvas = findDOMNode(this).querySelector(".react-grid-Canvas"); this.canvas.addEventListener("scroll", this.scrollListener); // document.addEventListener("copy", this.handleCopy); }
componentWillUnmount() { if (this.canvas) { this.canvas.removeEventListener("scroll", this.scrollListener); } document.removeEventListener("copy", this.handleCopy); }
parseCopyData = (copyData) => { console.log(copyData, "-------"); const { topLeft, bottomRight } = copyData; if (!topLeft || !bottomRight) { return; } // Loop through each row const text = range(topLeft.rowIdx, bottomRight.rowIdx + 1) .map( // Loop through each column 这里有和没有选择框索引是不一样的 (rowIdx) => columns .slice(topLeft.idx - 1, bottomRight.idx) .map( // Grab the row values and make a text string (col) => this.rowGetter(rowIdx)[col.key] ) .join("\t") ) .join("\n"); return text; };
executeCopy = (copyData) => { const text = this.parseCopyData(copyData); console.log(text); this.copyRef.current.value = text; this.copyRef.current.select(); document.execCommand("copy"); };
handleCopy = (e) => { console.debug("handleCopy Called"); e.preventDefault(); const text = this.parseCopyData(this.state.copyData); console.debug("text", text); e.clipboardData.setData("text/plain", text); };
rowGetter = (i) => this.props.records[i];
render() { return (
} }
const defaultColumnProperties = { // sortable: true, width: 120, resizable: true };
const columns = [ { key: "id", name: "ID", sortDescendingFirst: true }, { key: "title", name: "Title" }, { key: "firstName", name: "First Name" }, { key: "lastName", name: "Last Name" }, { key: "email", name: "Email" }, { key: "street", name: "Street" }, { key: "zipCode", name: "ZipCode" }, { key: "date", name: "Date" }, { key: "jobTitle", name: "Job Title" }, { key: "catchPhrase", name: "Catch Phrase" }, { key: "jobArea", name: "Job Area" }, { key: "jobType", name: "Job Type" } ].map((c) => ({ ...c, ...defaultColumnProperties }));
const ROW_COUNT = 50; let pages = 1; const firstNameActions = [ { icon: ,
callback: () => {
alert("Deleting");
}
},
{
icon: ,
actions: [
{
text: "Option 1",
callback: () => {
alert("Option 1 clicked");
}
},
{
text: "Option 2",
callback: () => {
alert("Option 2 clicked");
}
}
]
}
];
export default function Example({ rows = createRowData(50 pages), loadNextPage=() => createRowData(50 ++pages) }) {
const [state, dispatch] = React.useReducer(
(state, action) => state.concat(action),
rows
);
function getCellActions(column, row) {
const cellActions = {
jobType: firstNameActions
};
return cellActions[column.key];
}
return (
); }
`