Commit bc271234 authored by 邓晓峰's avatar 邓晓峰

Merge branch 'fix/table' into 'dev'

fix: update table See merge request !27
parents a834a2fe 49522451
Pipeline #25747 failed with stages
in 8 seconds
...@@ -45,7 +45,7 @@ const Demo = () => { ...@@ -45,7 +45,7 @@ const Demo = () => {
return ( return (
<div style={{ height: '400px' }}> <div style={{ height: '400px' }}>
{!!dataSource.length && ( {!!dataSource.length && (
<BasicTable dataSource={dataSource} columns={columns} scroll={{ y: 294 }} /> <BasicTable dataSource={dataSource} columns={columns} bordered={true} />
)} )}
{!dataSource.length && <Empty description={'暂无数据'} />} {!dataSource.length && <Empty description={'暂无数据'} />}
</div> </div>
......
...@@ -8,7 +8,7 @@ const BasicTable = (props) => { ...@@ -8,7 +8,7 @@ const BasicTable = (props) => {
const { getPrefixCls } = useContext(ConfigProvider.ConfigContext); const { getPrefixCls } = useContext(ConfigProvider.ConfigContext);
const prefixCls = getPrefixCls('basic-table'); const prefixCls = getPrefixCls('basic-table');
return <Table className={classNames(prefixCls)} {...props} bordered />; return <Table className={classNames(prefixCls)} scroll={{ y: 'calc(100% - 40px)' }} {...props} />;
}; };
BasicTable.defaultProps = { BasicTable.defaultProps = {
......
...@@ -2,16 +2,21 @@ ...@@ -2,16 +2,21 @@
@basic-table-prefix-cls: ~'@{ant-prefix}-basic-table'; @basic-table-prefix-cls: ~'@{ant-prefix}-basic-table';
.@{basic-table-prefix-cls} { .@{basic-table-prefix-cls} {
display: flex;
flex-direction: column;
height: 100%; height: 100%;
overflow: hidden;
.ant-table-wrapper, .ant-table-wrapper,
.ant-spin-nested-loading, .ant-spin-nested-loading,
.ant-spin-container { .ant-spin-container,
height: 100%; .ant-table,
} .ant-table-container,
.ant-table-content {
.ant-table.ant-table-bordered { display: flex;
height: calc(100% - 64px); flex: 1;
flex-direction: column;
overflow: hidden;
} }
.ant-table-tbody > tr { .ant-table-tbody > tr {
...@@ -22,10 +27,6 @@ ...@@ -22,10 +27,6 @@
background: rgba(255, 255, 255, 0); background: rgba(255, 255, 255, 0);
} }
.ant-table-tbody > tr:hover:not(.ant-table-expanded-row) > td {
background: rgba(255, 255, 255, 0);
}
.ant-table-thead > tr > th { .ant-table-thead > tr > th {
font-weight: 600; font-weight: 600;
background: white; background: white;
...@@ -37,7 +38,10 @@ ...@@ -37,7 +38,10 @@
.ant-table tfoot > tr > th, .ant-table tfoot > tr > th,
.ant-table tfoot > tr > td { .ant-table tfoot > tr > td {
padding: 8px 8px; padding: 8px 8px;
border-right: 1px solid #dbe7fb; }
.ant-table-tbody > tr:hover:not(.ant-table-expanded-row) > td {
background: rgba(255, 255, 255, 0);
} }
.ant-table-tbody > tr:nth-child(2n-1) { .ant-table-tbody > tr:nth-child(2n-1) {
...@@ -48,6 +52,10 @@ ...@@ -48,6 +52,10 @@
background: #edf2ff; background: #edf2ff;
} }
.ant-table-tbody > tr > td {
border-bottom: 1px solid #dbe7fb;
}
.ant-table.ant-table-bordered .ant-table.ant-table-bordered
> .ant-table-container > .ant-table-container
> .ant-table-content > .ant-table-content
...@@ -116,8 +124,4 @@ ...@@ -116,8 +124,4 @@
border-right: 0; border-right: 0;
border-bottom: 0; border-bottom: 0;
} }
.ant-table-tbody > tr > td {
border-bottom: 1px solid #dbe7fb;
}
} }
...@@ -2,17 +2,24 @@ import React, { useContext } from 'react'; ...@@ -2,17 +2,24 @@ import React, { useContext } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import classNames from 'classnames'; import classNames from 'classnames';
import { ConfigProvider } from 'antd'; import { ConfigProvider } from 'antd';
import noDataLight from './assets/noDataLight.svg'; import { ReactComponent as noDataLight } from './assets/noDataLight.svg';
import noDataDark from './assets/noDataDark.svg'; import { ReactComponent as noDataDark } from './assets/noDataDark.svg';
import errorLight from './assets/errorLight.png'; import errorLight from './assets/errorLight.png';
import errorDark from './assets/errorDark.png'; import errorDark from './assets/errorDark.png';
import './index.less'; import './index.less';
const IconBase = ({ icon: SvgIcon }) => {
const SvgAttributes = {
width: '100%',
height: '100%',
};
return <SvgIcon {...SvgAttributes} />;
};
const Empty = ({ description, image, theme, size, statusCode, imageStyle, children }) => { const Empty = ({ description, image, theme, size, statusCode, imageStyle, children }) => {
const alt = description ? description : 'empty'; const alt = description ? description : 'empty';
const des = description ? description : DESC_DATA[`${statusCode}`]; const des = description ? description : DESC_DATA[`${statusCode}`];
const imageSrc = image ? image : IMAGE_DATA[theme][statusCode == '0' ? 0 : 1];
const { getPrefixCls } = useContext(ConfigProvider.ConfigContext); const { getPrefixCls } = useContext(ConfigProvider.ConfigContext);
const prefixCls = getPrefixCls('panda-empty'); const prefixCls = getPrefixCls('panda-empty');
...@@ -20,7 +27,12 @@ const Empty = ({ description, image, theme, size, statusCode, imageStyle, childr ...@@ -20,7 +27,12 @@ const Empty = ({ description, image, theme, size, statusCode, imageStyle, childr
let imageNode = null; let imageNode = null;
if (typeof image === 'string') { if (typeof image === 'string') {
imageNode = <img alt={alt} src={imageSrc} />; if (statusCode == '0') {
imageNode = <IconBase icon={IMAGE_DATA[theme][0]} />;
} else {
let imageSrc = image ? image : IMAGE_DATA[theme][1];
imageNode = <img alt={alt} src={imageSrc} />;
}
} else { } else {
imageNode = image; imageNode = image;
} }
......
...@@ -29,22 +29,21 @@ group: ...@@ -29,22 +29,21 @@ group:
已选指标树 props 参考 https://ant.design/components/tree-cn/#API 已选指标树 props 参考 https://ant.design/components/tree-cn/#API
| 参数 | 说明 | 类型 | 默认值 | | 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- | | -------------- | ------------------------------ | ------------------ | -------------- |
| buttonProps | 指标选择按钮 | object | { } | | buttonProps | 指标选择按钮 | object | { } |
| width | 模态框宽度 | number | 900 | | width | 模态框宽度 | number | 900 |
| title | 模态框标题 | string | 选择显示字段 | | title | 模态框标题 | string | 选择显示字段 |
| cancelText | 模态框取消文本 | string | 取消选择 | | cancelText | 模态框取消按钮文字 | string | 取消选择 |
| placeholder | 搜索框占位符 | string | 搜索关键词 | | okText | 模态框确认按钮文字 | string | 确定 |
| searchPrefix | 搜索框前置图标 | ReactNode | SearchOutlined | | placeholder | 搜索框占位符 | string | 搜索关键词 |
| targetValue | 指标类型 | string | 重要指标 | | searchPrefix | 搜索框前置图标 | ReactNode | SearchOutlined |
| maximum | 最多可选择指标数量 | number | 0 | | maximum | 最多可选择指标数量 | number | 0 |
| dataSource | 指标列表数据源 | array | [ ] | | dataSource | 指标列表数据源 | array | [ ] |
| selectData | 已选指标数据 | array | [ ] | | selectData | 已选指标数据 | array | [ ] |
| treeProps | 已选指标树 props | object | { } | | treeProps | 已选指标树 props | object | { } |
| onModalCancel | 点击模态框取消按钮的回调 | function(value){ } | - | | onModalCancel | 点击模态框取消按钮的回调 | function(value){ } | - |
| onModalOk | 模态框点击确定回调 | function(value){ } | - | | onModalOk | 模态框点击确定回调 | function(value){ } | - |
| onModalClose | 模态框点击关闭回调 | function(value){ } | - | | onModalClose | 模态框点击关闭回调 | function(value){ } | - |
| onSearch | 搜索框输入事件的回调,会返回搜索框输入信息 | function(value){ } | - | | onTreeDrop | 拖动选中树节点的回调 | function(value){ } | - |
| onRadioChange | 指标类型切换的回调 | function(value){ } | - | | onCancelSelect | 点击已选指标树的删除按钮的回调 | function(value){ } | - |
| onCancelSelect | 点击已选指标树的删除按钮的回调 | function(value){ } | - |
...@@ -18,12 +18,7 @@ const Demo = () => { ...@@ -18,12 +18,7 @@ const Demo = () => {
}) })
.then(function (response) { .then(function (response) {
if (response.code == '0') { if (response.code == '0') {
let curData = response.data.map((item) => ({ let curData = response.data;
title: item.Name,
key: item.Name,
checked: false,
...item,
}));
setQuotaList(curData); setQuotaList(curData);
} }
}) })
...@@ -45,114 +40,23 @@ const Demo = () => { ...@@ -45,114 +40,23 @@ const Demo = () => {
}; };
const onModalCancel = () => { const onModalCancel = () => {
let newQuotaList = [...quotaList];
newQuotaList.forEach((item) => {
item.checked = false;
});
setQuotaList(newQuotaList);
setSelectData([]); setSelectData([]);
console.log('onModalCancel'); console.log('onModalCancel');
}; };
const onCheckboxChange = (e) => { const onCheckboxChange = ({ selectList }) => {
let curData = [...selectData]; setSelectData(selectList);
let newQuotaList = [...quotaList]; console.log(selectList, 'onCheckboxChange');
let data = curData.filter((item) => item.title === e.target.value);
if (data.length) {
curData = curData.filter((item) => item.title !== e.target.value);
} else {
curData.push({ key: e.target.value, title: e.target.value });
}
newQuotaList.forEach((item) => {
if (item.title === e.target.value) item.checked = !item.checked;
});
setSelectData(curData);
setQuotaList(newQuotaList);
console.log(e.target.value, 'onCheckboxChange');
}; };
const onSearch = (e) => { const onCancelSelect = ({ selectList }) => {
if (e.type === 'keydown') { setSelectData(selectList);
console.log(e.target.value, 'onSearch'); console.log(selectList, 'onCancelSelect');
}
}; };
const onRadioChange = (e) => { const onTreeDrop = ({ selectList }) => {
console.log(e, 'onRadioChange'); setSelectData(selectList);
}; console.log(selectList, 'onTreeDrop');
const onCancelSelect = ({ title }) => {
let curData = [...selectData];
let newQuotaList = [...quotaList];
let data = curData.filter((item) => item.title !== title);
newQuotaList.forEach((item) => {
if (item.title === title) item.checked = !item.checked;
});
setSelectData(data);
setQuotaList(newQuotaList);
console.log(title, 'onCancelSelect');
};
const onDragEnter = (info) => {
console.log(info, 'onDragEnter');
};
const onDrop = (info) => {
console.log(info, 'onDrop');
const dropKey = info.node.key;
const dragKey = info.dragNode.key;
const dropPos = info.node.pos.split('-');
const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1]);
const loop = (data, key, callback) => {
for (let i = 0; i < data.length; i++) {
if (data[i].key === key) {
return callback(data[i], i, data);
}
if (data[i].children) {
loop(data[i].children, key, callback);
}
}
};
const data = [...selectData];
let dragObj;
loop(data, dragKey, (item, index, arr) => {
arr.splice(index, 1);
dragObj = item;
});
if (!info.dropToGap) {
loop(data, dropKey, (item) => {
item.children = item.children || [];
item.children.unshift(dragObj);
});
} else if (
(info.node.props.children || []).length > 0 && // Has children
info.node.props.expanded && // Is expanded
dropPosition === 1 // On the bottom gap
) {
loop(data, dropKey, (item) => {
item.children = item.children || [];
item.children.unshift(dragObj);
});
} else {
let ar;
let i;
loop(data, dropKey, (item, index, arr) => {
ar = arr;
i = index;
});
if (dropPosition === -1) {
ar.splice(i, 0, dragObj);
} else {
ar.splice(i + 1, 0, dragObj);
}
}
setSelectData(data);
}; };
return ( return (
...@@ -165,19 +69,11 @@ const Demo = () => { ...@@ -165,19 +69,11 @@ const Demo = () => {
onModalOk={onModalOk} onModalOk={onModalOk}
onModalClose={onModalClose} onModalClose={onModalClose}
maximum={3} maximum={3}
targetValue={'emphasis'}
dataSource={quotaList} dataSource={quotaList}
selectData={selectData} selectData={selectData}
onSearch={onSearch}
searchPrefix={<SearchOutlined />}
onRadioChange={onRadioChange}
onCheckboxChange={onCheckboxChange} onCheckboxChange={onCheckboxChange}
onCancelSelect={onCancelSelect} onCancelSelect={onCancelSelect}
treeProps={{ onTreeDrop={onTreeDrop}
draggable: true,
onDragEnter,
onDrop,
}}
/> />
); );
}; };
......
import React, { useContext, useState } from 'react'; import React, { useContext, useEffect, useState } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import classNames from 'classnames'; import classNames from 'classnames';
import { Button, Input, Radio, Modal, Checkbox, Row, Col, Tree, ConfigProvider } from 'antd'; import { Button, Input, Radio, Modal, Checkbox, Row, Col, Tree, ConfigProvider } from 'antd';
...@@ -13,25 +13,67 @@ const QuotaSelect = ({ ...@@ -13,25 +13,67 @@ const QuotaSelect = ({
width, width,
title, title,
cancelText, cancelText,
okText,
onModalOk, onModalOk,
onModalCancel, onModalCancel,
onModalClose, onModalClose,
searchPrefix, searchPrefix,
placeholder, placeholder,
targetValue,
maximum, maximum,
dataSource, dataSource,
selectData, selectData,
onSearch,
onRadioChange,
onCheckboxChange, onCheckboxChange,
onCancelSelect, onCancelSelect,
treeProps, treeProps,
onTreeDrop,
}) => { }) => {
const { getPrefixCls } = useContext(ConfigProvider.ConfigContext); const { getPrefixCls } = useContext(ConfigProvider.ConfigContext);
const prefixCls = getPrefixCls('quota-select'); const prefixCls = getPrefixCls('quota-select');
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
const [targetValue, setTargetValue] = useState('emphasis');
const [allQuotaList, setAllQuotaList] = useState([]);
const [quotaList, setQuotaList] = useState([]);
useEffect(() => {
if (dataSource.length > 0) {
let data = dataSource.map((item) => ({
...item,
checked: false,
title: item.Name,
key: item.Name,
}));
setAllQuotaList(data);
}
}, [dataSource]);
useEffect(() => {
if (targetValue === 'emphasis') {
filterEmphasisQuota();
}
}, [allQuotaList]);
useEffect(() => {
let data = [...allQuotaList];
data.forEach((item) => {
item.checked = false;
if (selectData.length > 0) {
selectData.forEach((child) => {
if (child.key === item.key) {
item.checked = true;
}
});
}
});
setAllQuotaList(data);
}, [selectData]);
// 过滤重点指标
const filterEmphasisQuota = () => {
let newQuotaList = [...allQuotaList];
newQuotaList = newQuotaList.filter((item) => item.IsShow === '1');
setQuotaList(newQuotaList);
};
// 展示模态框 // 展示模态框
const showModal = () => { const showModal = () => {
...@@ -48,11 +90,134 @@ const QuotaSelect = ({ ...@@ -48,11 +90,134 @@ const QuotaSelect = ({
} }
}; };
const onOk = (e) => { const onOk = () => {
onModalOk && onModalOk(); onModalOk && onModalOk();
setVisible(false); setVisible(false);
}; };
// 切换重点与全部
const onRadioChange = (e) => {
if (e.target.value === 'all') {
setQuotaList(allQuotaList);
} else {
filterEmphasisQuota();
}
setTargetValue(e.target.value);
};
// 搜索指标
const onSearch = (e) => {
if (e.type === 'keydown' || e.target.value === '') {
if (e.target.value !== '') {
let newQuotaList = [];
quotaList.forEach((item) => {
if (item.Name.indexOf(e.target.value) > -1) newQuotaList.push(item);
});
setQuotaList(newQuotaList);
} else {
if (targetValue === 'all') {
setQuotaList(allQuotaList);
} else {
filterEmphasisQuota();
}
}
}
};
// 处理复选框点击事件
const handleCheckboxChange = (e) => {
let newQuotaList = [...allQuotaList];
let curSelectKey = [];
let curSelectList = [...selectData];
let data = curSelectList.filter((item) => item.title === e.target.value);
if (data.length) {
curSelectList = curSelectList.filter((item) => item.title !== e.target.value);
} else {
curSelectList.push({ key: e.target.value, title: e.target.value });
}
newQuotaList.forEach((item) => {
if (item.title === e.target.value) {
item.checked = !item.checked;
}
});
curSelectKey = curSelectList.map((item) => item.key);
onCheckboxChange({
selectKey: curSelectKey,
selectList: curSelectList,
});
setAllQuotaList(newQuotaList);
};
// 处理取消选择按钮点击事件
const handleCancelSelect = ({ title }) => {
let data = [...selectData];
data = data.filter((item) => item.title !== title);
onCancelSelect({
selectKey: data.map((item) => item.key),
selectList: data,
});
};
// 拖动选中树节点
const handleDrop = (info) => {
const dropKey = info.node.key;
const dragKey = info.dragNode.key;
const dropPos = info.node.pos.split('-');
const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1]);
const loop = (data, key, callback) => {
for (let i = 0; i < data.length; i++) {
if (data[i].key === key) {
return callback(data[i], i, data);
}
if (data[i].children) {
loop(data[i].children, key, callback);
}
}
};
const data = [...selectData];
let dragObj;
loop(data, dragKey, (item, index, arr) => {
arr.splice(index, 1);
dragObj = item;
});
if (!info.dropToGap) {
loop(data, dropKey, (item) => {
item.children = item.children || [];
item.children.unshift(dragObj);
});
} else if (
(info.node.props.children || []).length > 0 && // Has children
info.node.props.expanded && // Is expanded
dropPosition === 1 // On the bottom gap
) {
loop(data, dropKey, (item) => {
item.children = item.children || [];
item.children.unshift(dragObj);
});
} else {
let ar;
let i;
loop(data, dropKey, (item, index, arr) => {
ar = arr;
i = index;
});
if (dropPosition === -1) {
ar.splice(i, 0, dragObj);
} else {
ar.splice(i + 1, 0, dragObj);
}
}
onTreeDrop({
selectKey: data.map((item) => item.key),
selectList: data,
});
};
return ( return (
<div className={classNames(prefixCls)}> <div className={classNames(prefixCls)}>
<Button {...buttonProps} onClick={showModal} /> <Button {...buttonProps} onClick={showModal} />
...@@ -61,6 +226,7 @@ const QuotaSelect = ({ ...@@ -61,6 +226,7 @@ const QuotaSelect = ({
width={width} width={width}
title={title} title={title}
cancelText={cancelText} cancelText={cancelText}
okText={okText}
visible={visible} visible={visible}
onCancel={handleCancel} onCancel={handleCancel}
onOk={onOk} onOk={onOk}
...@@ -103,10 +269,10 @@ const QuotaSelect = ({ ...@@ -103,10 +269,10 @@ const QuotaSelect = ({
</div> </div>
</div> </div>
<div className={classNames(`${prefixCls}-modal-option-wrap`)}> <div className={classNames(`${prefixCls}-modal-option-wrap`)}>
{!dataSource.length && <Empty />} {!quotaList.length && <Empty />}
<Row gutter={[0, 6]}> <Row gutter={[0, 6]}>
{!!dataSource.length && {!!quotaList.length &&
dataSource.map((item) => ( quotaList.map((item) => (
<Col span={8} key={item.key}> <Col span={8} key={item.key}>
<Checkbox <Checkbox
value={item.title} value={item.title}
...@@ -115,7 +281,7 @@ const QuotaSelect = ({ ...@@ -115,7 +281,7 @@ const QuotaSelect = ({
(selectData.length > maximum || selectData.length === maximum) && (selectData.length > maximum || selectData.length === maximum) &&
!item.checked !item.checked
} }
onChange={onCheckboxChange} onChange={handleCheckboxChange}
> >
{item.title} {item.title}
</Checkbox> </Checkbox>
...@@ -129,14 +295,14 @@ const QuotaSelect = ({ ...@@ -129,14 +295,14 @@ const QuotaSelect = ({
已选:{selectData.length}/{maximum} 已选:{selectData.length}/{maximum}
</div> </div>
<div className={classNames(`${prefixCls}-modal-tree`)}> <div className={classNames(`${prefixCls}-modal-tree`)}>
<Tree {...treeProps}> <Tree draggable={true} onDrop={handleDrop} {...treeProps}>
{selectData.map((item) => ( {selectData.map((item) => (
<TreeNode <TreeNode
key={item.key} key={item.key}
title={ title={
<div className={classNames(`${prefixCls}-modal-tree-title`)}> <div className={classNames(`${prefixCls}-modal-tree-title`)}>
<div>{item.title}</div> <div>{item.title}</div>
<CloseOutlined onClick={() => onCancelSelect(item)} /> <CloseOutlined onClick={() => handleCancelSelect(item)} />
</div> </div>
} }
/> />
...@@ -155,9 +321,9 @@ QuotaSelect.defaultProps = { ...@@ -155,9 +321,9 @@ QuotaSelect.defaultProps = {
width: 900, width: 900,
title: '选择显示字段', title: '选择显示字段',
cancelText: '取消选择', cancelText: '取消选择',
okText: '确定',
placeholder: '搜索关键词', placeholder: '搜索关键词',
searchPrefix: <SearchOutlined />, searchPrefix: <SearchOutlined />,
targetValue: 'emphasis',
maximum: 0, maximum: 0,
dataSource: [], dataSource: [],
selectData: [], selectData: [],
...@@ -165,9 +331,8 @@ QuotaSelect.defaultProps = { ...@@ -165,9 +331,8 @@ QuotaSelect.defaultProps = {
onModalCancel: () => {}, onModalCancel: () => {},
onModalOk: () => {}, onModalOk: () => {},
onModalClose: () => {}, onModalClose: () => {},
onSearch: () => {},
onRadioChange: () => {},
onCancelSelect: () => {}, onCancelSelect: () => {},
onTreeDrop: () => {},
}; };
QuotaSelect.propTypes = { QuotaSelect.propTypes = {
...@@ -175,9 +340,9 @@ QuotaSelect.propTypes = { ...@@ -175,9 +340,9 @@ QuotaSelect.propTypes = {
width: PropTypes.number, width: PropTypes.number,
title: PropTypes.string, title: PropTypes.string,
cancelText: PropTypes.string, cancelText: PropTypes.string,
okText: PropTypes.string,
placeholder: PropTypes.string, placeholder: PropTypes.string,
searchPrefix: PropTypes.node, searchPrefix: PropTypes.node,
targetValue: PropTypes.string,
maximum: PropTypes.number, maximum: PropTypes.number,
dataSource: PropTypes.array, dataSource: PropTypes.array,
selectData: PropTypes.array, selectData: PropTypes.array,
...@@ -185,9 +350,8 @@ QuotaSelect.propTypes = { ...@@ -185,9 +350,8 @@ QuotaSelect.propTypes = {
onModalCancel: PropTypes.func, onModalCancel: PropTypes.func,
onModalOk: PropTypes.func, onModalOk: PropTypes.func,
onModalClose: PropTypes.func, onModalClose: PropTypes.func,
onSearch: PropTypes.func,
onRadioChange: PropTypes.func,
onCancelSelect: PropTypes.func, onCancelSelect: PropTypes.func,
onTreeDrop: PropTypes.func,
}; };
export default QuotaSelect; export default QuotaSelect;
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