feat:summary-card 重构到 common-ui 里!

This commit is contained in:
YunaiV
2025-10-19 19:10:09 +08:00
parent f6053bd6ca
commit 05bc69541b
8 changed files with 106 additions and 75 deletions

View File

@@ -1,2 +0,0 @@
export { default as SummaryCard } from './summary-card.vue';
export type { SummaryCardProps } from './typing';

View File

@@ -1,60 +0,0 @@
<script lang="ts" setup>
import type { SummaryCardProps } from './typing';
import { CountTo } from '@vben/common-ui';
import { IconifyIcon } from '@vben/icons';
import { Card, Tooltip } from 'ant-design-vue';
/** 统计卡片 */
defineOptions({ name: 'SummaryCard' });
defineProps<SummaryCardProps>();
</script>
<template>
<Card :bordered="false" class="h-full shadow-sm">
<div class="flex flex-row items-center gap-3">
<div
class="flex h-12 w-12 flex-shrink-0 items-center justify-center rounded"
:class="`${iconColor} ${iconBgColor}`"
>
<IconifyIcon v-if="icon" :icon="icon" class="!text-6" />
</div>
<div class="flex flex-col gap-1">
<div class="flex items-center gap-1">
<span class="text-sm text-gray-500">{{ title }}</span>
<Tooltip :content="tooltip" placement="topLeft" v-if="tooltip">
<IconifyIcon
icon="lucide:circle-alert"
class="item-center !text-3 flex"
/>
</Tooltip>
</div>
<div class="flex flex-row items-baseline gap-2">
<div class="text-2xl">
<CountTo
:prefix="prefix"
:end-val="value ?? 0"
:decimals="decimals ?? 0"
/>
</div>
<span
v-if="percent !== undefined"
:class="Number(percent) > 0 ? 'text-red-500' : 'text-green-500'"
class="flex items-center"
>
<span class="text-sm">{{ Math.abs(Number(percent)) }}%</span>
<IconifyIcon
:icon="
Number(percent) > 0
? 'lucide:chevron-up'
: 'lucide:chevron-down'
"
class="ml-0.5 !text-sm"
/>
</span>
</div>
</div>
</div>
</Card>
</template>

View File

@@ -1,11 +0,0 @@
export interface SummaryCardProps {
title: string;
tooltip?: string;
icon?: string;
iconColor?: string;
iconBgColor?: string;
prefix?: string;
value?: number;
decimals?: number;
percent?: number | string;
}

View File

@@ -3,13 +3,12 @@ import type { MallMemberStatisticsApi } from '#/api/mall/statistics/member';
import { onMounted, ref } from 'vue';
import { DocAlert, Page } from '@vben/common-ui';
import { DocAlert, Page, SummaryCard } from '@vben/common-ui';
import { fenToYuan } from '@vben/utils';
import { Col, Row } from 'ant-design-vue';
import * as MemberStatisticsApi from '#/api/mall/statistics/member';
import { SummaryCard } from '#/components/summary-card';
import MemberAreaCard from './modules/area-card.vue';
import MemberFunnelCard from './modules/funnel-card.vue';

View File

@@ -4,6 +4,7 @@ export * from './col-page';
export * from './content-wrap';
export * from './count-to';
export * from './doc-alert';
export * from './summary-card';
export * from './ellipsis-text';
export * from './icon-picker';
export * from './iframe';

View File

@@ -0,0 +1,3 @@
// add by 芋艿:总结卡片,目前 mall 模块在使用
export { default as SummaryCard } from './summary-card.vue';
export * from './types';

View File

@@ -0,0 +1,79 @@
<script lang="ts" setup>
import type { SummaryCardProps } from './types';
import {
Card,
CardContent,
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
VbenCountToAnimator,
VbenIcon,
} from '@vben-core/shadcn-ui';
/** 统计卡片 */
defineOptions({ name: 'SummaryCard' });
defineProps<SummaryCardProps>();
</script>
<template>
<Card class="h-full">
<CardContent class="flex items-center gap-3 p-6">
<div
v-if="icon"
class="flex h-12 w-12 flex-shrink-0 items-center justify-center rounded"
:class="`${iconColor} ${iconBgColor}`"
>
<VbenIcon :icon="icon" class="size-6" />
</div>
<div class="flex flex-col gap-1">
<div class="flex items-center gap-1">
<span class="text-sm text-muted-foreground">{{ title }}</span>
<TooltipProvider v-if="tooltip">
<Tooltip>
<TooltipTrigger>
<VbenIcon
icon="lucide:circle-alert"
class="size-3 text-muted-foreground"
/>
</TooltipTrigger>
<TooltipContent>
<p>{{ tooltip }}</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
<div class="flex flex-row items-baseline gap-2">
<div class="text-2xl">
<VbenCountToAnimator
:prefix="prefix"
:end-val="value ?? 0"
:decimals="decimals ?? 0"
/>
</div>
<span
v-if="percent !== undefined"
:class="
Number(percent) > 0
? 'text-destructive'
: 'text-emerald-600 dark:text-emerald-400'
"
class="flex items-center"
>
<span class="text-sm">{{ Math.abs(Number(percent)) }}%</span>
<VbenIcon
:icon="
Number(percent) > 0
? 'lucide:chevron-up'
: 'lucide:chevron-down'
"
class="ml-0.5 size-3"
/>
</span>
</div>
</div>
</CardContent>
</Card>
</template>

View File

@@ -0,0 +1,22 @@
import type { Component } from 'vue';
export interface SummaryCardProps {
/** 标题 */
title: string;
/** 提示信息 */
tooltip?: string;
/** 图标 */
icon?: Component | string;
/** 图标颜色 */
iconColor?: string;
/** 图标背景色 */
iconBgColor?: string;
/** 前缀 */
prefix?: string;
/** 数值 */
value?: number;
/** 小数位数 */
decimals?: number;
/** 百分比 */
percent?: number | string;
}