diff --git a/packages/devui-vue/devui/ripple/__tests__/ripple.spec.ts b/packages/devui-vue/devui/ripple/__tests__/ripple.spec.ts
deleted file mode 100644
index e4e3fddc36720ed65073df08ece25f0ff1a44128..0000000000000000000000000000000000000000
--- a/packages/devui-vue/devui/ripple/__tests__/ripple.spec.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-import { nextTick, createApp } from 'vue'
-import { mount } from '@vue/test-utils'
-import Ripple from '../index'
-import { DEFAULT_PLUGIN_OPTIONS } from '../src/options'
-// 全局属性
-const global = {
- directives: {
- ripple: Ripple
- }
-}
-describe('ripple', () => {
- it('ripple should render correctly', async () => {
- const wrapper = mount(
- {
- template: `
-
- `
- },
- {
- global
- }
- )
- await nextTick()
- const rippleElement = wrapper.find('.ripple-container') as any
- await rippleElement.trigger('click')
- console.log(rippleElement.element.childElementCount)
-
- expect(wrapper.find('div').exists()).toBeTruthy()
- })
- it('test ripple plugin', () => {
- const app = createApp({}).use(Ripple)
- expect(app.directive('ripple', Ripple)).toBeTruthy()
- })
-
- it('ripple default options', () => {
- expect(DEFAULT_PLUGIN_OPTIONS).toEqual({
- directive: 'ripple',
- color: 'currentColor',
- initialOpacity: 0.2,
- finalOpacity: 0.1,
- duration: 0.8,
- easing: 'ease-out',
- delayTime: 75,
- disabled: false
- })
- })
-})
diff --git a/packages/devui-vue/devui/ripple/src/options.ts b/packages/devui-vue/devui/ripple/src/options.ts
deleted file mode 100644
index 18f04ca94b1129d11fc1ce9b0a8e14998c035e41..0000000000000000000000000000000000000000
--- a/packages/devui-vue/devui/ripple/src/options.ts
+++ /dev/null
@@ -1,95 +0,0 @@
-interface IRippleDirectiveOptions {
- /**
- *
- * @remarks
- * Y* 你可以设置 ·currentColor· to 能够自动使用元素的文本颜色
- *
- * @default
- * 'currentColor'
- */
- color: string
- /**
- * 第一次出现的透明度
- *
- * @default
- * 0.2 默认opacity 0.2
- */
- initialOpacity: number
- /**
- * 在透明度 结束的时候 stopped 的时候 我们设置透明度的大小
- *
- * @default
- * 0.1
- */
- finalOpacity: number
- /**
- * 动画持续事件
- *
- * @default
- * 0.4
- */
- duration: number
- /**
- * css 动画 从开始到结束 以相同的时间来执行动画
- *
- * @default
- * 'ease-out'
- */
- easing: string
- /**
- * 取消延迟时间
- *
- * @note
- * 类似于 debounceTime
- * @default
- * 75
- */
- delayTime: number
- /**
- * 禁止 水波
- *
- * @note
- * 类似于 debounceTime
- * @default
- * 75
- */
- disabled: boolean
-}
-
-interface IRipplePluginOptions extends IRippleDirectiveOptions {
- /**
- * 用于覆盖指令的名称
- *
- * @remarks
- *
- * @example
- *
- * @default
- * 默认指令 ripple
- */
- directive: string
-}
-
-// 给可预见值 value 添加类型
-
-interface IRippleDirectiveOptionWithBinding {
- value: IRippleDirectiveOptions
-}
-
-const DEFAULT_PLUGIN_OPTIONS: IRipplePluginOptions = {
- directive: 'ripple',
- color: 'currentColor',
- initialOpacity: 0.2,
- finalOpacity: 0.1,
- duration: 0.8,
- easing: 'ease-out',
- delayTime: 75,
- disabled: false
-}
-
-export {
- DEFAULT_PLUGIN_OPTIONS,
- IRipplePluginOptions,
- IRippleDirectiveOptions,
- IRippleDirectiveOptionWithBinding
-}
diff --git a/packages/devui-vue/devui/ripple/src/ripple-directive.ts b/packages/devui-vue/devui/ripple/src/ripple-directive.ts
deleted file mode 100644
index e4ad61ebdb798e5f20a38686cb883b4f0109e10e..0000000000000000000000000000000000000000
--- a/packages/devui-vue/devui/ripple/src/ripple-directive.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-// can export function. 解构参数类型冗余 新定义insterface IRippleDirectiveOptionWithBinding
-import {
- DEFAULT_PLUGIN_OPTIONS,
- IRippleDirectiveOptions,
- IRippleDirectiveOptionWithBinding
-} from './options'
-import { ripple } from './v-ripple'
-const optionMap = new WeakMap | false>()
-const globalOptions = { ...DEFAULT_PLUGIN_OPTIONS }
-export default {
- mounted(el: HTMLElement, binding: IRippleDirectiveOptionWithBinding) {
- optionMap.set(el, binding.value ?? {})
-
- el.addEventListener('pointerdown', (event) => {
- const options = optionMap.get(el)
- // 必须确保disabled 属性存在 否则指令终止报错
- if (binding.value && binding.value.disabled) return
-
- if (options === false) return
-
- ripple(event, el, {
- ...globalOptions,
- ...options
- })
- })
- },
- updated(el: HTMLElement, binding: IRippleDirectiveOptionWithBinding) {
- optionMap.set(el, binding.value ?? {})
- }
-}
diff --git a/packages/devui-vue/devui/statistic/__tests__/statistic.spec.ts b/packages/devui-vue/devui/statistic/__tests__/statistic.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..fb9c9e8903d8935a48e5f2b5946f2dd62edeac24
--- /dev/null
+++ b/packages/devui-vue/devui/statistic/__tests__/statistic.spec.ts
@@ -0,0 +1,8 @@
+import { mount } from '@vue/test-utils'
+import { Statistic } from '../index'
+
+describe('statistic test', () => {
+ it('statistic init render', async () => {
+ // todo
+ })
+})
diff --git a/packages/devui-vue/devui/statistic/index.ts b/packages/devui-vue/devui/statistic/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..116831ee7fa9e81dfad9691db365ec9d382c0145
--- /dev/null
+++ b/packages/devui-vue/devui/statistic/index.ts
@@ -0,0 +1,17 @@
+import type { App } from 'vue'
+import Statistic from './src/statistic'
+
+Statistic.install = function(app: App): void {
+ app.component(Statistic.name, Statistic)
+}
+
+export { Statistic }
+
+export default {
+ title: 'Statistic 统计数值',
+ category: '数据展示',
+ status: undefined, // TODO: 组件若开发完成则填入"已完成",并删除该注释
+ install(app: App): void {
+ app.use(Statistic as any)
+ }
+}
diff --git a/packages/devui-vue/devui/statistic/src/statistic-types.ts b/packages/devui-vue/devui/statistic/src/statistic-types.ts
new file mode 100644
index 0000000000000000000000000000000000000000..db27965c2a682798630622fedb5a1bf1ddc0d0b7
--- /dev/null
+++ b/packages/devui-vue/devui/statistic/src/statistic-types.ts
@@ -0,0 +1,63 @@
+import type { PropType, ExtractPropTypes, CSSProperties } from 'vue'
+import type { easingType } from './utils/animation'
+export const statisticProps = {
+ title: {
+ type: String,
+ default: ''
+ },
+ value: {
+ type: [Number, String]
+ },
+ prefix: {
+ type: String
+ },
+ suffix: {
+ type: String
+ },
+ precision: {
+ type: Number
+ },
+ groupSeparator: {
+ type: String,
+ default: ','
+ },
+ showGroupSeparator: {
+ type: Boolean,
+ default: false
+ },
+ titleStyle: {
+ type: Object as PropType
+ },
+ contentStyle: {
+ type: Object as PropType
+ },
+ animationDuration: {
+ type: Number,
+ default: 2000
+ },
+ valueFrom: {
+ type: Number
+ },
+ animation: {
+ type: Boolean,
+ default: false
+ },
+ start: {
+ type: Boolean,
+ default: false
+ },
+ extra: {
+ type: String,
+ default: ''
+ },
+ easing: {
+ type: String as PropType,
+ default: 'easeOutCubic'
+ },
+ delay: {
+ type: Number,
+ default: 0
+ }
+} as const
+
+export type StatisticProps = ExtractPropTypes
diff --git a/packages/devui-vue/devui/statistic/src/statistic.scss b/packages/devui-vue/devui/statistic/src/statistic.scss
new file mode 100644
index 0000000000000000000000000000000000000000..a619e6ce5c2c119d0cc0160ff82ad1796237c4b7
--- /dev/null
+++ b/packages/devui-vue/devui/statistic/src/statistic.scss
@@ -0,0 +1,34 @@
+.devui-statistic {
+ box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+ font-size: 14px;
+ font-variant: tabular-nums;
+ line-height: 1.5715;
+ list-style: none;
+
+ &-title {
+ margin-bottom: 4 px;
+ opacity: 0.7;
+ font-size: 14px;
+ }
+
+ &-content {
+ font-size: 24px;
+ display: flex;
+ align-items: center;
+ vertical-align: center;
+ }
+
+ &-prefix {
+ margin-right: 6px;
+ }
+
+ &-suffix {
+ margin-left: 6px;
+ }
+
+ &--value {
+ display: inline-block;
+ }
+}
diff --git a/packages/devui-vue/devui/statistic/src/statistic.tsx b/packages/devui-vue/devui/statistic/src/statistic.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..e57ebf1127858cfabba21b0e4b83618caba7cdbd
--- /dev/null
+++ b/packages/devui-vue/devui/statistic/src/statistic.tsx
@@ -0,0 +1,85 @@
+import { defineComponent, computed, ref, onMounted, watch } from 'vue'
+import { statisticProps, StatisticProps } from './statistic-types'
+import { analysisValueType } from './utils/separator'
+import { Tween } from './utils/animation'
+import './statistic.scss'
+
+export default defineComponent({
+ name: 'DStatistic',
+ props: statisticProps,
+ inheritAttrs: false,
+ setup(props: StatisticProps, ctx) {
+ const innerValue = ref(props.valueFrom ?? props.value)
+ const tween = ref(null)
+
+ const animation = (
+ from: number = props.valueFrom ?? 0,
+ to: number = typeof props.value === 'number' ? props.value : Number(props.value)
+ ) => {
+ if (from !== to) {
+ tween.value = new Tween({
+ from: {
+ value: from
+ },
+ to: {
+ value: to
+ },
+ delay: props.delay,
+ duration: props.animationDuration,
+ easing: props.easing,
+ onUpdate: (keys: any) => {
+ innerValue.value = keys.value
+ },
+ onFinish: () => {
+ innerValue.value = to
+ }
+ })
+ tween.value.start()
+ }
+ }
+
+ const statisticValue = computed(() => {
+ return analysisValueType(
+ innerValue.value,
+ props.value,
+ props.groupSeparator,
+ props.precision,
+ props.showGroupSeparator,
+ props.animation
+ )
+ })
+ onMounted(() => {
+ if (props.animation && props.start) {
+ animation()
+ }
+ })
+
+ watch(
+ () => props.start,
+ (value) => {
+ if (value && !tween.value) {
+ animation()
+ }
+ }
+ )
+ return () => {
+ return (
+
+
+ {ctx.slots.title?.() || props.title}
+
+
+ {props.prefix || ctx.slots.prefix?.() ? (
+ {ctx.slots.prefix?.() || props.prefix}
+ ) : null}
+ {statisticValue.value}
+ {props.suffix || ctx.slots.suffix?.() ? (
+ {ctx.slots.suffix?.() || props.suffix}
+ ) : null}
+
+ {ctx.slots.extra?.() || props.extra}
+
+ )
+ }
+ }
+})
diff --git a/packages/devui-vue/devui/statistic/src/utils/animation.ts b/packages/devui-vue/devui/statistic/src/utils/animation.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8b1ef6958715dbf7c28eb18dc17af1d584ee08f3
--- /dev/null
+++ b/packages/devui-vue/devui/statistic/src/utils/animation.ts
@@ -0,0 +1,129 @@
+import * as easing from './easing'
+
+export type easingType = 'easeOutCubic' | 'linear' | 'easeOutExpo' | 'easeInOutExpo'
+export interface startFunc {
+ (key: number): number
+}
+export interface updateFunc {
+ (key: any): any
+}
+export interface finishFunc {
+ (key: any): any
+}
+export interface fromType {
+ value: number
+}
+export interface toType {
+ value: number
+}
+export interface AnimationOptions {
+ from: fromType
+ to: toType
+ duration?: number
+ delay?: number
+ easing?: easingType
+ onStart?: startFunc
+ onUpdate?: updateFunc
+ onFinish?: finishFunc
+}
+
+export class Tween {
+ from: fromType
+ to: toType
+ duration?: number
+ delay?: number
+ easing?: easingType
+ onStart?: startFunc
+ onUpdate?: updateFunc
+ onFinish?: finishFunc
+ startTime?: number
+ started?: boolean
+ finished?: boolean
+ timer?: null | number
+ time?: number
+ elapsed?: number
+ keys?: any
+ constructor(options: AnimationOptions) {
+ const { from, to, duration, delay, easing, onStart, onUpdate, onFinish } = options
+ for (const key in from) {
+ if (to[key] === undefined) {
+ to[key] = from[key]
+ }
+ }
+
+ for (const key in to) {
+ if (from[key] === undefined) {
+ from[key] = to[key]
+ }
+ }
+
+ this.from = from
+ this.to = to
+ this.duration = duration
+ this.delay = delay
+ this.easing = easing || 'linear'
+ this.onStart = onStart
+ this.onUpdate = onUpdate || function () {}
+ this.onFinish = onFinish
+ this.startTime = Date.now() + this.delay
+ this.started = false
+ this.finished = false
+ this.timer = null
+ this.keys = {}
+ }
+
+ update() {
+ this.time = Date.now()
+ // delay some time
+ if (this.time < this.startTime) {
+ return
+ }
+ if (this.finished) {
+ return
+ }
+ // finish animation
+ if (this.elapsed === this.duration) {
+ if (!this.finished) {
+ this.finished = true
+ this.onFinish && this.onFinish(this.keys)
+ }
+ return
+ }
+ // elapsed 时间 和 duration 时间比较 逝去光阴
+ this.elapsed = this.time - this.startTime
+ // 防止 时间 一直 流逝 ~
+ this.elapsed = this.elapsed > this.duration ? this.duration : this.elapsed
+ // 从0 到 1 elapsed time
+ for (const key in this.to) {
+ this.keys[key] =
+ this.from[key] +
+ (this.to[key] - this.from[key]) * easing[this.easing](this.elapsed / this.duration)
+ }
+ if (!this.started) {
+ this.onStart && this.onStart(this.keys)
+ this.started = true
+ }
+ this.onUpdate(this.keys)
+ }
+
+ // 递归 重绘
+ start() {
+ this.startTime = Date.now() + this.delay
+ const tick = () => {
+ this.update()
+ this.timer = requestAnimationFrame(tick)
+
+ if (this.finished) {
+ // 在判断 update中 结束后 停止 重绘
+ cancelAnimationFrame(this.timer)
+ this.timer = null
+ }
+ }
+ tick()
+ }
+
+ stop() {
+ cancelAnimationFrame(this.timer)
+ this.timer = null
+ }
+}
diff --git a/packages/devui-vue/devui/statistic/src/utils/easing.ts b/packages/devui-vue/devui/statistic/src/utils/easing.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6dfa4ca2f810be95f0928ea2360fae73bec1fdf0
--- /dev/null
+++ b/packages/devui-vue/devui/statistic/src/utils/easing.ts
@@ -0,0 +1,27 @@
+// pow 返回 基数的指数次幂 t ** power
+const pow = Math.pow
+const sqrt = Math.sqrt
+
+export const easeOutCubic = function (x: number) {
+ return 1 - pow(1 - x, 3)
+}
+export const linear = (x) => x
+export const easeOutExpo = function (x: number) {
+ return x === 1 ? 1 : 1 - pow(2, -10 * x)
+}
+
+export const easeInOutExpo = function (x: number) {
+ return x === 0
+ ? 0
+ : x === 1
+ ? 1
+ : x < 0.5
+ ? pow(2, 20 * x - 10) / 2
+ : (2 - pow(2, -20 * x + 10)) / 2
+}
+export const easeInExpo = function (x: number) {
+ return x === 0 ? 0 : pow(2, 10 * x - 10)
+}
+export const easeInOutCirc = function (x: number) {
+ return x < 0.5 ? (1 - sqrt(1 - pow(2 * x, 2))) / 2 : (sqrt(1 - pow(-2 * x + 2, 2)) + 1) / 2
+}
diff --git a/packages/devui-vue/devui/statistic/src/utils/separator.ts b/packages/devui-vue/devui/statistic/src/utils/separator.ts
new file mode 100644
index 0000000000000000000000000000000000000000..91178bccbc0862d6ce8ff48467dff169505f75ec
--- /dev/null
+++ b/packages/devui-vue/devui/statistic/src/utils/separator.ts
@@ -0,0 +1,54 @@
+export type valueType = string | number
+
+export const separator = (
+ SeparatorString: string, // value
+ groupSeparator: string, // 千分位分隔符
+ showGroupSeparator: boolean // 是否展示千分位分隔符
+): string => {
+ const res = SeparatorString.replace(/\d+/, function (n) {
+ // 先提取整数部分
+ return n.replace(/(\d)(?=(\d{3})+$)/g, function ($1) {
+ return $1 + `${showGroupSeparator ? groupSeparator : ''}`
+ })
+ })
+ return res
+}
+
+export const isHasDot = (value: number): boolean => {
+ if (!isNaN(value)) {
+ return (value + '').indexOf('.') !== -1
+ }
+}
+export const analysisValueType = (
+ value: valueType, // 动态value 值
+ propsValue: valueType, // 用户传入value
+ groupSeparator: string, // 千位分隔符
+ splitPrecisionNumber: number, // 分割精度, 小数点
+ showGroupSeparator: boolean // 是否展示千分位分隔符
+): string => {
+ const fixedNumber =
+ propsValue.toString().indexOf('.') !== -1
+ ? propsValue.toString().length - propsValue.toString().indexOf('.') - 1
+ : 0
+ if (typeof value === 'number') {
+ if (isHasDot(value)) {
+ return splitPrecisionNumber
+ ? separator(
+ value.toFixed(splitPrecisionNumber).toString(),
+ groupSeparator,
+ showGroupSeparator
+ )
+ : separator(value.toFixed(fixedNumber).toString(), groupSeparator, showGroupSeparator)
+ } else {
+ return splitPrecisionNumber
+ ? separator(
+ value.toFixed(splitPrecisionNumber).toString(),
+ groupSeparator,
+ showGroupSeparator
+ )
+ : separator(value.toString(), groupSeparator, showGroupSeparator)
+ }
+ } else {
+ return value
+ }
+}
diff --git a/packages/devui-vue/docs/components/ripple/index.md b/packages/devui-vue/docs/components/ripple/index.md
deleted file mode 100644
index 3212227f787c627f59fa0a6e6ceaa964fba1a6e6..0000000000000000000000000000000000000000
--- a/packages/devui-vue/docs/components/ripple/index.md
+++ /dev/null
@@ -1,219 +0,0 @@
-# Ripple 水波纹指令
-
-`v-ripple` 指令 用于用户动作交互场景, 可以应用于任何块级元素 `注:只能作用于块级元素`
-
-### 使用
-
-:::demo 用户 可以在组件 或者 HTML 元素上任意使用 `v-ripple` 指令 使用基本的 `v-ripple` 指令, `v-ripple` 接收 一个对象
-
-```vue
-
-
-
-
-
-
-
-
-
-
-
-```
-
-:::
-
-### 自定义色彩
-
-### 通过修改文本颜色来动态改变
-
-:::demo
-
-```vue
-
-
-
-
- -
-
- {{ item.text }}
-
-
-
-
-
-
- -
-
- {{ item.text }}
-
-
-
-
-
-
-```
-
-:::
-
-
-### 应用于其他组件
-
-Button 组件
-
-:::demo
-
-```vue
-
-
-
- Text
-
-
- Text dark
-
-
-
-
-
-
-
-
-
-```
-
-:::
-
-Card 组件
-
-:::demo
-```vue
-
-
-
-
-
-
- DEVUI Course
-
-
- DevUI
-
-
- DEVUI is a free open-source and common solution for the front end of enterprise mid- and back-end products. Its design values are basedon...
-
-
-
- 12
-
-
- 8
-
-
- 8
-
-
-
-
-
-```
-
-:::
-
-
-
-### API
-
-| 参数 | 类型 | 默认 | 说明 |
-| :-------------: | :-------: | :---------: | :-------------------------------- |
-| color | `string` | `#00000050` | 可选,默认当前文本颜色 |
-| initial-opacity | `number` | `0.1` | 可选,初始交互效果透明度大小 |
-| final-opacity | `number` | `0.1` | 可选,结束交互效果长按透明度大小 |
-| duration | `number` | `0.4s` | 可选,持续时间 |
-| easing | `string` | `ease-out` | 可选,缓动动画 |
-| delay-time | `number` | `75ms` | 可选,延迟 debouceTime 时间后调用 |
-| disabled | `boolean` | `false` | 可选,禁止水波效果 |
diff --git a/packages/devui-vue/docs/components/statistic/index.md b/packages/devui-vue/docs/components/statistic/index.md
new file mode 100644
index 0000000000000000000000000000000000000000..2b8809b45ed7f39cc3269ef7a533005d88c88719
--- /dev/null
+++ b/packages/devui-vue/docs/components/statistic/index.md
@@ -0,0 +1,191 @@
+# Statistic 统计数值
+
+### 何时使用
+
+当需要展示带描述的统计类数据时使用
+
+### 基本用法
+
+:::demo
+
+```vue
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+:::
+
+### 在卡片中使用
+
+在卡片中展示统计数值。
+:::demo
+
+```vue
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+:::
+
+### 数值动画
+
+我们可以通过设置 animation 属性 开启数值动画。可以在页面加载时开始动画,也可以手动控制
+:::demo
+
+```vue
+
+
+
+
+
+
+
+
+
+
+
+
+ Start
+
+
+
+
+
+```
+
+:::
+
+### 插槽的使用
+
+前缀和后缀插槽
+:::demo
+
+```vue
+
+
+
+
+
+ %
+
+
+
+
+
+
+ / 100
+
+
+
+
+
+```
+
+:::
+
+### d-statistic
+
+| 参数 | 类型 | 默认 | 说明 |
+| ------------------ | ------------------ | -------- | ---------------- |
+| title | `string \| v-slot` | - | 数值的标题 |
+| extra | `string \| v-slot` | - | 额外内容 |
+| value | `number \| string` | - | 数值内容 |
+| group-separator | `string` | , | 设置千分位标识符 |
+| precision | `number` | - | 设置数值精度 |
+| suffix | `string \| v-slot` | - | 设置数值的后缀 |
+| prefix | `string \| v-slot` | - | 设置数值的前缀 |
+| title-style | `style` | - | 标题样式 |
+| content-style | `style` | - | 内容样式 |
+| animation-duration | `number` | 2000 | 动画持续时间 |
+| delay | `number` | 0 | 延迟进行动画时间 |
+| valueFrom | `number` | 0 | 动画初始值 |
+| animation | `boolean` | false | 是否开启动画 |
+| easing | `string` | quartOut | 数字动画效果 |
+| start | `boolean` | false | 是否开始动画 |
+
+d-statistic 事件
+
+| 事件 | 类型 | 说明 | 跳转 Demo |
+| ---- | ---- | ---- | --------- |
+| | | | |
+| | | | |
+| | | | |
diff --git a/packages/devui-vue/docs/en-US/components/ripple/index.md b/packages/devui-vue/docs/en-US/components/ripple/index.md
deleted file mode 100644
index 193770a83f7bcc9b8d7509d98ea9e39d14ebdca0..0000000000000000000000000000000000000000
--- a/packages/devui-vue/docs/en-US/components/ripple/index.md
+++ /dev/null
@@ -1,221 +0,0 @@
-# RippleDirective
-
-`v-ripple`The v-ripple directive is used to show action from a user. It can be applied to any block level element.`tips: It can be applied to any block level element.`
-
-### When to Use
-
-:::demo User can be use Basic ripple functionality can be enabled just by using v-ripple directive on a component or an HTML element `v-ripple`Basic ripple functionality `v-ripple` Directive `v-ripple` Accept an object
-
-```vue
-
-
-
-
-
-
-
-
-
-
-
-```
-
-:::
-
-### Custom color
-
-### Change the ripple color dynamically by changing the text color or the ripple color
-
-:::demo
-
-```vue
-
-
-
-
- -
-
- {{ item.text }}
-
-
-
-
-
-
- -
-
- {{ item.text }}
-
-
-
-
-
-
-```
-
-:::
-
-
-### Ripple in components
-
-### Some components provide the ripple prop that allows you to control the ripple effect.
-
-Button Component
-
-:::demo
-
-```vue
-
-
-
- Text
-
-
- Text dark
-
-
-
-
-
-
-
-
-
-```
-
-:::
-
-Card Component
-
-:::demo
-```vue
-
-
-
-
-
-
- DEVUI Course
-
-
- DevUI
-
-
- DEVUI is a free open-source and common solution for the front end of enterprise mid- and back-end products. Its design values are basedon...
-
-
-
- 12
-
-
- 8
-
-
- 8
-
-
-
-
-
-```
-
-:::
-
-
-
-### API
-
-| 参数 | 类型 | 默认 | 说明 |
-| :-------------: | :-------: | :---------: | :---------------------------------------------------------------------------- |
-| color | `string` | `#00000050` | Choose Default current text color |
-| initial-opacity | `number` | `0.1` | Choose Initial interaction Opacity size |
-| final-opacity | `number` | `0.1` | Choose, end the interactive effect and press the Opacity size for a long time |
-| duration | `number` | `0.4s` | Choose, duration |
-| easing | `string` | `ease-out` | Choose, animation easing |
-| delay-time | `number` | `75ms` | Choose, slow animation is delayed after debouceTime time. |
-| disabled | `boolean` | `false` | Choose, disabled ripple effect |
diff --git a/packages/devui-vue/docs/en-US/components/statistic/index.md b/packages/devui-vue/docs/en-US/components/statistic/index.md
new file mode 100644
index 0000000000000000000000000000000000000000..5bc17b46ab39d261e7847c1e9bb3b5e2914694bd
--- /dev/null
+++ b/packages/devui-vue/docs/en-US/components/statistic/index.md
@@ -0,0 +1,191 @@
+# Statistic
+
+### When to use
+
+Used when it is necessary to display statistical data with description
+
+### Basic Usage
+
+:::demo
+
+```vue
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+:::
+
+### Use in card
+
+Display statistics in cards.
+:::demo
+
+```vue
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+:::
+
+### Numerical animation
+
+We can start numerical animation by setting the animation attribute. You can start the animation when the page loads, or you can control it manually
+:::demo
+
+```vue
+
+
+
+
+
+
+
+
+
+
+
+
+ Start
+
+
+
+
+
+```
+
+:::
+
+### Use of slots
+
+Prefix and suffix slots
+:::demo
+
+```vue
+
+
+
+
+
+ %
+
+
+
+
+
+
+ / 100
+
+
+
+
+
+```
+
+:::
+
+### d-statistic
+
+| 参数 | 类型 | 默认 | 说明 |
+| ------------------ | ------------------ | -------- | ---------------------------- |
+| title | `string \| v-slot` | - | Title of value |
+| extra | `string \| v-slot` | - | Extra content |
+| value | `number \| string` | - | Value content |
+| group-separator | `string` | , | Set group-separator |
+| precision | `number` | - | Set numeric precision |
+| suffix | `string \| v-slot` | - | Sets the suffix of the value |
+| prefix | `string \| v-slot` | - | Sets the prefix of the value |
+| title-style | `style` | - | Title Style |
+| content-style | `style` | - | Content style |
+| animation-duration | `number` | 2000 | Animation duration |
+| delay | `number` | 0 | Delay animation time |
+| valueFrom | `number` | 0 | Animation initial value |
+| animation | `boolean` | false | Turn on animation |
+| easing | `string` | quartOut | Digital animation effect |
+| start | `boolean` | false | Start animation |
+
+d-statistic 事件
+
+| 事件 | 类型 | 说明 | 跳转 Demo |
+| ---- | ---- | ---- | --------- |
+| | | | |
+| | | | |
+| | | | |