mirror of
https://github.com/perfect-panel/ppanel-web.git
synced 2026-02-15 12:51:11 -05:00
✨ feat: Add batch delete functionality and enhance chart tooltips in statistics cards
This commit is contained in:
parent
f4a1237619
commit
c4f536eb05
@ -317,6 +317,23 @@ export default function ServersPage() {
|
|||||||
{t('copy')}
|
{t('copy')}
|
||||||
</Button>,
|
</Button>,
|
||||||
],
|
],
|
||||||
|
batchRender(rows) {
|
||||||
|
return [
|
||||||
|
<ConfirmButton
|
||||||
|
key='delete'
|
||||||
|
trigger={<Button variant='destructive'>{t('delete')}</Button>}
|
||||||
|
title={t('confirmDeleteTitle')}
|
||||||
|
description={t('confirmDeleteDesc')}
|
||||||
|
onConfirm={async () => {
|
||||||
|
await Promise.all(rows.map((r) => deleteServer({ id: r.id })));
|
||||||
|
toast.success(t('deleted'));
|
||||||
|
ref.current?.refresh();
|
||||||
|
}}
|
||||||
|
cancelText={t('cancel')}
|
||||||
|
confirmText={t('confirm')}
|
||||||
|
/>,
|
||||||
|
];
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
onSort={async (source, target, items) => {
|
onSort={async (source, target, items) => {
|
||||||
const sourceIndex = items.findIndex((item) => String(item.id) === source);
|
const sourceIndex = items.findIndex((item) => String(item.id) === source);
|
||||||
|
|||||||
@ -36,6 +36,7 @@ import { Empty } from '../empty';
|
|||||||
|
|
||||||
export function RevenueStatisticsCard() {
|
export function RevenueStatisticsCard() {
|
||||||
const t = useTranslations('index');
|
const t = useTranslations('index');
|
||||||
|
const locale = useLocale();
|
||||||
|
|
||||||
const IncomeStatisticsConfig = {
|
const IncomeStatisticsConfig = {
|
||||||
new_purchase: {
|
new_purchase: {
|
||||||
@ -46,9 +47,12 @@ export function RevenueStatisticsCard() {
|
|||||||
label: t('repurchase'),
|
label: t('repurchase'),
|
||||||
color: 'hsl(var(--chart-2))',
|
color: 'hsl(var(--chart-2))',
|
||||||
},
|
},
|
||||||
|
total: {
|
||||||
|
label: t('totalIncome'),
|
||||||
|
color: 'hsl(var(--chart-3))',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const locale = useLocale();
|
|
||||||
const { data: RevenueStatistics } = useQuery({
|
const { data: RevenueStatistics } = useQuery({
|
||||||
queryKey: ['queryRevenueStatistics'],
|
queryKey: ['queryRevenueStatistics'],
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
@ -175,6 +179,10 @@ export function RevenueStatisticsCard() {
|
|||||||
date: item.date,
|
date: item.date,
|
||||||
new_purchase: unitConversion('centsToDollars', item.new_order_amount),
|
new_purchase: unitConversion('centsToDollars', item.new_order_amount),
|
||||||
repurchase: unitConversion('centsToDollars', item.renewal_order_amount),
|
repurchase: unitConversion('centsToDollars', item.renewal_order_amount),
|
||||||
|
total: unitConversion(
|
||||||
|
'centsToDollars',
|
||||||
|
item.new_order_amount + item.renewal_order_amount,
|
||||||
|
),
|
||||||
})) || []
|
})) || []
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@ -182,18 +190,60 @@ export function RevenueStatisticsCard() {
|
|||||||
<XAxis
|
<XAxis
|
||||||
dataKey='date'
|
dataKey='date'
|
||||||
tickLine={false}
|
tickLine={false}
|
||||||
tickMargin={10}
|
|
||||||
axisLine={false}
|
axisLine={false}
|
||||||
|
tickMargin={10}
|
||||||
tickFormatter={(value) => {
|
tickFormatter={(value) => {
|
||||||
return new Date(value).toLocaleDateString(locale, {
|
const [year, month, day] = value.split('-');
|
||||||
|
return new Date(year, month - 1, day).toLocaleDateString(locale, {
|
||||||
month: 'short',
|
month: 'short',
|
||||||
day: 'numeric',
|
day: 'numeric',
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Bar dataKey='new_purchase' fill='var(--color-new_purchase)' radius={4} />
|
<Bar
|
||||||
<Bar dataKey='repurchase' fill='var(--color-repurchase)' radius={4} />
|
dataKey='new_purchase'
|
||||||
<ChartTooltip cursor={false} content={<ChartTooltipContent />} />
|
fill='var(--color-new_purchase)'
|
||||||
|
radius={[0, 0, 4, 4]}
|
||||||
|
stackId='a'
|
||||||
|
/>
|
||||||
|
<Bar
|
||||||
|
dataKey='repurchase'
|
||||||
|
fill='var(--color-repurchase)'
|
||||||
|
radius={[4, 4, 0, 0]}
|
||||||
|
stackId='a'
|
||||||
|
/>
|
||||||
|
<ChartTooltip
|
||||||
|
content={
|
||||||
|
<ChartTooltipContent
|
||||||
|
formatter={(value, name, item, index) => (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
className='h-2.5 w-2.5 shrink-0 rounded-[2px] bg-[--color-bg]'
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
'--color-bg': `var(--color-${name})`,
|
||||||
|
} as React.CSSProperties
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{IncomeStatisticsConfig[name as keyof typeof IncomeStatisticsConfig]
|
||||||
|
?.label || name}
|
||||||
|
<div className='text-foreground ml-auto flex items-baseline gap-0.5 font-mono font-medium tabular-nums'>
|
||||||
|
{value}
|
||||||
|
</div>
|
||||||
|
{index === 1 && (
|
||||||
|
<div className='text-foreground flex basis-full items-center border-t pt-1.5 text-xs font-medium'>
|
||||||
|
{t('totalIncome')}
|
||||||
|
<div className='text-foreground ml-auto flex items-baseline gap-0.5 font-mono font-medium tabular-nums'>
|
||||||
|
{item.payload.total}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
cursor={false}
|
||||||
|
/>
|
||||||
<ChartLegend content={<ChartLegendContent />} />
|
<ChartLegend content={<ChartLegendContent />} />
|
||||||
</BarChart>
|
</BarChart>
|
||||||
</ChartContainer>
|
</ChartContainer>
|
||||||
@ -247,6 +297,10 @@ export function RevenueStatisticsCard() {
|
|||||||
date: item.date,
|
date: item.date,
|
||||||
new_purchase: unitConversion('centsToDollars', item.new_order_amount),
|
new_purchase: unitConversion('centsToDollars', item.new_order_amount),
|
||||||
repurchase: unitConversion('centsToDollars', item.renewal_order_amount),
|
repurchase: unitConversion('centsToDollars', item.renewal_order_amount),
|
||||||
|
total: unitConversion(
|
||||||
|
'centsToDollars',
|
||||||
|
item.new_order_amount + item.renewal_order_amount,
|
||||||
|
),
|
||||||
})) || []
|
})) || []
|
||||||
}
|
}
|
||||||
margin={{
|
margin={{
|
||||||
@ -259,14 +313,45 @@ export function RevenueStatisticsCard() {
|
|||||||
dataKey='date'
|
dataKey='date'
|
||||||
tickLine={false}
|
tickLine={false}
|
||||||
axisLine={false}
|
axisLine={false}
|
||||||
tickMargin={8}
|
|
||||||
tickFormatter={(value) => {
|
tickFormatter={(value) => {
|
||||||
return new Date(value).toLocaleDateString(locale, {
|
const [year, month] = value.split('-');
|
||||||
|
return new Date(year, month - 1).toLocaleDateString(locale, {
|
||||||
month: 'short',
|
month: 'short',
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<ChartTooltip cursor={false} content={<ChartTooltipContent indicator='dot' />} />
|
<ChartTooltip
|
||||||
|
cursor={false}
|
||||||
|
content={
|
||||||
|
<ChartTooltipContent
|
||||||
|
formatter={(value, name, item, index) => (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
className='h-2.5 w-2.5 shrink-0 rounded-[2px] bg-[--color-bg]'
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
'--color-bg': `var(--color-${name})`,
|
||||||
|
} as React.CSSProperties
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{IncomeStatisticsConfig[name as keyof typeof IncomeStatisticsConfig]
|
||||||
|
?.label || name}
|
||||||
|
<div className='text-foreground ml-auto flex items-baseline gap-0.5 font-mono font-medium tabular-nums'>
|
||||||
|
{value}
|
||||||
|
</div>
|
||||||
|
{index === 1 && (
|
||||||
|
<div className='text-foreground flex basis-full items-center border-t pt-1.5 text-xs font-medium'>
|
||||||
|
{t('totalIncome')}
|
||||||
|
<div className='text-foreground ml-auto flex items-baseline gap-0.5 font-mono font-medium tabular-nums'>
|
||||||
|
{item.payload.total}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
<Area
|
<Area
|
||||||
dataKey='new_purchase'
|
dataKey='new_purchase'
|
||||||
type='natural'
|
type='natural'
|
||||||
|
|||||||
@ -34,6 +34,7 @@ import { Empty } from '../empty';
|
|||||||
|
|
||||||
export function UserStatisticsCard() {
|
export function UserStatisticsCard() {
|
||||||
const t = useTranslations('index');
|
const t = useTranslations('index');
|
||||||
|
const locale = useLocale();
|
||||||
|
|
||||||
const UserStatisticsConfig = {
|
const UserStatisticsConfig = {
|
||||||
register: {
|
register: {
|
||||||
@ -49,7 +50,6 @@ export function UserStatisticsCard() {
|
|||||||
color: 'hsl(var(--chart-3))',
|
color: 'hsl(var(--chart-3))',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const locale = useLocale();
|
|
||||||
|
|
||||||
const { data: UserStatistics } = useQuery({
|
const { data: UserStatistics } = useQuery({
|
||||||
queryKey: ['queryUserStatistics'],
|
queryKey: ['queryUserStatistics'],
|
||||||
@ -192,15 +192,31 @@ export function UserStatisticsCard() {
|
|||||||
tickMargin={10}
|
tickMargin={10}
|
||||||
axisLine={false}
|
axisLine={false}
|
||||||
tickFormatter={(value) => {
|
tickFormatter={(value) => {
|
||||||
|
// value format: "YYYY-MM-DD"
|
||||||
return new Date(value).toLocaleDateString(locale, {
|
return new Date(value).toLocaleDateString(locale, {
|
||||||
month: 'short',
|
month: 'short',
|
||||||
day: 'numeric',
|
day: 'numeric',
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Bar dataKey='register' fill='var(--color-register)' radius={4} />
|
<Bar
|
||||||
<Bar dataKey='new_purchase' fill='var(--color-new_purchase)' radius={4} />
|
dataKey='register'
|
||||||
<Bar dataKey='repurchase' fill='var(--color-repurchase)' radius={4} />
|
fill='var(--color-register)'
|
||||||
|
radius={[0, 0, 4, 4]}
|
||||||
|
stackId='a'
|
||||||
|
/>
|
||||||
|
<Bar
|
||||||
|
dataKey='new_purchase'
|
||||||
|
fill='var(--color-new_purchase)'
|
||||||
|
radius={0}
|
||||||
|
stackId='a'
|
||||||
|
/>
|
||||||
|
<Bar
|
||||||
|
dataKey='repurchase'
|
||||||
|
fill='var(--color-repurchase)'
|
||||||
|
radius={[4, 4, 0, 0]}
|
||||||
|
stackId='a'
|
||||||
|
/>
|
||||||
<ChartTooltip cursor={false} content={<ChartTooltipContent />} />
|
<ChartTooltip cursor={false} content={<ChartTooltipContent />} />
|
||||||
<ChartLegend content={<ChartLegendContent />} />
|
<ChartLegend content={<ChartLegendContent />} />
|
||||||
</BarChart>
|
</BarChart>
|
||||||
@ -267,9 +283,10 @@ export function UserStatisticsCard() {
|
|||||||
dataKey='date'
|
dataKey='date'
|
||||||
tickLine={false}
|
tickLine={false}
|
||||||
axisLine={false}
|
axisLine={false}
|
||||||
tickMargin={8}
|
|
||||||
tickFormatter={(value) => {
|
tickFormatter={(value) => {
|
||||||
return new Date(value).toLocaleDateString(locale, {
|
// value format: "YYYY-MM"
|
||||||
|
const [year, month] = value.split('-');
|
||||||
|
return new Date(year, month - 1).toLocaleDateString(locale, {
|
||||||
month: 'short',
|
month: 'short',
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user