From 5e467b7b2e14f668c5e4e63e053410c260d4c6d8 Mon Sep 17 00:00:00 2001 From: Teacatkk <307519856@qq.com> Date: Fri, 14 Jul 2023 18:44:36 +0800 Subject: [PATCH 1/3] feat: support custom color and footer Signed-off-by: Teacatkk <307519856@qq.com> --- package.json | 2 +- src/components/UsageBar/index.tsx | 314 ++++++++++++++++-------------- src/interface.tsx | 8 +- stories/UsageBar.stories.tsx | 23 ++- stories/docs/UsageBar.mdx | 2 + 5 files changed, 198 insertions(+), 151 deletions(-) diff --git a/package.json b/package.json index b0798654..3d7ac072 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wizard-ui", - "version": "1.0.1", + "version": "1.0.3-beta.0", "private": false, "main": "lib/index.js", "module": "esm/index.js", diff --git a/src/components/UsageBar/index.tsx b/src/components/UsageBar/index.tsx index 8d5be78f..9611031a 100644 --- a/src/components/UsageBar/index.tsx +++ b/src/components/UsageBar/index.tsx @@ -12,18 +12,32 @@ const PERCENT_WITH_STATUS = { danger: 0.85, }; -function calcPercent(p: number) { - let percent: number | string = 100 * p; - if (percent < 0.01 && percent > 0) { - percent = '0.01%'; - } else if (percent < 1) { - percent = `${percent.toFixed(3)}%`; - } else if (isNaN(percent)) { - percent = 'NO'; - } else { - percent = `${percent.toFixed(2)}%`; +const spacer = (unit: string) => (unit === '%' ? '' : ' '); + +function numericalConvert(num: string | number) { + if (typeof num !== 'number' || isNaN(num) || num === 0) return num; + let n; + switch (true) { + case num >= 1: + n = num.toFixed(2); + break; + case num < 0.001: + n = 0.001; + break; + case num < 1: + n = num.toFixed(3); + break; + default: + n = num; } - return percent; + return n; +} + +function calcPercent(p: number) { + if (isNaN(p)) return '--'; + const num = 100 * p; + const percent = numericalConvert(num); + return `${percent}%`; } const UsageBar: React.FC = props => { @@ -44,140 +58,150 @@ const UsageBar: React.FC = props => { extraFooterInfo, formatType, series, - withLenged, + withLegend, unavailableData, + handleCustomFooter, } = props; const hasNow = props.hasOwnProperty('now'); const hasPercent = props.hasOwnProperty('percent'); const hasSeries = props.hasOwnProperty('series'); let left; let right; - let usedStyle; + let usedStyle: string | undefined; let finalSeries: Array; - switch (true) { - case hasSeries: - const total = lodash.sumBy(series, 'value'); - finalSeries = lodash.map(series, ({ name, value, bsStyle }) => { - const perc = value / total; - let legend: any = perc; - switch (true) { - case isPercent: - legend = calcPercent(perc); - break; - case isByte: - legend = xbytes(value, {}); - break; - case isBulk: - legend = bulk(value, {}); - break; - default: - } - return { - name, - bsStyle, - perc, - legend, - value, - }; - }); - break; - default: - const now = hasNow ? props.now : props.percent && max && props.percent * max; - // 当展示右侧 max 为 0+单位时(showZeroMax为true), 如果 now 大于 max 时,percent 应为 100% - const defaultPercent = showZeroMax && Number(now) > Number(max) ? 1 : 0; - const percent = hasPercent - ? props.percent - : max - ? props.now && props.now / max - : defaultPercent; - const errorPercent = unavailableData && max && unavailableData / max; - let nowValue: number | string | undefined = now; - let maxValue: number | string | undefined = max; - let nowSuffix: any = ''; - let maxSuffix: any = ''; - // bar 左边为百分比形式, 右边默认设为百分形式 - if (isPercent || hasPercent) { - nowValue = percent && (percent * 100).toFixed(2); - maxValue = 100; - nowSuffix = maxSuffix = '%'; - } + const now = hasNow ? props.now : props.percent && max && props.percent * max; + // 当展示右侧 max 为 0+单位时(showZeroMax为true), 如果 now 大于 max 时,percent 应为 100% + const defaultPercent = showZeroMax && Number(now) > Number(max) ? 1 : 0; + const percent = hasPercent + ? props.percent + : max && !lodash.isUndefined(props.now) + ? props.now / max + : defaultPercent; + const errorPercent = unavailableData && max && unavailableData / max; + let nowValue: number | string | undefined = now; + let maxValue: number | string | undefined = max; + let nowSuffix: any = ''; + let maxSuffix: any = ''; + // bar 左边为百分比形式, 右边默认设为百分形式 + if (isPercent || hasPercent) { + nowValue = percent && (percent * 100).toFixed(2); + maxValue = 100; + nowSuffix = maxSuffix = '%'; + } - if (isByte || formatType) { - // hasPercent 表明左边数据设置完成(百分比形式),不需要再调整 - let byteOptions: object = { splitUnit: true }; - if (formatType) { - byteOptions = { splitUnit: true, formatType }; - } + if (isByte || formatType) { + // hasPercent 表明左边数据设置完成(百分比形式),不需要再调整 + let byteOptions: object = { splitUnit: true }; + if (formatType) { + byteOptions = { splitUnit: true, formatType }; + } - if (!hasPercent && now) { - const nowArr: any = xbytes(now, byteOptions); - nowValue = nowArr[0]; - nowSuffix = nowArr[1]; - } - const maxArr: any = max && xbytes(max, byteOptions); - maxValue = maxArr[0] === undefined ? 0 : maxArr[0]; - maxSuffix = maxArr[1] === undefined ? 'B' : 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] === undefined ? 0 : maxArr[0]; - maxSuffix = maxArr[1] === undefined ? '' : maxArr[1]; - } + if (!hasPercent && hasNow) { + const nowArr: any = xbytes(now || 0, byteOptions); + nowValue = nowArr[0]; + nowSuffix = nowArr[1]; + } + const maxArr: any = max && xbytes(max, byteOptions); + maxValue = maxArr[0] === undefined ? 0 : maxArr[0]; + maxSuffix = maxArr[1] === undefined ? 'B' : maxArr[1]; + } else if (isBulk) { + // hasPercent 表明左边数据设置完成(百分比形式),不需要再调整 + if (!hasPercent && hasNow) { + const nowArr = bulk(now || 0, { splitUnit: true }); + nowValue = nowArr[0]; + nowSuffix = nowArr[1]; + } + const maxArr: any = max && bulk(max, { splitUnit: true }); + maxValue = maxArr[0] === undefined ? 0 : maxArr[0]; + maxSuffix = maxArr[1] === undefined ? '' : maxArr[1]; + } - // max 为 0 时,设置为无限制 - // isPercent,hasPercent 涉及到百分比展示,此时 max 不应该为无限制 - // showZeroMax 直接展示 max 为处理后的 0 + 单位 - if (!max && !hasPercent && !isPercent && !showZeroMax) { - maxValue = lang().MAX_VALUE; - maxSuffix = ''; - } + // max 为 0 时,设置为无限制 + // isPercent,hasPercent 涉及到百分比展示,此时 max 不应该为无限制 + // showZeroMax 直接展示 max 为处理后的 0 + 单位 + if (!max && !hasPercent && !isPercent && !showZeroMax) { + maxValue = lang().MAX_VALUE; + maxSuffix = ''; + } - // 处理 bar 颜色 - if (percent && percent >= PERCENT_WITH_STATUS.danger) { - usedStyle = 'danger'; - } else if ( - percent && - percent < PERCENT_WITH_STATUS.danger && - percent > PERCENT_WITH_STATUS.warning && - !isExcludeWarning - ) { - usedStyle = 'warning'; - } + console.log('props.hasOwnProperty(bsStyle)', props.hasOwnProperty('bsStyle')); + + // 处理 bar 颜色 + if (props.hasOwnProperty('bsStyle')) { + usedStyle = props.bsStyle; + } else { + if (percent && percent >= PERCENT_WITH_STATUS.danger) { + usedStyle = 'danger'; + } else if ( + percent && + percent < PERCENT_WITH_STATUS.danger && + percent > PERCENT_WITH_STATUS.warning && + !isExcludeWarning + ) { + usedStyle = '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 = ''; + if (withPercent) { + // 左边百分比形式,右边展示数值 + left = percent ? calcPercent(percent) : '0%'; + // 右边只展示 max 数值 + if (hideNow) { + // 数值与单位之间需要空格 + right = maxValue + spacer(maxSuffix) + maxSuffix; + } else { + // 数值与单位之间需要空格 + right = `${nowValue + spacer(nowSuffix) + nowSuffix} / ${maxValue + + spacer(maxSuffix) + + maxSuffix}`; + } + } else { + left = nowValue + spacer(nowSuffix) + nowSuffix; + right = maxValue + spacer(maxSuffix) + maxSuffix; + } + //纯数字的进度条屏蔽右侧显示 + if (hideRight) { + right = ''; + } + + if (hasSeries) { + const total = lodash.sumBy(series, 'value'); + finalSeries = lodash.map(series, ({ name, value, bsStyle }) => { + const perc = value / total; + let legend: any = perc; + switch (true) { + case isPercent: + legend = calcPercent(perc); + break; + case isByte: + legend = xbytes(value, {}); + break; + case isBulk: + legend = bulk(value, {}); + break; + default: } - finalSeries = lodash.compact([ - { - bsStyle: usedStyle, - perc: percent, - value: now, - }, - withUnavailable && { - bsStyle: 'info', - perc: errorPercent, - value: unavailableData, - }, - ]); + return { + name, + bsStyle: bsStyle || usedStyle, + perc, + legend, + value, + }; + }); + } else { + finalSeries = lodash.compact([ + { + bsStyle: usedStyle, + perc: percent, + value: now, + }, + withUnavailable && { + bsStyle: 'info', + perc: errorPercent, + value: unavailableData, + }, + ]); } return ( @@ -199,16 +223,22 @@ const UsageBar: React.FC = props => { {waterLine && (
)} - {!isHideFooter && !hasSeries && ( -
-
- {left} - {extraFooterInfo && {extraFooterInfo}} + {!isHideFooter && + !withLegend && + (handleCustomFooter ? ( + handleCustomFooter(left, right) + ) : ( +
+
+ {left} + {extraFooterInfo && ( + {extraFooterInfo} + )} +
+
{right}
-
{right}
-
- )} - {hasSeries && withLenged && ( + ))} + {hasSeries && withLegend && ( {lodash.map(finalSeries, ({ name, legend, bsStyle, value }, index) => ( @@ -301,14 +331,14 @@ UsageBar.propTypes = { */ extraFooterInfo: PropTypes.string, /** - * 2段以上 processbar 的数据集,该模式下支持(isPercent,isByte,isBulk,inline,withLenged)等属性 + * 2段以上 processbar 的数据集,该模式下支持(isPercent,isByte,isBulk,inline,withLegend)等属性 * [{ name: 'pool1', value: 20, bsStyle: 'primary' }, { name: 'pool2', value: 40, bsStyle: 'success' }, { name: 'pool3', value: 20, bsStyle: 'error' }] **/ series: PropTypes.array, /** * series 模式下是否显示图例 **/ - withLenged: PropTypes.bool, + withLegend: PropTypes.bool, }; UsageBar.defaultProps = { max: 0, diff --git a/src/interface.tsx b/src/interface.tsx index de885a2a..57e26307 100644 --- a/src/interface.tsx +++ b/src/interface.tsx @@ -159,10 +159,14 @@ export interface UsageBarProps { extraFooterInfo?: string; /**格式化输出,可选[decimal|binary] */ formatType?: string; - /**2段以上 processbar 的数据集,该模式下支持(isPercent,isByte,isBulk,inline,withLenged)等属性 */ + /**指定 bar 颜色 */ + bsStyle?: string; + /**2段以上 processbar 的数据集,该模式下支持(isPercent,isByte,isBulk,inline,withLegend)等属性 */ series?: Array; /**series 模式下是否显示图例 */ - withLenged?: boolean; + withLegend?: boolean; + /** 自定义底部容量展示 */ + handleCustomFooter?: (left?: string | 0, right?: string) => JSX.Element | string; } export interface LoaderProps { diff --git a/stories/UsageBar.stories.tsx b/stories/UsageBar.stories.tsx index 0132fb38..0d1b20cb 100644 --- a/stories/UsageBar.stories.tsx +++ b/stories/UsageBar.stories.tsx @@ -116,13 +116,13 @@ export const Series: Story = { render: props => ( <>

SERIES 模式 isByte

- +

SERIES 模式,isByte,附带图例

- +

SERIES 模式,isBulk,附带图例

- +

SERIES 模式,isPercent,附带图例

- + ), }; @@ -136,11 +136,22 @@ export const ExtraInfo: Story = { <> -      +        -      +        ), }; + +export const CustomFooter: Story = { + render: props => { + const handleCustomFooter = (left?: string | 0, right?: string) => { + return
{`容量即将耗尽,请尽快扩容(已使用 ${left},${right})`}
; + }; + return ( + + ); + }, +}; diff --git a/stories/docs/UsageBar.mdx b/stories/docs/UsageBar.mdx index e76bacc7..a85aa3d4 100644 --- a/stories/docs/UsageBar.mdx +++ b/stories/docs/UsageBar.mdx @@ -31,6 +31,8 @@ import * as UsageBarStories from '../UsageBar.stories.tsx'; ### 附带额外信息 +### 自定义底部信息 + ## API \ No newline at end of file From c02d5db6062369ea4cb3d725fd53a42fc0df7f75 Mon Sep 17 00:00:00 2001 From: Teacatkk <307519856@qq.com> Date: Mon, 17 Jul 2023 14:26:11 +0800 Subject: [PATCH 2/3] update Signed-off-by: Teacatkk <307519856@qq.com> --- package.json | 2 +- src/components/UsageBar/index.tsx | 36 +++++++++++++------------------ stories/UsageBar.stories.tsx | 6 +++--- 3 files changed, 19 insertions(+), 25 deletions(-) diff --git a/package.json b/package.json index 3d7ac072..b0798654 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wizard-ui", - "version": "1.0.3-beta.0", + "version": "1.0.1", "private": false, "main": "lib/index.js", "module": "esm/index.js", diff --git a/src/components/UsageBar/index.tsx b/src/components/UsageBar/index.tsx index 9611031a..b7c3502b 100644 --- a/src/components/UsageBar/index.tsx +++ b/src/components/UsageBar/index.tsx @@ -12,6 +12,7 @@ const PERCENT_WITH_STATUS = { danger: 0.85, }; +// 数值与单位之间需要空格 const spacer = (unit: string) => (unit === '%' ? '' : ' '); function numericalConvert(num: string | number) { @@ -90,14 +91,13 @@ const UsageBar: React.FC = props => { } if (isByte || formatType) { - // hasPercent 表明左边数据设置完成(百分比形式),不需要再调整 let byteOptions: object = { splitUnit: true }; if (formatType) { byteOptions = { splitUnit: true, formatType }; } - - if (!hasPercent && hasNow) { - const nowArr: any = xbytes(now || 0, byteOptions); + // hasPercent 表明左边数据设置完成(百分比形式),不需要再调整 + if (!hasPercent && props.now) { + const nowArr: any = xbytes(props.now, byteOptions); nowValue = nowArr[0]; nowSuffix = nowArr[1]; } @@ -106,8 +106,8 @@ const UsageBar: React.FC = props => { maxSuffix = maxArr[1] === undefined ? 'B' : maxArr[1]; } else if (isBulk) { // hasPercent 表明左边数据设置完成(百分比形式),不需要再调整 - if (!hasPercent && hasNow) { - const nowArr = bulk(now || 0, { splitUnit: true }); + if (!hasPercent && props.now) { + const nowArr = bulk(props.now, { splitUnit: true }); nowValue = nowArr[0]; nowSuffix = nowArr[1]; } @@ -124,22 +124,18 @@ const UsageBar: React.FC = props => { maxSuffix = ''; } - console.log('props.hasOwnProperty(bsStyle)', props.hasOwnProperty('bsStyle')); - // 处理 bar 颜色 if (props.hasOwnProperty('bsStyle')) { usedStyle = props.bsStyle; - } else { - if (percent && percent >= PERCENT_WITH_STATUS.danger) { - usedStyle = 'danger'; - } else if ( - percent && - percent < PERCENT_WITH_STATUS.danger && - percent > PERCENT_WITH_STATUS.warning && - !isExcludeWarning - ) { - usedStyle = 'warning'; - } + } else if (percent && percent >= PERCENT_WITH_STATUS.danger) { + usedStyle = 'danger'; + } else if ( + percent && + percent < PERCENT_WITH_STATUS.danger && + percent > PERCENT_WITH_STATUS.warning && + !isExcludeWarning + ) { + usedStyle = 'warning'; } if (withPercent) { @@ -147,10 +143,8 @@ const UsageBar: React.FC = props => { left = percent ? calcPercent(percent) : '0%'; // 右边只展示 max 数值 if (hideNow) { - // 数值与单位之间需要空格 right = maxValue + spacer(maxSuffix) + maxSuffix; } else { - // 数值与单位之间需要空格 right = `${nowValue + spacer(nowSuffix) + nowSuffix} / ${maxValue + spacer(maxSuffix) + maxSuffix}`; diff --git a/stories/UsageBar.stories.tsx b/stories/UsageBar.stories.tsx index 0d1b20cb..433fbb35 100644 --- a/stories/UsageBar.stories.tsx +++ b/stories/UsageBar.stories.tsx @@ -118,11 +118,11 @@ export const Series: Story = {

SERIES 模式 isByte

SERIES 模式,isByte,附带图例

- +

SERIES 模式,isBulk,附带图例

- +

SERIES 模式,isPercent,附带图例

- + ), }; From 81a4a1e2bdb295973d47466bd8656f2b163d5bd9 Mon Sep 17 00:00:00 2001 From: Teacatkk <307519856@qq.com> Date: Mon, 17 Jul 2023 18:02:17 +0800 Subject: [PATCH 3/3] fix: percent Signed-off-by: Teacatkk <307519856@qq.com> --- src/components/UsageBar/index.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/components/UsageBar/index.tsx b/src/components/UsageBar/index.tsx index b7c3502b..36276c0e 100644 --- a/src/components/UsageBar/index.tsx +++ b/src/components/UsageBar/index.tsx @@ -73,11 +73,7 @@ const UsageBar: React.FC = props => { const now = hasNow ? props.now : props.percent && max && props.percent * max; // 当展示右侧 max 为 0+单位时(showZeroMax为true), 如果 now 大于 max 时,percent 应为 100% const defaultPercent = showZeroMax && Number(now) > Number(max) ? 1 : 0; - const percent = hasPercent - ? props.percent - : max && !lodash.isUndefined(props.now) - ? props.now / max - : defaultPercent; + const percent = hasPercent ? props.percent : max ? props.now && props.now / max : defaultPercent; const errorPercent = unavailableData && max && unavailableData / max; let nowValue: number | string | undefined = now; let maxValue: number | string | undefined = max;