feat: 添加按日期查询用电记录功能,支持切换查看历史用电趋势
1. 新增/api/records-by-date后端接口,支持按日期查询详细用电记录并计算当日用量和费用 2. 前端新增日期选择器,支持切换查看指定日期的用电趋势 3. 更新README文档,补充功能说明、配置项和接口文档 4. 新增.trae目录到gitignore 5. 引入IconPack图标库和dayjs日期处理库
This commit is contained in:
@@ -37,3 +37,9 @@ export async function triggerCollect() {
|
||||
if (res.status === 401) throw new Error('未登录');
|
||||
return res.json();
|
||||
}
|
||||
|
||||
export async function fetchRecordsByDate(dateStr) {
|
||||
const res = await fetch(`${BASE}/records-by-date?date=${dateStr}`);
|
||||
if (res.status === 401) throw new Error('未登录');
|
||||
return res.json();
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { useState, useEffect, useCallback, useRef } from 'react';
|
||||
import { Button, Spin, message } from 'antd';
|
||||
import { Button, Spin, message, DatePicker } from 'antd';
|
||||
import { LogoutOutlined, ReloadOutlined, BugOutlined } from '@ant-design/icons';
|
||||
import { Lightning, ChartLine, ChartHistogram, Timer } from '@icon-park/react';
|
||||
import { Chart, registerables } from 'chart.js';
|
||||
import { fetchCurrent, fetchHistory, triggerCollect, logout } from '../api';
|
||||
import dayjs from 'dayjs';
|
||||
import { fetchCurrent, fetchHistory, triggerCollect, logout, fetchRecordsByDate } from '../api';
|
||||
|
||||
Chart.register(...registerables);
|
||||
|
||||
@@ -34,6 +35,10 @@ export default function Dashboard({ onLogout }) {
|
||||
const [days, setDays] = useState(30);
|
||||
const [collecting, setCollecting] = useState(false);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [chartDate, setChartDate] = useState(dayjs().format('YYYY-MM-DD'));
|
||||
const [dateRecords, setDateRecords] = useState(null);
|
||||
const [datePrevLast, setDatePrevLast] = useState(null);
|
||||
const [isToday, setIsToday] = useState(true);
|
||||
|
||||
const hourlyChartRef = useRef(null);
|
||||
const trendChartRef = useRef(null);
|
||||
@@ -63,6 +68,17 @@ export default function Dashboard({ onLogout }) {
|
||||
};
|
||||
}, [loadData]);
|
||||
|
||||
useEffect(() => {
|
||||
const today = dayjs().format('YYYY-MM-DD');
|
||||
setIsToday(chartDate === today);
|
||||
fetchRecordsByDate(chartDate).then(data => {
|
||||
if (data.success) {
|
||||
setDateRecords(data.records);
|
||||
setDatePrevLast(data.prevLastRecord);
|
||||
}
|
||||
});
|
||||
}, [chartDate]);
|
||||
|
||||
const handleCollect = async () => {
|
||||
setCollecting(true);
|
||||
try {
|
||||
@@ -110,11 +126,12 @@ export default function Dashboard({ onLogout }) {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!currentData?.todayRecords || currentData.todayRecords.length === 0) return;
|
||||
const records = isToday ? currentData?.todayRecords : dateRecords;
|
||||
const prev = isToday ? currentData?.yesterdayLastRecord : datePrevLast;
|
||||
if (!records || records.length === 0) return;
|
||||
hourlyInstance.current?.destroy();
|
||||
|
||||
const sorted = [...currentData.todayRecords].sort((a, b) => a.timestamp - b.timestamp);
|
||||
const prev = currentData.yesterdayLastRecord;
|
||||
const sorted = [...records].sort((a, b) => a.timestamp - b.timestamp);
|
||||
const labels = sorted.map(r => formatTime(r.timestamp));
|
||||
const values = sorted.map((r, i) => {
|
||||
const prevRecord = i === 0 ? prev : sorted[i - 1];
|
||||
@@ -179,7 +196,7 @@ export default function Dashboard({ onLogout }) {
|
||||
interaction: { intersect: false, mode: 'index' },
|
||||
},
|
||||
});
|
||||
}, [currentData]);
|
||||
}, [currentData, dateRecords, datePrevLast, isToday]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!historyData?.dailyRecords || historyData.dailyRecords.length === 0) return;
|
||||
@@ -408,13 +425,20 @@ body { margin: 0; }
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 16, fontWeight: 600, color: 'var(--text-primary)' }}>
|
||||
<ChartLine theme="filled" size="20" fill="#4a90e2" style={{ display: 'flex' }} />
|
||||
今日用电趋势
|
||||
用电趋势
|
||||
<span style={{ fontSize: 13, color: 'var(--text-tertiary)', fontWeight: 400 }}>(每时段)</span>
|
||||
</div>
|
||||
<DatePicker
|
||||
value={dayjs(chartDate)}
|
||||
onChange={(d) => d && setChartDate(d.format('YYYY-MM-DD'))}
|
||||
allowClear={false}
|
||||
size="small"
|
||||
style={{ width: 130 }}
|
||||
/>
|
||||
</div>
|
||||
<div className="d-chart" style={{ position: 'relative', height: 280, background: 'var(--bg-chart)', borderRadius: 8, padding: 20 }}>
|
||||
{(!currentData?.todayRecords || currentData.todayRecords.length === 0) ? (
|
||||
<div className="d-chart-empty" style={{ textAlign: 'center', paddingTop: 110, color: 'var(--text-tertiary)' }}>暂无今日数据</div>
|
||||
{(!isToday && (!dateRecords || dateRecords.length === 0)) || (isToday && (!currentData?.todayRecords || currentData.todayRecords.length === 0)) ? (
|
||||
<div className="d-chart-empty" style={{ textAlign: 'center', paddingTop: 110, color: 'var(--text-tertiary)' }}>暂无数据</div>
|
||||
) : null}
|
||||
<canvas ref={hourlyChartRef} />
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user