Commit 01c56eb9 authored by XieZhiXiong's avatar XieZhiXiong

完善表格组件,新增可编辑列表格组件

parent 7eee52fa
import React, { useContext, useState, useEffect, useRef } from 'react';
import {
Card,
Input,
Button,
Form,
message,
} from 'antd';
import { StandardTableProps, EditableCellProps, EditableColumns } from './interface';
import NormalTable from './NormalTable';
const EditableContext = React.createContext<any>({});
interface EditableRowProps {
index: number;
}
const EditableRow: React.FC<EditableRowProps> = ({ index, ...props }) => {
const [form] = Form.useForm();
return (
<Form form={form} component={false}>
<EditableContext.Provider value={form}>
<tr {...props} />
</EditableContext.Provider>
</Form>
);
};
const EditableCell: React.FC<EditableCellProps> = ({
title,
editable,
children,
dataIndex,
index,
record,
rules = [],
addonAfter = null,
onSave,
onValidateError,
...restProps
}) => {
const [editing, setEditing] = useState(true);
const inputRef = useRef();
const form = useContext(EditableContext);
const inputId = `${dataIndex}-${index}`; // 拼接 name-index,不然全部展示输入框会警告 id 不唯一的问题
useEffect(() => {
if (editing) {
// inputRef.current.focus();
}
}, [editing]);
const toggleEdit = () => {
setEditing(!editing);
form.setFieldsValue({ [dataIndex]: record[dataIndex] });
};
const save = async e => {
try {
const values = await form.validateFields();
// toggleEdit();
if (onSave) {
onSave({
...record,
[dataIndex]: values[inputId],
});
}
} catch (errInfo) {
if (onValidateError) {
onValidateError(errInfo);
}
}
};
let childNode = children;
if (editable) {
childNode = editing ? (
<Form.Item
style={{ margin: 0 }}
name={inputId}
rules={rules}
initialValue={record[dataIndex]}
>
<Input
ref={inputRef}
onPressEnter={save}
onBlur={save}
addonAfter={addonAfter}
/>
</Form.Item>
) : (
<div
className="editable-cell-value-wrap"
style={{ paddingRight: 24 }} onClick={toggleEdit}
>
{children}
</div>
);
}
return <td {...restProps}>{childNode}</td>;
};
const EditableCellTable: React.FC<StandardTableProps> = props => {
const components = {
body: {
row: EditableRow,
cell: EditableCell,
},
};
return (
<NormalTable
components={components}
rowClassName={() => 'editable-row'}
{...props}
/>
);
};
export default React.memo(EditableCellTable);
\ No newline at end of file
/*
* @Author: XieZhiXiong
* @Date: 2020-08-20 16:15:59
* @LastEditors: XieZhiXiong
* @LastEditTime: 2020-08-21 11:18:36
* @Description: 简单封装了分页事件的 Table
*/
import React from 'react';
import { Table } from 'antd';
import classNames from 'classnames';
import { TableProps, TablePaginationConfig, ColumnType } from 'antd/lib/table';
import { PaginationProps } from 'antd/lib/pagination';
import { StandardTableProps } from './interface';
import styles from './index.less';
export default class NormalTable extends React.PureComponent<StandardTableProps> {
state = {
page: 1,
size: 10,
};
handlePaginationChange = (page: number, size: number) => {
const { pagination = {}, onPaginationChange } = this.props;
const { current, pageSize } = pagination;
// 内部自己维护 page、size, 单独控制当前页 或 当前页数
if (!('current' in pagination)) {
this.setState({ page: current });
}
if (!('pageSize' in pagination)) {
this.setState({ size: pageSize });
}
if (onPaginationChange) {
onPaginationChange(page, size);
}
};
render() {
const { page, size } = this.state;
const {
columns,
dataSource,
rowKey = 'id',
pagination = {},
loading,
className,
onPaginationChange,
...restProps
} = this.props;
const newPagination: any = pagination ? {
current: page,
pageSize: size,
showSizeChanger: true,
showQuickJumper: true,
onChange: this.handlePaginationChange,
onShowSizeChange: this.handlePaginationChange,
size: 'small',
showTotal: () => `共 ${pagination.total || 0} 条`,
...pagination,
} : false;
return (
<div className={classNames(className)}>
<Table
rowKey={rowKey}
columns={columns}
dataSource={dataSource}
loading={loading}
pagination={newPagination}
{...restProps}
/>
</div>
)
}
}
\ No newline at end of file
import React from 'react';
import { Table } from 'antd';
import classNames from 'classnames';
import { TableProps, TablePaginationConfig, ColumnType } from 'antd/lib/table';
import { PaginationProps } from 'antd/lib/pagination';
import styles from './index.less';
import NormalTable from './NormalTable';
import EditableCellTable from './EditableCellTable';
export interface StandardTableProps extends TableProps<any> {
pagination: TablePaginationConfig;
onPaginationChange?: (page: number, size: number) => void;
};
export default class StandardTable extends React.PureComponent<StandardTableProps> {
state = {
page: 1,
size: 10,
};
handlePaginationChange = (page: number, size: number) => {
const { pagination = {}, onPaginationChange } = this.props;
const { current, pageSize } = pagination;
// 内部自己维护 page、size, 单独控制当前页 或 当前页数
if (!('current' in pagination)) {
this.setState({ page: current });
}
if (!('pageSize' in pagination)) {
this.setState({ size: pageSize });
}
if (onPaginationChange) {
onPaginationChange(page, size);
}
};
render() {
const { page, size } = this.state;
const {
columns,
dataSource,
rowKey = 'id',
pagination = {},
loading,
className,
onPaginationChange,
...restProps
} = this.props;
const newPagination: any = pagination ? {
current: page,
pageSize: size,
showSizeChanger: true,
showQuickJumper: true,
onChange: this.handlePaginationChange,
onShowSizeChange: this.handlePaginationChange,
size: 'small',
showTotal: () => `共 ${pagination.total || 0} 条`,
...pagination,
} : false;
return (
<div className={classNames(className)}>
<Table
rowKey={rowKey}
columns={columns}
dataSource={dataSource}
loading={loading}
pagination={newPagination}
{...restProps}
/>
</div>
)
}
export {
NormalTable as default,
EditableCellTable,
}
\ No newline at end of file
import { TableProps, TablePaginationConfig, ColumnType } from 'antd/lib/table';
export interface StandardTableProps extends TableProps<any> {
pagination?: TablePaginationConfig;
onPaginationChange?: (page: number, size: number) => void;
}
export interface EditableCellProps {
onSave?: (row: {[key: string]: any}) => void,
onValidateError?: (error: {[key: string]: any}) => void,
record?: any;
index?: number;
dataIndex: string | number;
title?: React.ReactNode;
editable?: boolean;
children?: React.ReactNode;
rules?: Array<any>;
addonAfter?: React.ReactNode;
}
interface EditableColumns extends ColumnType<any> {
dataIndex?: string | number;
editable?: boolean;
rules?: Array<any>;
}
\ No newline at end of file
export interface MemberType {
id: number;
typeName: string;
}
export interface BusinessType {
id: number;
typeName: string;
}
export interface UseType {
memberType: MemberType[];
businessType: BusinessType[];
}
export interface UserRegister {
useType: UseType;
}
export interface ShopInfo {
id: number;
name: string;
type: number;
environment: number;
logoUrl: string;
describe: string;
state: number;
url: string;
}
export interface Web {
shopInfo: ShopInfo[];
}
export interface PayConfig {
paymemberConfig?: any;
}
export interface CountryList {
name: string;
key: string;
icon: string;
}
export interface Global {
siteId: number;
siteUrl: string;
logo: string;
countryList: CountryList[];
}
export interface RootObject {
userRegister: UserRegister;
web: Web;
payConfig: PayConfig;
global: Global;
}
\ No newline at end of file
......@@ -259,8 +259,8 @@ h6 {
padding: 4px 11px;
}
.editable-row .ant-form-explain {
.editable-row .ant-form-item-explain {
position: absolute;
top: 100%;
font-size: 12px;
margin-top: -4px;
}
\ No newline at end of file
......@@ -11,7 +11,8 @@ import { PublicApi } from '@/services/api';
import { VIP_RULE_TRANSACTION, VIP_RULE_LOGIN, VIP_RULE_COMMENT } from '@/constants';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import { ContainerOutlined } from '@ant-design/icons';
import StandardTable from '@/components/StandardTable';
import StandardTable, { EditableCellTable } from '@/components/StandardTable';
import { EditableCellProps, EditableColumns } from '@/components/StandardTable/interface';
const EditableContext = React.createContext<any>({});
......@@ -30,18 +31,6 @@ const EditableRow: React.FC<EditableRowProps> = ({ index, ...props }) => {
);
};
interface EditableCellProps {
title: React.ReactNode;
editable: boolean;
children: React.ReactNode;
dataIndex: string;
index: number;
record: any;
rules: any;
handleSave: (record: any) => void;
addonAfter: React.ReactNode,
}
const EditableCell: React.FC<EditableCellProps> = ({
title,
editable,
......@@ -51,7 +40,8 @@ const EditableCell: React.FC<EditableCellProps> = ({
record,
rules = [],
addonAfter = null,
handleSave,
onSave,
onValidateError,
...restProps
}) => {
const [editing, setEditing] = useState(true);
......@@ -75,12 +65,16 @@ const EditableCell: React.FC<EditableCellProps> = ({
const values = await form.validateFields();
// toggleEdit();
handleSave({
if (onSave) {
onSave({
...record,
[dataIndex]: values[inputId],
});
}
} catch (errInfo) {
console.log('Save failed:', errInfo);
if (onValidateError) {
onValidateError(errInfo);
}
}
};
......@@ -114,19 +108,15 @@ const EditableCell: React.FC<EditableCellProps> = ({
return <td {...restProps}>{childNode}</td>;
};
interface Columns extends ColumnType<any> {
editable?: boolean;
rules?: Array<any>;
}
const MemberUpgradeRule: React.FC<[]> = () => {
const PAGE_SIZE = 10;
const [page, setPage] = useState(1);
const [size, setSize] = useState(10);
const [size, setSize] = useState(PAGE_SIZE);
const [total, setTotal] = useState(0);
const [dataSource, setDataSource] = useState([]);
const [listLoading, setListLoading] = useState(true);
const [submitLoading, setSubmitLoading] = useState(false);
const [submitDisabled, setSubmitDisabled] = useState(false);
const getRuleList = async (params) => {
setListLoading(true);
......@@ -147,7 +137,7 @@ const MemberUpgradeRule: React.FC<[]> = () => {
});
}, [page, size]);
const columns: Columns[] = [
const columns: EditableColumns[] = [
{
title: 'ID',
dataIndex: 'id',
......@@ -167,6 +157,7 @@ const MemberUpgradeRule: React.FC<[]> = () => {
{
title: '可获取的分值',
dataIndex: 'point',
align: 'center',
width: '30%',
editable: true,
},
......@@ -190,6 +181,11 @@ const MemberUpgradeRule: React.FC<[]> = () => {
setDataSource(newData);
};
// 表单元素校验失败事件
const handleValidateError = errInfo => {
// do something
};
const handleSubmit = async () => {
if (!dataSource.length) {
return;
......@@ -224,19 +220,19 @@ const MemberUpgradeRule: React.FC<[]> = () => {
[VIP_RULE_TRANSACTION]: [
{
pattern: /^([0]|[1-9]+[0-9]*)(\.[0-9]+)?$/,
message: '请输入正确的格式',
message: '请输入整数或小数',
},
],
[VIP_RULE_LOGIN]: [
{
pattern: /^[0]$|^[1-9]+[0-9]*$/,
message: '请输入正确的格式',
message: '请输入整数数值',
},
],
[VIP_RULE_COMMENT]: [
{
pattern: /^[0]$|^[1-9]+[0-9]*$/,
message: '请输入正确的格式',
message: '请输入整数数值',
},
],
};
......@@ -247,8 +243,9 @@ const MemberUpgradeRule: React.FC<[]> = () => {
}
return {
...col,
onCell: (record, index) => ({
handleSave,
onCell: (record, index): EditableCellProps => ({
onSave: handleSave,
onValidateError: handleValidateError,
record,
index,
dataIndex: col.dataIndex,
......@@ -273,6 +270,7 @@ const MemberUpgradeRule: React.FC<[]> = () => {
type="primary"
icon={<ContainerOutlined />}
loading={submitLoading}
disabled={submitDisabled}
onClick={handleSubmit}
>
保存
......@@ -280,17 +278,9 @@ const MemberUpgradeRule: React.FC<[]> = () => {
}
>
<Card>
<div className="editable-row">
<div className="ant-form-explain">
123
</div>
</div>
<StandardTable
<EditableCellTable
dataSource={dataSource}
columns={newColumns}
components={components}
rowClassName={() => 'editable-row'}
loading={listLoading}
pagination={{
pageSize: size,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment