65 lines
2.1 KiB
JavaScript
65 lines
2.1 KiB
JavaScript
import { useCallback, useEffect, useRef, useState } from "react";
|
|
import { EChart } from "../charts/EChart.jsx";
|
|
import { createMetricTrendOption } from "../charts/options/createMetricTrendOption.js";
|
|
|
|
const MODAL_TRANSITION_MS = 180;
|
|
|
|
export function MetricTrendModal({ item, onClose }) {
|
|
const [closing, setClosing] = useState(false);
|
|
const closeTimerRef = useRef(null);
|
|
const requestClose = useCallback(() => {
|
|
if (closing) {
|
|
return;
|
|
}
|
|
setClosing(true);
|
|
closeTimerRef.current = window.setTimeout(onClose, MODAL_TRANSITION_MS);
|
|
}, [closing, onClose]);
|
|
|
|
useEffect(() => () => {
|
|
if (closeTimerRef.current) {
|
|
window.clearTimeout(closeTimerRef.current);
|
|
}
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
const closeOnEscape = (event) => {
|
|
if (event.key === "Escape") {
|
|
requestClose();
|
|
}
|
|
};
|
|
window.addEventListener("keydown", closeOnEscape);
|
|
return () => window.removeEventListener("keydown", closeOnEscape);
|
|
}, [requestClose]);
|
|
|
|
return (
|
|
<div
|
|
className={["metric-trend-modal", closing ? "is-closing" : ""].filter(Boolean).join(" ")}
|
|
role="presentation"
|
|
onMouseDown={(event) => {
|
|
if (event.target === event.currentTarget) {
|
|
requestClose();
|
|
}
|
|
}}
|
|
>
|
|
<section aria-label={`${item.label} 每日趋势`} aria-modal="true" className="metric-trend-dialog" role="dialog">
|
|
<header className="metric-trend-head">
|
|
<div>
|
|
<h2>{item.label}</h2>
|
|
<span>每日折线图</span>
|
|
</div>
|
|
<button aria-label="关闭每日趋势" type="button" onClick={requestClose}>
|
|
<span aria-hidden="true" className="modal-close-mark" />
|
|
</button>
|
|
</header>
|
|
<div className="metric-trend-body">
|
|
{hasTrend(item) ? <EChart className="metric-trend-chart" option={createMetricTrendOption(item)} /> : <div className="panel-empty">暂无趋势数据</div>}
|
|
</div>
|
|
</section>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function hasTrend(item) {
|
|
return Array.isArray(item?.trend) && item.trend.some((line) => Array.isArray(line.data) && line.data.length);
|
|
}
|