Skip to content
This repository has been archived by the owner on Nov 14, 2023. It is now read-only.

Commit

Permalink
feat: UsageBar docs
Browse files Browse the repository at this point in the history
  • Loading branch information
wangkailang committed Jun 10, 2019
1 parent 73a3ad2 commit 2552692
Show file tree
Hide file tree
Showing 11 changed files with 539 additions and 17 deletions.
67 changes: 67 additions & 0 deletions docs/content/components/usage-bar.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
---
title: UsageBar 使用量
date: 2019-06-06
---

通过当前值、最大值等参数展现某一指标的使用量,比如硬盘、存储池的容量使用,license配额的使用等。

## 使用场景
- 展示资源占整体百分比
- 某个资源的使用、消耗情况

### 百分比格式展示
```jsx
<div>
<UsageBar percent="0.16" />
</div>
```
### 字节
```
<div>
<UsageBar now={900000} max={7000000} isByte />
<UsageBar percent={900000/7000000} max={7000000} isByte />
<UsageBar now={900000} max={7000000} isByte withPercent />
<UsageBar now={900000} max={7000000} isByte withPercent hideNow/>
</div>
```

### 个数
```
<div>
<UsageBar now={900000} max={7000000} isBulk />
<UsageBar percent={900000/7000000} max={7000000} isBulk />
{false && <UsageBar now={900000} max={7000000} isBulk withPercent hideNow />}
<UsageBar now={900000} max={7000000} isBulk withPercent />
</div>
```

### 行内应用
设置行内元素时,默认width为120px

```
<div className="flex-between">
<UsageBar now={900000} max={7000000} isPercent inline />
<UsageBar now={900000} max={7000000} isByte inline />
<UsageBar now={900000} max={7000000} isBulk inline />
</div>
```

### 状态
告警:大于 max 的 75%,小于 max 的 85%
```
<UsageBar now={76} max={100} />
```
危险:大于 max 的 85%
```
<UsageBar now={90} max={100} />
```
### 极限值处理
```
<div>
<UsageBar now={0} isByte />
<UsageBar now={0} isBulk />
<UsageBar percent={0} isByte />
<UsageBar percent={0} isBulk />
<UsageBar percent={0} />
</div>
```
20 changes: 20 additions & 0 deletions src/interface.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import * as React from 'react';

