commit
15c645fea1
|
@ -95,6 +95,8 @@ import { default as Slider } from './slider';
|
|||
|
||||
import { default as Spin } from './spin';
|
||||
|
||||
import { default as Statistic } from './statistic';
|
||||
|
||||
import { default as Steps } from './steps';
|
||||
|
||||
import { default as Switch } from './switch';
|
||||
|
@ -172,6 +174,7 @@ const components = [
|
|||
Select,
|
||||
Slider,
|
||||
Spin,
|
||||
Statistic,
|
||||
Steps,
|
||||
Switch,
|
||||
Table,
|
||||
|
@ -254,6 +257,7 @@ export {
|
|||
Select,
|
||||
Slider,
|
||||
Spin,
|
||||
Statistic,
|
||||
Steps,
|
||||
Switch,
|
||||
Table,
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
import * as moment from 'moment';
|
||||
import interopDefault from '../_util/interopDefault';
|
||||
import { cloneElement } from '../_util/vnode';
|
||||
import { initDefaultProps } from '../_util/props-util';
|
||||
import Statistic, { StatisticProps } from './Statistic';
|
||||
import { formatCountdown } from './utils';
|
||||
|
||||
const REFRESH_INTERVAL = 1000 / 30;
|
||||
|
||||
function getTime(value) {
|
||||
return interopDefault(moment)(value).valueOf();
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'AStatisticCountdown',
|
||||
props: initDefaultProps(StatisticProps, {
|
||||
format: 'HH:mm:ss',
|
||||
}),
|
||||
|
||||
data() {
|
||||
return {
|
||||
uniKey: 0,
|
||||
};
|
||||
},
|
||||
|
||||
countdownId: undefined,
|
||||
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
this.syncTimer();
|
||||
});
|
||||
},
|
||||
|
||||
updated() {
|
||||
this.$nextTick(() => {
|
||||
this.syncTimer();
|
||||
});
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
this.stopTimer();
|
||||
},
|
||||
|
||||
methods: {
|
||||
syncTimer() {
|
||||
const { value } = this.$props;
|
||||
const timestamp = getTime(value);
|
||||
if (timestamp >= Date.now()) {
|
||||
this.startTimer();
|
||||
} else {
|
||||
this.stopTimer();
|
||||
}
|
||||
},
|
||||
|
||||
startTimer() {
|
||||
if (this.countdownId) {
|
||||
return;
|
||||
}
|
||||
this.countdownId = window.setInterval(() => {
|
||||
this.uniKey++;
|
||||
}, REFRESH_INTERVAL);
|
||||
},
|
||||
|
||||
stopTimer() {
|
||||
const { value } = this.$props;
|
||||
if (this.countdownId) {
|
||||
clearInterval(this.countdownId);
|
||||
this.countdownId = undefined;
|
||||
|
||||
const timestamp = getTime(value);
|
||||
if (timestamp < Date.now()) {
|
||||
this.$emit('finish');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
formatCountdown(value, config) {
|
||||
const { format } = this.$props;
|
||||
return formatCountdown(value, { ...config, format });
|
||||
},
|
||||
|
||||
// Countdown do not need display the timestamp
|
||||
valueRenderHtml: node =>
|
||||
cloneElement(node, {
|
||||
props: {
|
||||
title: undefined,
|
||||
},
|
||||
}),
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Statistic
|
||||
key={this.uniKey}
|
||||
{...{
|
||||
props: {
|
||||
...this.$props,
|
||||
valueRender: this.valueRenderHtml,
|
||||
formatter: this.formatCountdown,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
},
|
||||
};
|
|
@ -0,0 +1,58 @@
|
|||
import padEnd from 'lodash/padEnd';
|
||||
|
||||
export default {
|
||||
name: 'AStatisticNumber',
|
||||
functional: true,
|
||||
render(h, context) {
|
||||
const {
|
||||
value,
|
||||
formatter,
|
||||
precision,
|
||||
decimalSeparator,
|
||||
groupSeparator = '',
|
||||
prefixCls,
|
||||
} = context.props;
|
||||
|
||||
let valueNode;
|
||||
|
||||
if (typeof formatter === 'function') {
|
||||
// Customize formatter
|
||||
valueNode = formatter(value);
|
||||
} else {
|
||||
// Internal formatter
|
||||
const val = String(value);
|
||||
const cells = val.match(/^(-?)(\d*)(\.(\d+))?$/);
|
||||
// Process if illegal number
|
||||
if (!cells) {
|
||||
valueNode = val;
|
||||
} else {
|
||||
const negative = cells[1];
|
||||
let int = cells[2] || '0';
|
||||
let decimal = cells[4] || '';
|
||||
|
||||
int = int.replace(/\B(?=(\d{3})+(?!\d))/g, groupSeparator);
|
||||
if (typeof precision === 'number') {
|
||||
decimal = padEnd(decimal, precision, '0').slice(0, precision);
|
||||
}
|
||||
|
||||
if (decimal) {
|
||||
decimal = `${decimalSeparator}${decimal}`;
|
||||
}
|
||||
|
||||
valueNode = [
|
||||
<span key="int" class={`${prefixCls}-content-value-int`}>
|
||||
{negative}
|
||||
{int}
|
||||
</span>,
|
||||
decimal && (
|
||||
<span key="decimal" class={`${prefixCls}-content-value-decimal`}>
|
||||
{decimal}
|
||||
</span>
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return <span class={`${prefixCls}-content-value`}>{valueNode}</span>;
|
||||
},
|
||||
};
|
|
@ -0,0 +1,64 @@
|
|||
import PropTypes from '../_util/vue-types';
|
||||
import { getComponentFromProp, initDefaultProps } from '../_util/props-util';
|
||||
import { ConfigConsumerProps } from '../config-provider';
|
||||
import StatisticNumber from './Number';
|
||||
|
||||
export const StatisticProps = {
|
||||
prefixCls: PropTypes.string,
|
||||
decimalSeparator: PropTypes.string,
|
||||
groupSeparator: PropTypes.string,
|
||||
format: PropTypes.string,
|
||||
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
valueStyle: PropTypes.any,
|
||||
valueRender: PropTypes.any,
|
||||
formatter: PropTypes.any,
|
||||
precision: PropTypes.number,
|
||||
prefix: PropTypes.any,
|
||||
suffix: PropTypes.any,
|
||||
title: PropTypes.any,
|
||||
};
|
||||
|
||||
export default {
|
||||
name: 'AStatistic',
|
||||
props: initDefaultProps(StatisticProps, {
|
||||
prefixCls: 'ant-statistic',
|
||||
decimalSeparator: '.',
|
||||
groupSeparator: ',',
|
||||
}),
|
||||
inject: {
|
||||
configProvider: { default: () => ({}) },
|
||||
},
|
||||
|
||||
render() {
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
value = 0,
|
||||
valueStyle,
|
||||
valueRender,
|
||||
} = this.$props;
|
||||
const getPrefixCls = this.configProvider.getPrefixCls || ConfigConsumerProps.getPrefixCls;
|
||||
const prefixCls = getPrefixCls('statistic', customizePrefixCls);
|
||||
|
||||
const title = getComponentFromProp(this, 'title');
|
||||
let prefix = getComponentFromProp(this, 'prefix');
|
||||
let suffix = getComponentFromProp(this, 'suffix');
|
||||
const formatter = getComponentFromProp(this, 'formatter');
|
||||
let valueNode = (
|
||||
<StatisticNumber {...{ props: this.$props }} value={value} formatter={formatter} />
|
||||
);
|
||||
if (valueRender) {
|
||||
valueNode = valueRender(valueNode);
|
||||
}
|
||||
|
||||
return (
|
||||
<div class={prefixCls}>
|
||||
{title && <div class={`${prefixCls}-title`}>{title}</div>}
|
||||
<div style={valueStyle} class={`${prefixCls}-content`}>
|
||||
{prefix && <span class={`${prefixCls}-content-prefix`}>{prefix}</span>}
|
||||
{valueNode}
|
||||
{suffix && <span class={`${prefixCls}-content-suffix`}>{suffix}</span>}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
};
|
|
@ -0,0 +1,57 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders ./components/statistic/demo/basic.md correctly 1`] = `
|
||||
<div>
|
||||
<div class="ant-statistic" style="margin-right: 50px;">
|
||||
<div class="ant-statistic-title">Active Users</div>
|
||||
<div class="ant-statistic-content"><span class="ant-statistic-content-value"><span class="ant-statistic-content-value-int">112,893</span></span></div>
|
||||
</div>
|
||||
<div class="ant-statistic">
|
||||
<div class="ant-statistic-title">Account Balance (CNY)</div>
|
||||
<div class="ant-statistic-content"><span class="ant-statistic-content-value"><span class="ant-statistic-content-value-int">112,893</span><span class="ant-statistic-content-value-decimal">.00</span></span></div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/statistic/demo/card.md correctly 1`] = `
|
||||
<div>
|
||||
<div class="ant-card ant-card-bordered" style="padding: 30px;">
|
||||
<div class="ant-card-body">
|
||||
<div class="ant-statistic" style="margin-right: 50px;">
|
||||
<div class="ant-statistic-title">Feedback</div>
|
||||
<div class="ant-statistic-content"><span class="ant-statistic-content-prefix"><i slot="prefix" aria-label="icon: like" class="anticon anticon-like"><svg viewBox="64 64 896 896" data-icon="like" width="1em" height="1em" fill="currentColor" aria-hidden="true" class=""><path d="M885.9 533.7c16.8-22.2 26.1-49.4 26.1-77.7 0-44.9-25.1-87.4-65.5-111.1a67.67 67.67 0 0 0-34.3-9.3H572.4l6-122.9c1.4-29.7-9.1-57.9-29.5-79.4A106.62 106.62 0 0 0 471 99.9c-52 0-98 35-111.8 85.1l-85.9 311H144c-17.7 0-32 14.3-32 32v364c0 17.7 14.3 32 32 32h601.3c9.2 0 18.2-1.8 26.5-5.4 47.6-20.3 78.3-66.8 78.3-118.4 0-12.6-1.8-25-5.4-37 16.8-22.2 26.1-49.4 26.1-77.7 0-12.6-1.8-25-5.4-37 16.8-22.2 26.1-49.4 26.1-77.7-.2-12.6-2-25.1-5.6-37.1zM184 852V568h81v284h-81zm636.4-353l-21.9 19 13.9 25.4a56.2 56.2 0 0 1 6.9 27.3c0 16.5-7.2 32.2-19.6 43l-21.9 19 13.9 25.4a56.2 56.2 0 0 1 6.9 27.3c0 16.5-7.2 32.2-19.6 43l-21.9 19 13.9 25.4a56.2 56.2 0 0 1 6.9 27.3c0 22.4-13.2 42.6-33.6 51.8H329V564.8l99.5-360.5a44.1 44.1 0 0 1 42.2-32.3c7.6 0 15.1 2.2 21.1 6.7 9.9 7.4 15.2 18.6 14.6 30.5l-9.6 198.4h314.4C829 418.5 840 436.9 840 456c0 16.5-7.2 32.1-19.6 43z"></path></svg></i></span><span class="ant-statistic-content-value"><span class="ant-statistic-content-value-int">1,128</span></span></div>
|
||||
</div>
|
||||
<div class="ant-statistic" valueclass="demo-class">
|
||||
<div class="ant-statistic-title">Unmerged</div>
|
||||
<div class="ant-statistic-content"><span class="ant-statistic-content-value"><span class="ant-statistic-content-value-int">1,234,567,890</span></span><span class="ant-statistic-content-suffix"><span> / 100</span></span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/statistic/demo/countdown.md correctly 1`] = `
|
||||
<div>
|
||||
<div class="ant-statistic" style="margin-right: 50px;">
|
||||
<div class="ant-statistic-title">Countdown</div>
|
||||
<div class="ant-statistic-content"><span class="ant-statistic-content-value">48:00:30</span></div>
|
||||
</div>
|
||||
<div class="ant-statistic">
|
||||
<div class="ant-statistic-title">Million Seconds</div>
|
||||
<div class="ant-statistic-content"><span class="ant-statistic-content-value">48:00:30:000</span></div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/statistic/demo/unit.md correctly 1`] = `
|
||||
<div>
|
||||
<div class="ant-statistic" style="margin-right: 50px;">
|
||||
<div class="ant-statistic-title">Feedback</div>
|
||||
<div class="ant-statistic-content" style="color: rgb(63, 134, 0);"><span class="ant-statistic-content-prefix"><i slot="prefix" aria-label="icon: arrow-up" class="anticon anticon-arrow-up"><svg viewBox="64 64 896 896" data-icon="arrow-up" width="1em" height="1em" fill="currentColor" aria-hidden="true" class=""><path d="M868 545.5L536.1 163a31.96 31.96 0 0 0-48.3 0L156 545.5a7.97 7.97 0 0 0 6 13.2h81c4.6 0 9-2 12.1-5.5L474 300.9V864c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V300.9l218.9 252.3c3 3.5 7.4 5.5 12.1 5.5h81c6.8 0 10.5-8 6-13.2z"></path></svg></i></span><span class="ant-statistic-content-value"><span class="ant-statistic-content-value-int">11</span><span class="ant-statistic-content-value-decimal">.28</span></span><span class="ant-statistic-content-suffix">%</span></div>
|
||||
</div>
|
||||
<div class="ant-statistic" valueclass="demo-class">
|
||||
<div class="ant-statistic-title">Unmerged</div>
|
||||
<div class="ant-statistic-content"><span class="ant-statistic-content-value"><span class="ant-statistic-content-value-int">78</span></span><span class="ant-statistic-content-suffix"><span> / 100</span></span></div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
|
@ -0,0 +1,3 @@
|
|||
import demoTest from '../../../tests/shared/demoTest';
|
||||
|
||||
demoTest('statistic');
|
|
@ -0,0 +1,18 @@
|
|||
<cn>
|
||||
#### 基本
|
||||
简单展示
|
||||
</cn>
|
||||
|
||||
<us>
|
||||
#### Basic
|
||||
Simplest Usage.
|
||||
</us>
|
||||
|
||||
```html
|
||||
<template>
|
||||
<div>
|
||||
<a-statistic title="Active Users" :value="112893" style="margin-right: 50px" />
|
||||
<a-statistic title="Account Balance (CNY)" :precision="2" :value="112893" />
|
||||
</div>
|
||||
</template>
|
||||
```
|
|
@ -0,0 +1,32 @@
|
|||
<cn>
|
||||
#### 在卡片中使用
|
||||
在卡片中展示统计数值。
|
||||
</cn>
|
||||
|
||||
<us>
|
||||
#### In Card
|
||||
Display statistic data in Card.
|
||||
</us>
|
||||
|
||||
```html
|
||||
<template>
|
||||
<div>
|
||||
<a-card style="padding: 30px">
|
||||
<a-statistic
|
||||
title="Feedback"
|
||||
:value="1128"
|
||||
style="margin-right: 50px"
|
||||
>
|
||||
<a-icon slot="prefix" type="like" />
|
||||
</a-statistic>
|
||||
<a-statistic
|
||||
title="Unmerged"
|
||||
:value="1234567890"
|
||||
valueClass="demo-class"
|
||||
>
|
||||
<span slot="suffix"> / 100</span>
|
||||
</a-statistic>
|
||||
</a-card>
|
||||
</div>
|
||||
</template>
|
||||
```
|
|
@ -0,0 +1,41 @@
|
|||
<cn>
|
||||
#### 倒计时
|
||||
倒计时组件。
|
||||
</cn>
|
||||
|
||||
<us>
|
||||
#### Countdown
|
||||
Countdown component.
|
||||
</us>
|
||||
|
||||
```html
|
||||
<template>
|
||||
<div>
|
||||
<a-statistic-countdown
|
||||
title="Countdown"
|
||||
:value="deadline"
|
||||
@finish="onFinish"
|
||||
style="margin-right: 50px"
|
||||
/>
|
||||
<a-statistic-countdown
|
||||
title="Million Seconds"
|
||||
:value="deadline"
|
||||
format="HH:mm:ss:SSS"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
deadline: Date.now() + 1000 * 60 * 60 * 24 * 2 + 1000 * 30,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onFinish() {
|
||||
console.log('over');
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
```
|
|
@ -0,0 +1,50 @@
|
|||
<script>
|
||||
import Basic from './basic';
|
||||
import Card from './card';
|
||||
import Unit from './unit';
|
||||
import Countdown from './countdown';
|
||||
import CN from '../index.zh-CN.md';
|
||||
import US from '../index.en-US.md';
|
||||
|
||||
const md = {
|
||||
cn: `# Statistic 统计数值
|
||||
展示统计数值。
|
||||
## 何时使用
|
||||
- 当需要突出某个或某组数字时
|
||||
- 当需要展示带描述的统计类数据时使用
|
||||
|
||||
## 代码演示`,
|
||||
us: `# Statistic
|
||||
Statistics can be used to represent people or objects. It supports images, 'Icon's, or letters.
|
||||
## Examples
|
||||
`,
|
||||
};
|
||||
export default {
|
||||
category: 'Components',
|
||||
subtitle: '统计数值',
|
||||
type: 'Data Display',
|
||||
zhType: '数据展示',
|
||||
title: 'Statistic',
|
||||
render () {
|
||||
return (
|
||||
<div>
|
||||
<md cn={md.cn} us={md.us}/>
|
||||
<Basic/>
|
||||
<br/>
|
||||
<Unit/>
|
||||
<br/>
|
||||
<Card/>
|
||||
<br/>
|
||||
<Countdown/>
|
||||
<br/>
|
||||
<api>
|
||||
<template slot='cn'>
|
||||
<CN/>
|
||||
</template>
|
||||
<US/>
|
||||
</api>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,33 @@
|
|||
<cn>
|
||||
#### 单位
|
||||
通过前缀和后缀添加单位。
|
||||
</cn>
|
||||
|
||||
<us>
|
||||
#### Unit
|
||||
Add unit through `prefix` and `suffix`.
|
||||
</us>
|
||||
|
||||
```html
|
||||
<template>
|
||||
<div>
|
||||
<a-statistic
|
||||
title="Feedback"
|
||||
:value="11.28"
|
||||
:precision="2"
|
||||
suffix="%"
|
||||
:valueStyle="{color: '#3f8600'}"
|
||||
style="margin-right: 50px"
|
||||
>
|
||||
<a-icon slot="prefix" type="arrow-up" />
|
||||
</a-statistic>
|
||||
<a-statistic
|
||||
title="Unmerged"
|
||||
:value="78"
|
||||
valueClass="demo-class"
|
||||
>
|
||||
<span slot="suffix"> / 100</span>
|
||||
</a-statistic>
|
||||
</div>
|
||||
</template>
|
||||
```
|
|
@ -0,0 +1,30 @@
|
|||
## API
|
||||
|
||||
### Statistic
|
||||
|
||||
| Property | Description | Type | Default |
|
||||
| -------- | ----------- | ---- | ------- |
|
||||
| decimalSeparator | decimal separator | string | . |
|
||||
| formatter | customize value display logic | (h) => VNode | - |
|
||||
| groupSeparator | group separator | string | , |
|
||||
| precision | precision of input value | number | - |
|
||||
| prefix | prefix node of value | string \| VNode | - |
|
||||
| suffix | suffix node of value | string \| VNode | - |
|
||||
| title | Display title | string \| VNode | - |
|
||||
| value | Display value | string \| number | - |
|
||||
|
||||
|
||||
### Statistic.Countdown
|
||||
|
||||
| Property | Description | Type | Default |
|
||||
| -------- | ----------- | ---- | ------- |
|
||||
| format | Format as [moment](http://momentjs.com/) | string | 'HH:mm:ss' |
|
||||
| prefix | prefix node of value | string \| VNode | - |
|
||||
| suffix | suffix node of value | string \| VNode | - |
|
||||
| title | Display title | string \| VNode | - |
|
||||
| value | Set target countdown time | number \| moment | - |
|
||||
|
||||
#### Statistic.Countdown Events
|
||||
| Events Name | Description | Arguments |
|
||||
| --- | --- | --- |
|
||||
| finish | Trigger when time's up | () => void | - |
|
|
@ -0,0 +1,11 @@
|
|||
import Statistic from './Statistic';
|
||||
import Countdown from './Countdown';
|
||||
|
||||
Statistic.Countdown = Countdown;
|
||||
/* istanbul ignore next */
|
||||
Statistic.install = function(Vue) {
|
||||
Vue.component(Statistic.name, Statistic);
|
||||
Vue.component(Statistic.Countdown.name, Statistic.Countdown);
|
||||
};
|
||||
|
||||
export default Statistic;
|
|
@ -0,0 +1,29 @@
|
|||
## API
|
||||
|
||||
### Statistic
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| -------- | ----------- | ---- | ------- |
|
||||
| decimalSeparator | 设置小数点 | string | . |
|
||||
| formatter | 自定义数值展示 | (h) => VNode | - |
|
||||
| groupSeparator | 设置千分位标识符 | string | , |
|
||||
| precision | 数值精度 | number | - |
|
||||
| prefix | 设置数值的前缀 | string \| VNode | - |
|
||||
| suffix | 设置数值的后缀 | string \| VNode | - |
|
||||
| title | 数值的标题 | string \| VNode | - |
|
||||
| value | 数值内容 | string \| number | - |
|
||||
|
||||
### Statistic.Countdown
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| -------- | ----------- | ---- | ------- |
|
||||
| format | 格式化倒计时展示,参考 [moment](http://momentjs.com/) | string | 'HH:mm:ss' |
|
||||
| prefix | 设置数值的前缀 | string \| VNode | - |
|
||||
| suffix | 设置数值的后缀 | string \| VNode | - |
|
||||
| title | 数值的标题 | string \| VNode | - |
|
||||
| value | 数值内容 | number \| moment | - |
|
||||
|
||||
#### Statistic.Countdown事件
|
||||
| 事件名称 | 说明 | 回调参数 |
|
||||
| --- | --- | --- |
|
||||
| finish | 倒计时完成时触发 | () => void |
|
|
@ -0,0 +1,2 @@
|
|||
import '../../style/index.less';
|
||||
import './index.less';
|
|
@ -0,0 +1,23 @@
|
|||
@import '../../style/themes/default';
|
||||
@import '../../style/mixins/index';
|
||||
|
||||
@statistic-prefix-cls: ~'@{ant-prefix}-statistic';
|
||||
|
||||
.@{statistic-prefix-cls} {
|
||||
.reset-component;
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
vertical-align: middle;
|
||||
|
||||
&-content-value,
|
||||
&-content-prefix {
|
||||
font-size: 1.7em;
|
||||
}
|
||||
&-content-value-decimal {
|
||||
font-size: 0.7em;
|
||||
}
|
||||
&-content-suffix {
|
||||
font-size: 1.1em;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
import * as moment from 'moment';
|
||||
import padStart from 'lodash/padStart';
|
||||
|
||||
import interopDefault from '../_util/interopDefault';
|
||||
|
||||
// Countdown
|
||||
const timeUnits = [
|
||||
['Y', 1000 * 60 * 60 * 24 * 365], // years
|
||||
['M', 1000 * 60 * 60 * 24 * 30], // months
|
||||
['D', 1000 * 60 * 60 * 24], // days
|
||||
['H', 1000 * 60 * 60], // hours
|
||||
['m', 1000 * 60], // minutes
|
||||
['s', 1000], // seconds
|
||||
['S', 1], // million seconds
|
||||
];
|
||||
|
||||
function formatTimeStr(duration, format) {
|
||||
let leftDuration = duration;
|
||||
|
||||
return timeUnits.reduce((current, [name, unit]) => {
|
||||
if (current.indexOf(name) !== -1) {
|
||||
const value = Math.floor(leftDuration / unit);
|
||||
leftDuration -= value * unit;
|
||||
return current.replace(new RegExp(`${name}+`, 'g'), match => {
|
||||
const len = match.length;
|
||||
return padStart(value.toString(), len, '0');
|
||||
});
|
||||
}
|
||||
return current;
|
||||
}, format);
|
||||
}
|
||||
|
||||
export function formatCountdown(value, config) {
|
||||
const { format = '' } = config;
|
||||
const target = interopDefault(moment)(value).valueOf();
|
||||
const current = interopDefault(moment)().valueOf();
|
||||
const diff = Math.max(target - current, 0);
|
||||
return formatTimeStr(diff, format);
|
||||
}
|
|
@ -54,3 +54,4 @@ import './skeleton/style';
|
|||
import './comment/style';
|
||||
import './config-provider/style';
|
||||
import './empty/style';
|
||||
import './statistic/style';
|
||||
|
|
|
@ -40,6 +40,7 @@ import {
|
|||
Select,
|
||||
Slider,
|
||||
Spin,
|
||||
Statistic,
|
||||
Steps,
|
||||
Switch,
|
||||
Table,
|
||||
|
@ -110,6 +111,7 @@ Vue.use(Row);
|
|||
Vue.use(Select);
|
||||
Vue.use(Slider);
|
||||
Vue.use(Spin);
|
||||
Vue.use(Statistic);
|
||||
Vue.use(Steps);
|
||||
Vue.use(Switch);
|
||||
Vue.use(Table);
|
||||
|
|
|
@ -352,4 +352,10 @@ export default {
|
|||
title: 'Skeleton',
|
||||
subtitle: '骨架屏',
|
||||
},
|
||||
statistic: {
|
||||
category: 'Components',
|
||||
subtitle: '统计数值',
|
||||
type: 'Data Display',
|
||||
title: 'Statistic',
|
||||
},
|
||||
};
|
||||
|
|
|
@ -7,6 +7,14 @@ export default [
|
|||
path: 'avatar-cn',
|
||||
component: () => import('../components/avatar/demo/index.vue'),
|
||||
},
|
||||
{
|
||||
path: 'statistic',
|
||||
component: () => import('../components/statistic/demo/index.vue'),
|
||||
},
|
||||
{
|
||||
path: 'statistic-cn',
|
||||
component: () => import('../components/statistic/demo/index.vue'),
|
||||
},
|
||||
{
|
||||
path: 'badge',
|
||||
component: () => import('../components/badge/demo/index.vue'),
|
||||
|
|
|
@ -44,6 +44,7 @@ Array [
|
|||
"Select",
|
||||
"Slider",
|
||||
"Spin",
|
||||
"Statistic",
|
||||
"Steps",
|
||||
"Switch",
|
||||
"Table",
|
||||
|
|
|
@ -46,6 +46,7 @@ import { Select } from './select/select';
|
|||
import { Skeleton } from './skeleton';
|
||||
import { Slider } from './slider';
|
||||
import { Spin } from './spin';
|
||||
import { Statistic } from './statistic';
|
||||
import { Steps } from './steps/steps';
|
||||
import { Switch } from './switch';
|
||||
import { Table } from './table/table';
|
||||
|
@ -110,6 +111,7 @@ export {
|
|||
Select,
|
||||
Slider,
|
||||
Spin,
|
||||
Statistic,
|
||||
Steps,
|
||||
Switch,
|
||||
Table,
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
// Project: https://github.com/vueComponent/ant-design-vue
|
||||
// Definitions by: akki-jat <https://github.com/akki-jat>
|
||||
// Definitions: https://github.com/vueComponent/ant-design-vue/types
|
||||
|
||||
import { AntdComponent } from './component';
|
||||
import { VNode } from 'vue';
|
||||
|
||||
export declare class Statistic extends AntdComponent {
|
||||
/**
|
||||
* decimal separator
|
||||
* @default '.'
|
||||
* @type string
|
||||
*/
|
||||
decimalSeparator: string;
|
||||
|
||||
/**
|
||||
* the shape of statistic
|
||||
* @type string
|
||||
*/
|
||||
formatter: () => VNode;
|
||||
|
||||
/**
|
||||
* group separator
|
||||
* @default ','
|
||||
* @type string
|
||||
*/
|
||||
groupSeparator: string;
|
||||
|
||||
/**
|
||||
* precision of input value
|
||||
* @type number
|
||||
*/
|
||||
precision: number;
|
||||
|
||||
/**
|
||||
* prefix node of value
|
||||
* @type string | VNode
|
||||
*/
|
||||
prefix: string | VNode;
|
||||
|
||||
/**
|
||||
* suffix node of value
|
||||
* @type string | VNode
|
||||
*/
|
||||
suffix: string | VNode;;
|
||||
|
||||
/**
|
||||
* Display title
|
||||
* @type string | VNode
|
||||
*/
|
||||
title: string | VNode;
|
||||
|
||||
/**
|
||||
* Display value
|
||||
* @type string or number
|
||||
*/
|
||||
value: string | number;
|
||||
|
||||
}
|
Loading…
Reference in New Issue