mirror of
https://github.com/router-for-me/Cli-Proxy-API-Management-Center.git
synced 2026-02-18 18:50:49 +08:00
refactor(usage): modularize UsagePage into separate section components
This commit is contained in:
142
src/utils/usage/chartConfig.ts
Normal file
142
src/utils/usage/chartConfig.ts
Normal file
@@ -0,0 +1,142 @@
|
||||
/**
|
||||
* Chart.js configuration utilities for usage statistics
|
||||
* Extracted from UsagePage.tsx for reusability
|
||||
*/
|
||||
|
||||
import type { ChartOptions } from 'chart.js';
|
||||
|
||||
/**
|
||||
* Static sparkline chart options (no dependencies on theme/mobile)
|
||||
*/
|
||||
export const sparklineOptions: ChartOptions<'line'> = {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
plugins: { legend: { display: false }, tooltip: { enabled: false } },
|
||||
scales: { x: { display: false }, y: { display: false } },
|
||||
elements: { line: { tension: 0.45 }, point: { radius: 0 } }
|
||||
};
|
||||
|
||||
export interface ChartConfigOptions {
|
||||
period: 'hour' | 'day';
|
||||
labels: string[];
|
||||
isDark: boolean;
|
||||
isMobile: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build chart options with theme and responsive awareness
|
||||
*/
|
||||
export function buildChartOptions({
|
||||
period,
|
||||
labels,
|
||||
isDark,
|
||||
isMobile
|
||||
}: ChartConfigOptions): ChartOptions<'line'> {
|
||||
const pointRadius = isMobile && period === 'hour' ? 0 : isMobile ? 2 : 4;
|
||||
const tickFontSize = isMobile ? 10 : 12;
|
||||
const maxTickLabelCount = isMobile ? (period === 'hour' ? 8 : 6) : period === 'hour' ? 12 : 10;
|
||||
const gridColor = isDark ? 'rgba(255, 255, 255, 0.06)' : 'rgba(17, 24, 39, 0.06)';
|
||||
const axisBorderColor = isDark ? 'rgba(255, 255, 255, 0.10)' : 'rgba(17, 24, 39, 0.10)';
|
||||
const tickColor = isDark ? 'rgba(255, 255, 255, 0.72)' : 'rgba(17, 24, 39, 0.72)';
|
||||
const tooltipBg = isDark ? 'rgba(17, 24, 39, 0.92)' : 'rgba(255, 255, 255, 0.98)';
|
||||
const tooltipTitle = isDark ? '#ffffff' : '#111827';
|
||||
const tooltipBody = isDark ? 'rgba(255, 255, 255, 0.86)' : '#374151';
|
||||
const tooltipBorder = isDark ? 'rgba(255, 255, 255, 0.10)' : 'rgba(17, 24, 39, 0.10)';
|
||||
|
||||
return {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
interaction: {
|
||||
mode: 'index',
|
||||
intersect: false
|
||||
},
|
||||
plugins: {
|
||||
legend: { display: false },
|
||||
tooltip: {
|
||||
backgroundColor: tooltipBg,
|
||||
titleColor: tooltipTitle,
|
||||
bodyColor: tooltipBody,
|
||||
borderColor: tooltipBorder,
|
||||
borderWidth: 1,
|
||||
padding: 10,
|
||||
displayColors: true,
|
||||
usePointStyle: true
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
x: {
|
||||
grid: {
|
||||
color: gridColor,
|
||||
drawTicks: false
|
||||
},
|
||||
border: {
|
||||
color: axisBorderColor
|
||||
},
|
||||
ticks: {
|
||||
color: tickColor,
|
||||
font: { size: tickFontSize },
|
||||
maxRotation: isMobile ? 0 : 45,
|
||||
minRotation: 0,
|
||||
autoSkip: true,
|
||||
maxTicksLimit: maxTickLabelCount,
|
||||
callback: (value) => {
|
||||
const index = typeof value === 'number' ? value : Number(value);
|
||||
const raw =
|
||||
Number.isFinite(index) && labels[index] ? labels[index] : typeof value === 'string' ? value : '';
|
||||
|
||||
if (period === 'hour') {
|
||||
const [md, time] = raw.split(' ');
|
||||
if (!time) return raw;
|
||||
if (time.startsWith('00:')) {
|
||||
return md ? [md, time] : time;
|
||||
}
|
||||
return time;
|
||||
}
|
||||
|
||||
if (isMobile) {
|
||||
const parts = raw.split('-');
|
||||
if (parts.length === 3) {
|
||||
return `${parts[1]}-${parts[2]}`;
|
||||
}
|
||||
}
|
||||
return raw;
|
||||
}
|
||||
}
|
||||
},
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
grid: {
|
||||
color: gridColor
|
||||
},
|
||||
border: {
|
||||
color: axisBorderColor
|
||||
},
|
||||
ticks: {
|
||||
color: tickColor,
|
||||
font: { size: tickFontSize }
|
||||
}
|
||||
}
|
||||
},
|
||||
elements: {
|
||||
line: {
|
||||
tension: 0.35,
|
||||
borderWidth: isMobile ? 1.5 : 2
|
||||
},
|
||||
point: {
|
||||
borderWidth: 2,
|
||||
radius: pointRadius,
|
||||
hoverRadius: 4
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate minimum chart width for hourly data on mobile devices
|
||||
*/
|
||||
export function getHourChartMinWidth(labelCount: number, isMobile: boolean): string | undefined {
|
||||
if (!isMobile || labelCount <= 0) return undefined;
|
||||
const perPoint = 56;
|
||||
const minWidth = Math.min(labelCount * perPoint, 3000);
|
||||
return `${minWidth}px`;
|
||||
}
|
||||
6
src/utils/usage/index.ts
Normal file
6
src/utils/usage/index.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
// Chart configuration utilities
|
||||
export { sparklineOptions, buildChartOptions, getHourChartMinWidth } from './chartConfig';
|
||||
export type { ChartConfigOptions } from './chartConfig';
|
||||
|
||||
// Re-export everything from the main usage.ts for backwards compatibility
|
||||
export * from '../usage';
|
||||
Reference in New Issue
Block a user