Jingwei.Zhang c6f92259b2 feat: support custom option col
support custom label and content col for detail card in base detail tab

Change-Id: I4a1d92451ee8adc872e754cf270d2a96f3598570
2023-08-07 14:31:45 +08:00

181 lines
4.9 KiB
JavaScript

// Copyright 2021 99cloud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import React from 'react';
import { Row, Col, Skeleton, Tooltip, Typography, Popover } from 'antd';
import { InfoCircleOutlined } from '@ant-design/icons';
import { has, get, isNumber } from 'lodash';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { renderFilterMap } from 'utils/index';
import { getValueMapRender, getUnitRender } from 'utils/table';
import Status from 'components/Status';
import styles from './index.less';
const { Paragraph } = Typography;
const getContentValue = (value, dataIndex, data, copyable) => {
const status = get(data, dataIndex);
// get status
if (
dataIndex.toLowerCase().indexOf('status') >= 0 ||
dataIndex.toLowerCase().indexOf('state') >= 0
) {
return <Status status={status} text={value} />;
}
// get copyable
if (value !== '-') {
if (
(/_?id/g.test(dataIndex.toLowerCase()) && copyable !== false) ||
copyable
) {
return <Paragraph copyable={copyable}>{value}</Paragraph>;
}
}
return value || '-';
};
const getContent = (data, option) => {
const { content, dataIndex, render, valueRender, copyable, valueMap, unit } =
option;
if (has(option, 'content')) {
return copyable ? (
<Paragraph copyable={copyable}>{content}</Paragraph>
) : (
content
);
}
let value = get(data, dataIndex);
if (!render) {
if (valueRender) {
const renderFunc = renderFilterMap[valueRender];
value = renderFunc && renderFunc(value);
} else if (valueMap) {
value = getValueMapRender(option)(value);
} else if (unit) {
value = getUnitRender(option)(value);
}
} else {
value = render(value, data);
}
if (!isNumber(value)) {
value = value || '-';
}
return getContentValue(value, dataIndex, data, copyable);
};
const renderLabel = (option) => {
const { label, tooltip = '' } = option;
if (!tooltip) {
return label;
}
return (
<Tooltip title={tooltip}>
<span>{label}</span>
</Tooltip>
);
};
const renderOptions = (options, data, loading, labelCol, contentCol) =>
options
.filter((option) => !option.hidden)
.map((option, index) => {
const currentLabelCol = has(option, 'labelCol')
? option.labelCol
: labelCol;
const currentContentCol = has(option, 'contentCol')
? option.contentCol
: contentCol;
return (
<Skeleton loading={loading} key={`detail-row-${index}`}>
<Row className={classnames(styles['card-item'], 'sl-card-item')}>
<Col span={currentLabelCol}>{renderLabel(option)}</Col>
<Col span={currentContentCol}>{getContent(data, option)}</Col>
</Row>
</Skeleton>
);
});
const DetailCard = ({
title,
titleHelp,
loading,
options,
data,
labelCol,
contentCol,
className,
button,
}) => {
let titleHelpValue;
if (titleHelp) {
titleHelpValue = (
<Popover
arrowPointAtCenter="true"
placement="rightTop"
content={titleHelp}
getPopupContainer={(node) => node.parentNode}
>
<InfoCircleOutlined className={styles['title-help']} />
</Popover>
);
}
return (
<div className={classnames(styles.card, className)}>
<div className={styles['card-content']}>
<Skeleton loading={loading}>
<Row className={classnames(styles['card-item'], 'sl-card-item')}>
<h3> {title} </h3>
{titleHelpValue}
{button}
</Row>
</Skeleton>
{renderOptions(options, data, loading, labelCol, contentCol)}
</div>
</div>
);
};
const detailProps = PropTypes.shape({
label: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
content: PropTypes.any,
tooltip: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
dataIndex: PropTypes.string,
valueRender: PropTypes.string,
labelCol: PropTypes.number,
contentCol: PropTypes.number,
});
DetailCard.defaultProps = {
labelCol: 8,
contentCol: 16,
options: [],
title: '',
titleHelp: '',
loading: false,
data: {},
};
DetailCard.propTypes = {
title: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
titleHelp: PropTypes.any,
options: PropTypes.arrayOf(detailProps),
loading: PropTypes.bool,
data: PropTypes.object,
labelCol: PropTypes.number,
contentCol: PropTypes.number,
};
export default DetailCard;