时间范围联动数据:Dashboard 管理 rangeKey 状态,useDashboardData 按天数生成 dailyStats
This commit is contained in:
parent
d2913ff260
commit
65c28251f9
|
|
@ -48,9 +48,10 @@ const BentoTrend = ({
|
||||||
className = '',
|
className = '',
|
||||||
onRefresh,
|
onRefresh,
|
||||||
loading = false,
|
loading = false,
|
||||||
|
rangeKey = '7d',
|
||||||
|
onRangeChange,
|
||||||
}) => {
|
}) => {
|
||||||
const [rangeOpen, setRangeOpen] = useState(false);
|
const [rangeOpen, setRangeOpen] = useState(false);
|
||||||
const [selectedKey, setSelectedKey] = useState('7d');
|
|
||||||
const [customStart, setCustomStart] = useState('');
|
const [customStart, setCustomStart] = useState('');
|
||||||
const [customEnd, setCustomEnd] = useState('');
|
const [customEnd, setCustomEnd] = useState('');
|
||||||
const [tooltip, setTooltip] = useState(null); // { dayIdx, x, y } or null
|
const [tooltip, setTooltip] = useState(null); // { dayIdx, x, y } or null
|
||||||
|
|
@ -67,11 +68,11 @@ const BentoTrend = ({
|
||||||
return () => document.removeEventListener('mousedown', handler);
|
return () => document.removeEventListener('mousedown', handler);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const selectedLabel = RANGE_OPTIONS.find((r) => r.key === selectedKey)?.label || '近 7 天';
|
const selectedLabel = RANGE_OPTIONS.find((r) => r.key === rangeKey)?.label || '近 7 天';
|
||||||
|
|
||||||
const handleApply = () => {
|
const handleApply = () => {
|
||||||
if (customStart && customEnd) {
|
if (customStart && customEnd) {
|
||||||
setSelectedKey('custom');
|
onRangeChange('custom');
|
||||||
}
|
}
|
||||||
setRangeOpen(false);
|
setRangeOpen(false);
|
||||||
};
|
};
|
||||||
|
|
@ -150,13 +151,13 @@ const BentoTrend = ({
|
||||||
<button
|
<button
|
||||||
key={opt.key}
|
key={opt.key}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setSelectedKey(opt.key);
|
onRangeChange(opt.key);
|
||||||
setCustomStart('');
|
setCustomStart('');
|
||||||
setCustomEnd('');
|
setCustomEnd('');
|
||||||
setRangeOpen(false);
|
setRangeOpen(false);
|
||||||
}}
|
}}
|
||||||
className={`w-full rounded-lg px-3 py-1.5 text-left text-xs transition-colors ${
|
className={`w-full rounded-lg px-3 py-1.5 text-left text-xs transition-colors ${
|
||||||
selectedKey === opt.key
|
rangeKey === opt.key
|
||||||
? 'bg-blue-50 font-medium text-blue-700 dark:bg-blue-500/10 dark:text-blue-400'
|
? 'bg-blue-50 font-medium text-blue-700 dark:bg-blue-500/10 dark:text-blue-400'
|
||||||
: 'text-slate-600 hover:bg-slate-50 dark:text-white/60 dark:hover:bg-white/5'
|
: 'text-slate-600 hover:bg-slate-50 dark:text-white/60 dark:hover:bg-white/5'
|
||||||
}`}
|
}`}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
For commercial licensing, please contact support@quantumnous.com
|
For commercial licensing, please contact support@quantumnous.com
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useContext } from 'react';
|
import React, { useContext, useState } from 'react';
|
||||||
import { UserContext } from '../../context/User';
|
import { UserContext } from '../../context/User';
|
||||||
import { useUserMessageUnreadCount } from '../../hooks/common/useUserMessageUnreadCount';
|
import { useUserMessageUnreadCount } from '../../hooks/common/useUserMessageUnreadCount';
|
||||||
import { useDashboardData } from '../../hooks/dashboard/useDashboardData';
|
import { useDashboardData } from '../../hooks/dashboard/useDashboardData';
|
||||||
|
|
@ -30,11 +30,23 @@ import BentoTrend from './BentoTrend';
|
||||||
import MonthlyForecast from './MonthlyForecast';
|
import MonthlyForecast from './MonthlyForecast';
|
||||||
import RecentActivity from './RecentActivity';
|
import RecentActivity from './RecentActivity';
|
||||||
|
|
||||||
|
const RANGE_DAYS = {
|
||||||
|
today: 1,
|
||||||
|
yesterday: 1,
|
||||||
|
'24h': 1,
|
||||||
|
'7d': 7,
|
||||||
|
'14d': 14,
|
||||||
|
'30d': 30,
|
||||||
|
};
|
||||||
|
|
||||||
const Dashboard = () => {
|
const Dashboard = () => {
|
||||||
const [userState] = useContext(UserContext);
|
const [userState] = useContext(UserContext);
|
||||||
const user = userState?.user;
|
const user = userState?.user;
|
||||||
|
const [rangeKey, setRangeKey] = useState('7d');
|
||||||
|
|
||||||
const dashboard = useDashboardData(userState);
|
const rangeDays = RANGE_DAYS[rangeKey] || 7;
|
||||||
|
|
||||||
|
const dashboard = useDashboardData(userState, rangeDays);
|
||||||
const { unreadCount } = useUserMessageUnreadCount(user);
|
const { unreadCount } = useUserMessageUnreadCount(user);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -66,6 +78,8 @@ const Dashboard = () => {
|
||||||
topModels={dashboard.topModels}
|
topModels={dashboard.topModels}
|
||||||
onRefresh={dashboard.refresh}
|
onRefresh={dashboard.refresh}
|
||||||
loading={dashboard.loading}
|
loading={dashboard.loading}
|
||||||
|
rangeKey={rangeKey}
|
||||||
|
onRangeChange={setRangeKey}
|
||||||
className='md:col-span-2'
|
className='md:col-span-2'
|
||||||
/>
|
/>
|
||||||
<MonthlyForecast
|
<MonthlyForecast
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ const isSuccess = (l) =>
|
||||||
const sum = (arr, key) =>
|
const sum = (arr, key) =>
|
||||||
arr.reduce((s, l) => s + (Number(l[key]) || 0), 0);
|
arr.reduce((s, l) => s + (Number(l[key]) || 0), 0);
|
||||||
|
|
||||||
export const useDashboardData = (userState) => {
|
export const useDashboardData = (userState, rangeDays = 7) => {
|
||||||
const initialized = useRef(false);
|
const initialized = useRef(false);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [recentLogs, setRecentLogs] = useState([]);
|
const [recentLogs, setRecentLogs] = useState([]);
|
||||||
|
|
@ -138,7 +138,7 @@ export const useDashboardData = (userState) => {
|
||||||
const dailyStats = useMemo(() => {
|
const dailyStats = useMemo(() => {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const days = [];
|
const days = [];
|
||||||
const n = 7;
|
const n = rangeDays;
|
||||||
for (let i = n - 1; i >= 0; i--) {
|
for (let i = n - 1; i >= 0; i--) {
|
||||||
const d = new Date(now.getFullYear(), now.getMonth(), now.getDate() - i);
|
const d = new Date(now.getFullYear(), now.getMonth(), now.getDate() - i);
|
||||||
const dayStart = Math.floor(d.getTime() / 1000);
|
const dayStart = Math.floor(d.getTime() / 1000);
|
||||||
|
|
@ -160,7 +160,7 @@ export const useDashboardData = (userState) => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return days;
|
return days;
|
||||||
}, [recentLogs]);
|
}, [recentLogs, rangeDays]);
|
||||||
|
|
||||||
// ========== MoM delta (this month cost vs last month) ==========
|
// ========== MoM delta (this month cost vs last month) ==========
|
||||||
const monthDelta = useMemo(() => {
|
const monthDelta = useMemo(() => {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue