优化
This commit is contained in:
parent
38978befb7
commit
a891b5bccb
57
src/App.tsx
57
src/App.tsx
@ -21,7 +21,6 @@ const statisticOptions = [
|
||||
{ key: 'maxValue', label: '最高值', shortLabel: '高' },
|
||||
{ key: 'avgValue', label: '平均值', shortLabel: '均' },
|
||||
{ key: 'medianValue', label: '中位数', shortLabel: '中' },
|
||||
{ key: 'dataCount', label: '数据量', shortLabel: '量' },
|
||||
] as const;
|
||||
|
||||
const metricOptions = [
|
||||
@ -29,6 +28,7 @@ const metricOptions = [
|
||||
{ key: 'buildingArea', label: '建筑面积指标(元/m²)' },
|
||||
{ key: 'builtArea', label: '建造面积指标(元/m²)' },
|
||||
{ key: 'usableArea', label: '使用面积指标(元/m²)' },
|
||||
{ key: 'dataCount', label: '数据量' },
|
||||
] as const;
|
||||
|
||||
const contentOptions = [
|
||||
@ -179,8 +179,8 @@ function formatAreaMetricValue(value: number) {
|
||||
return `${formatNumber(value, fractionDigits)}元/m²`;
|
||||
}
|
||||
|
||||
function formatChartValue(value: number, metricKey: MetricKey, statisticKey: StatisticKey) {
|
||||
if (statisticKey === 'dataCount') {
|
||||
function formatChartValue(value: number, metricKey: MetricKey) {
|
||||
if (metricKey === 'dataCount') {
|
||||
return formatNumber(value, 0);
|
||||
}
|
||||
if (metricKey === 'cost') {
|
||||
@ -306,7 +306,7 @@ function renderTreeNodes(
|
||||
<ul className="content-tree-list" role={depth === 0 ? 'tree' : 'group'}>
|
||||
{nodes.map((node) => {
|
||||
const selected = selectedNodeKeys.has(getSelectionKey(contentKey, node.id));
|
||||
const color = node.canClick ? getNodeColor(contentKey, node.id) : undefined;
|
||||
const color = getNodeColor(contentKey, node.id);
|
||||
|
||||
return (
|
||||
<li className="content-tree-node" role="treeitem" aria-expanded={node.hasChildren ? node.expanded : undefined} key={node.id}>
|
||||
@ -322,13 +322,10 @@ function renderTreeNodes(
|
||||
className="content-tree-select"
|
||||
type="button"
|
||||
aria-pressed={selected}
|
||||
disabled={!node.canClick}
|
||||
onClick={() => {
|
||||
if (node.canClick) onSelect(node);
|
||||
}}
|
||||
onClick={() => onSelect(node)}
|
||||
title={node.label}
|
||||
>
|
||||
{node.canClick ? <span className="content-tree-series-mark" style={{ backgroundColor: color }} /> : null}
|
||||
<span className="content-tree-series-mark" style={{ backgroundColor: color }} />
|
||||
<span className="content-tree-label">{node.label}</span>
|
||||
</button>
|
||||
{node.loading ? <span className="content-tree-loading">加载中</span> : null}
|
||||
@ -387,6 +384,9 @@ function App() {
|
||||
const selectedMetric = metricOptions.find((option) => option.key === metricKey) ?? metricOptions[0];
|
||||
const activeContent = contentOptions.find((option) => option.key === activeContentKey) ?? contentOptions[0];
|
||||
const activeTree = treeByContent[activeContentKey];
|
||||
const selectedValueKey = metricKey === 'dataCount' ? 'dataCount' : statisticKey;
|
||||
const requestMetricKey = metricKey === 'dataCount' ? 'cost' : metricKey;
|
||||
const seriesValueLabel = metricKey === 'dataCount' ? selectedMetric.label : selectedStatistic.label;
|
||||
const selectedNodeKeys = useMemo(
|
||||
() => new Set(selectedContentNodes.map((node) => getSelectionKey(node.contentKey, node.id))),
|
||||
[selectedContentNodes],
|
||||
@ -536,6 +536,16 @@ function App() {
|
||||
});
|
||||
};
|
||||
|
||||
const handleActiveContentKeyChange = (nextContentKey: ContentKey) => {
|
||||
if (nextContentKey === activeContentKey) return;
|
||||
setActiveContentKey(nextContentKey);
|
||||
setSelectedContentNodes([]);
|
||||
setChartDataBySelection({});
|
||||
setLoadError(null);
|
||||
setLoadingHint('');
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
const updateMetricKey = (nextMetricKey: MetricKey) => {
|
||||
setMetricKey(nextMetricKey);
|
||||
setChartDataBySelection({});
|
||||
@ -599,12 +609,12 @@ function App() {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
groupBy: groupKey,
|
||||
metric: metricKey,
|
||||
nodes: selectedContentNodes.map((node) => ({
|
||||
key: getSelectionKey(node.contentKey, node.id),
|
||||
contentKey: node.contentKey,
|
||||
body: JSON.stringify({
|
||||
groupBy: groupKey,
|
||||
metric: requestMetricKey,
|
||||
nodes: selectedContentNodes.map((node) => ({
|
||||
key: getSelectionKey(node.contentKey, node.id),
|
||||
contentKey: node.contentKey,
|
||||
nodeId: node.id,
|
||||
})),
|
||||
}),
|
||||
@ -636,7 +646,7 @@ function App() {
|
||||
return () => {
|
||||
controller.abort();
|
||||
};
|
||||
}, [chartQueryVersion, groupKey, metricKey, selectedContentNodes]);
|
||||
}, [chartQueryVersion, groupKey, metricKey, requestMetricKey, selectedContentNodes]);
|
||||
|
||||
useEffect(() => {
|
||||
const frame = chartFrameRef.current;
|
||||
@ -751,7 +761,6 @@ function App() {
|
||||
}, [statisticMenuOpen]);
|
||||
|
||||
const chartOptions = useMemo<AgCartesianChartOptions>(() => {
|
||||
const isCount = statisticKey === 'dataCount';
|
||||
const groupNames: string[] = [];
|
||||
const groupNameSeen = new Set<string>();
|
||||
selectedContentNodes.forEach((node) => {
|
||||
@ -766,7 +775,7 @@ function App() {
|
||||
const row: Record<string, string | number | null> = { groupName };
|
||||
selectedContentNodes.forEach((node, index) => {
|
||||
const datum = chartDataBySelection[getSelectionKey(node.contentKey, node.id)]?.find((item) => item.groupName === groupName);
|
||||
row[getSeriesValueKey(index)] = datum?.[statisticKey] ?? null;
|
||||
row[getSeriesValueKey(index)] = datum?.[selectedValueKey] ?? null;
|
||||
});
|
||||
return row;
|
||||
});
|
||||
@ -866,7 +875,7 @@ function App() {
|
||||
type: 'line',
|
||||
xKey: 'groupName',
|
||||
yKey: getSeriesValueKey(index),
|
||||
yName: `${node.label} ${selectedStatistic.label}`,
|
||||
yName: `${node.label} ${seriesValueLabel}`,
|
||||
stroke: node.color,
|
||||
strokeWidth: 2,
|
||||
marker: {
|
||||
@ -882,7 +891,7 @@ function App() {
|
||||
renderer: ({ datum, yKey, yName }) => ({
|
||||
title: yName,
|
||||
data: [
|
||||
{ label: selectedMetric.label, value: formatChartValue(Number(datum[yKey]), metricKey, statisticKey) },
|
||||
{ label: selectedMetric.label, value: formatChartValue(Number(datum[yKey]), metricKey) },
|
||||
],
|
||||
}),
|
||||
},
|
||||
@ -915,7 +924,7 @@ function App() {
|
||||
label: {
|
||||
color: '#1f2933',
|
||||
fontSize: 12,
|
||||
formatter: ({ value }) => formatChartValue(Number(value), metricKey, statisticKey),
|
||||
formatter: ({ value }) => formatChartValue(Number(value), metricKey),
|
||||
},
|
||||
line: {
|
||||
enabled: false,
|
||||
@ -942,9 +951,11 @@ function App() {
|
||||
},
|
||||
tooltip: {
|
||||
enabled: true,
|
||||
mode: 'shared',
|
||||
pagination: true,
|
||||
},
|
||||
};
|
||||
}, [chartDataBySelection, metricKey, selectedContentNodes, selectedMetric.label, selectedStatistic.label, statisticKey]);
|
||||
}, [chartDataBySelection, metricKey, requestMetricKey, selectedContentNodes, selectedMetric.label, seriesValueLabel, selectedValueKey, statisticKey]);
|
||||
|
||||
return (
|
||||
<main className="dashboard-shell">
|
||||
@ -1033,7 +1044,7 @@ function App() {
|
||||
role="tab"
|
||||
key={option.key}
|
||||
aria-selected={option.key === activeContentKey}
|
||||
onClick={() => setActiveContentKey(option.key)}
|
||||
onClick={() => handleActiveContentKeyChange(option.key)}
|
||||
>
|
||||
{option.label}
|
||||
</button>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user