export interface BadgeProps {
count?: number | string
showZero?: boolean
Expand All @@ -12,6 +14,8 @@ export interface BadgeProps {
export interface IconProps {
type: string
className?: string
onClick?: React.MouseEventHandler
style?: object
}

export interface TooltipProps {
Expand All @@ -24,4 +28,20 @@ export interface TooltipProps {
style?: string
placement?: string
children: React.ReactNode
}

export interface UsageBarProps {
max?: number
now?: number
percent?: number
unavailableData?: number
isByte?: boolean
isPercent?: boolean
isBulk?: boolean
withPercent?: boolean
inline?: boolean
hideNow?: boolean
hideRight?: boolean
showZeroMax?: boolean
withUnavailable?: boolean
}
4 changes: 2 additions & 2 deletions src/lib/Badge/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import * as PropTypes from 'prop-types';
import { BadgeProps } from '../../interface';
import './style.scss';

const Badge: React.FC<BadgeProps> = props => {
const Badge: React.SFC<BadgeProps> = props => {
const { count, overflowCount, dot, size, showZero, status, text, title, children } = props;
const statusCls = `Badge--${status}`;
const parentCls = children ? 'Badge Badge__wrapper' : 'Badge';
if (count || showZero ) {
if (count || showZero) {
return (
<span className={parentCls}>
{children}
Expand Down
6 changes: 3 additions & 3 deletions src/lib/Icon/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import * as React from 'react';
import * as PropTypes from 'prop-types';
import { IconProps } from '../../interface';

const Icon: React.FC<IconProps> = props => {
const { type, className } = props;
const Icon: React.SFC<IconProps> = props => {
const { type, className, ...rest } = props;
const cls = `${className} icon icon-${type}`;
return <span className={cls}/>;
return <span className={cls} {...rest}/>;
}

Icon.propTypes = {
Expand Down
25 changes: 13 additions & 12 deletions src/lib/Tooltip/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as PropTypes from 'prop-types';
import cn from 'classnames';
import { Overlay, Tooltip as BaseTooltip } from 'react-bootstrap';
import { TooltipProps } from '../../interface';
import Icon from '../Icon';
import './style.scss';

const Tooltip: React.FC<TooltipProps> = props => {
Expand All @@ -19,11 +20,12 @@ const Tooltip: React.FC<TooltipProps> = props => {
...extra
} = props;

const wrapper = React.useRef(null);
const wrapper = React.useRef<HTMLInputElement>(null);
const [ placement, setPlacement ] = React.useState('top');
// 类似 componentDidMount。只会在 render 后执行一次
React.useEffect(() => {
const elem: any = wrapper.current;
const elem = wrapper.current;
if (!elem) return;
let placement = 'top';
const docElem = document.documentElement;
const box = elem.getBoundingClientRect();
Expand All @@ -49,16 +51,15 @@ const Tooltip: React.FC<TooltipProps> = props => {
const placeholder = label ? (
label
) : icon ? (
<span
className={`Tooltip__icon icon icon-${icon} ${iconClass}`}
onClick={onClick}
style={{
verticalAlign: iconAlign,
}}
/>
) : (
undefined
);
<Icon
type={icon}
className={`Tooltip__icon ${iconClass}`}
onClick={onClick}
style={{
verticalAlign: iconAlign,
}}
/>
) : undefined;
return (
<div
ref={wrapper}
Expand Down
196 changes: 196 additions & 0 deletions src/lib/UsageBar/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
import * as React from 'react';
import * as PropTypes from 'prop-types';
import { ProgressBar } from 'react-bootstrap';
import { bulk, xbytes } from '../../utils';
import { UsageBarProps } from '../../interface';
import './style.scss';

const PERCENT_WITH_STATUS = {
warning: 0.75,
danger: 0.85,
};

function calcPercent(p: number) {
let percent: number | string = 100 * p;
if (percent < 0.0001 && percent > 0) {
percent = '0.01%';
} else if (percent < 1) {
percent = `${percent.toFixed(3)}%`;
} else if (isNaN(percent)) {
percent = 'NO';
} else {
percent = `${percent.toFixed(2)}%`;
}
return percent;
}

const UsageBar: React.SFC<UsageBarProps> = props => {
const {
max,
isByte,
isPercent,
isBulk,
withPercent,
inline,
hideNow,
hideRight,
showZeroMax,
withUnavailable,
} = props;
const hasNow = props.hasOwnProperty('now');
const hasPercent = props.hasOwnProperty('percent');
const now = hasNow ? props.now : props.percent && max && props.percent * max;
const percent = hasPercent ? props.percent : max ? props.now && props.now / max : 0;
const errorPercent = props.unavailableData && max && props.unavailableData / max;
let nowValue: number | string | undefined = now;
let maxValue: number | string | undefined = max;
let nowSuffix = '';
let maxSuffix = '';
let left;
let right;
let bsStyle;

// bar 左边为百分比形式, 右边默认设为百分形式
if (isPercent || hasPercent) {
nowValue = percent && (percent * 100).toFixed(2);
maxValue = 100;
nowSuffix = maxSuffix = '%';
}

if (isByte) {
// hasPercent 表明左边数据设置完成(百分比形式),不需要再调整
if (!hasPercent && now) {
const nowArr: any = xbytes(now, { splitUnit: true });
nowValue = nowArr[0];
nowSuffix = nowArr[1];
}
const maxArr: any = max && xbytes(max, { splitUnit: true });
maxValue = maxArr[0];
maxSuffix = maxArr[1];
} else if (isBulk) {
// hasPercent 表明左边数据设置完成(百分比形式),不需要再调整
if (!hasPercent && now) {
const nowArr = bulk(now, { splitUnit: true });
nowValue = nowArr[0];
nowSuffix = nowArr[1];
}
const maxArr: any = max && bulk(max, { splitUnit: true });
maxValue = maxArr[0];
maxSuffix = maxArr[1];
}

// max 为 0 时,设置为无限制
// isPercent,hasPercent 涉及到百分比展示,此时 max 不应该为无限制
// showZeroMax 直接展示 max 为处理后的 0 + 单位
if (!max && !hasPercent && !isPercent && !showZeroMax) {
maxValue = 'no limit';
maxSuffix = '';
}

// 处理 bar 颜色
if (percent && percent > PERCENT_WITH_STATUS.danger) {
bsStyle = 'danger';
} else if (percent && percent < PERCENT_WITH_STATUS.danger && percent > PERCENT_WITH_STATUS.warning) {
bsStyle = 'warning';
}

if (withPercent) {
// 左边百分比形式,右边展示数值
left = percent && calcPercent(percent);
// 右边只展示 max 数值
if (hideNow) {
right = maxValue + maxSuffix;
} else {
right = `${nowValue + nowSuffix}/${maxValue + maxSuffix}`;
}
} else {
left = nowValue + nowSuffix;
right = maxValue + maxSuffix;
}
//纯数字的进度条屏蔽右侧显示
if (hideRight) {
right = ''
}

return (
<div className={`UsageBar ${inline ? 'inline' : ''}`}>
{
withUnavailable ?
<ProgressBar>
<ProgressBar bsStyle={bsStyle} now={percent} max={1} key={1} />
<ProgressBar bsStyle='info' now={errorPercent} max={1} key={2} />
</ProgressBar>
: <ProgressBar bsStyle={bsStyle} now={percent} max={1} />
}
<div className="UsageBar__footer">
<div className="UsageBar__footer--left">{left}</div>
<div className="UsageBar__footer--right">{right}</div>
</div>
</div>
);
}

UsageBar.propTypes = {
/**
* 当前量
**/
now: PropTypes.number,
/**
* 最大量
**/
max: PropTypes.number,
/**
* 百分比
**/
percent: PropTypes.number,
/**
* 数字以百分比为单位展示
**/
isPercent: PropTypes.bool,
/**
* 数字以字节(B, KB, MB, GB...)为单位展示
**/
isByte: PropTypes.bool,
/**
* 数字以数量(万, 亿, 兆, 京...)为单位展示
**/
isBulk: PropTypes.bool,
/**
* 设置组件行内展示,width 为 120px
**/
inline: PropTypes.bool,
/**
* 当 max 为 0 时,展示为 0+单位 或者无限制
**/
showZeroMax: PropTypes.bool,
/**
* 是否隐藏 now 的展示
**/
hideNow: PropTypes.bool,
/**
* 是否隐藏 right 的展示
**/
hideRight: PropTypes.bool,
/**
* 左边数值百分比展示
**/
withPercent: PropTypes.bool,
/**
* 2段以上数据的processbar
* https://react-bootstrap.netlify.com/components/progress/#progress-bar-props
* <ProgressBar>
* <ProgressBar striped variant="success" now={35} key={1} />
* <ProgressBar variant="warning" now={20} key={2} />
* </ProgressBar>;
*/
withUnavailable: PropTypes.bool,
/**
* 不可用数据量
**/
unavailableData: PropTypes.number,
};
UsageBar.defaultProps = {
max: 0,
};

export default UsageBar;
Loading

0 comments on commit 2552692

Please sign in to comment.