导表
This commit is contained in:
parent
d5799d8d99
commit
559a296c3a
74
src/App.tsx
74
src/App.tsx
@ -50,6 +50,8 @@ const metricOptions = [
|
||||
{ key: 'dataCount', label: '数据量' },
|
||||
] as const;
|
||||
|
||||
const gridMetricOptions = metricOptions.filter((option) => option.key !== 'dataCount');
|
||||
|
||||
const metricShortLabels: Record<MetricKey, string> = {
|
||||
cost: '价',
|
||||
buildingArea: '建',
|
||||
@ -748,6 +750,7 @@ function App() {
|
||||
const [rightPanelCollapsed, setRightPanelCollapsed] = useState(false);
|
||||
const [statisticMenuOpen, setStatisticMenuOpen] = useState(false);
|
||||
const [metricMenuOpen, setMetricMenuOpen] = useState(false);
|
||||
const [gridContextMenuPosition, setGridContextMenuPosition] = useState<{ left: number; top: number } | null>(null);
|
||||
const [activeContentKey, setActiveContentKey] = useState<ContentKey>('geoLocation');
|
||||
const [treeByContent, setTreeByContent] = useState<Record<ContentKey, TreeNode[]>>({
|
||||
geoLocation: [],
|
||||
@ -1012,7 +1015,7 @@ function App() {
|
||||
],
|
||||
},
|
||||
{
|
||||
headerName: '样本统计值',
|
||||
headerName: `样本统计值(${pivotGridRowData.length})`,
|
||||
children: [
|
||||
{
|
||||
field: 'maxValue',
|
||||
@ -1069,7 +1072,7 @@ function App() {
|
||||
},
|
||||
];
|
||||
},
|
||||
[requestMetricKey],
|
||||
[pivotGridRowData.length, requestMetricKey],
|
||||
);
|
||||
const fitPivotGridColumns = useCallback(() => {
|
||||
window.requestAnimationFrame(() => {
|
||||
@ -1082,6 +1085,29 @@ function App() {
|
||||
});
|
||||
});
|
||||
}, []);
|
||||
const exportPivotGrid = useCallback(() => {
|
||||
pivotGridApiRef.current?.exportDataAsCsv({ fileName: '建筑设施对象统计表.csv' });
|
||||
setGridContextMenuPosition(null);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!gridContextMenuPosition) return;
|
||||
|
||||
const closeMenu = () => setGridContextMenuPosition(null);
|
||||
const handleKeyDown = (event: KeyboardEvent) => {
|
||||
if (event.key === 'Escape') closeMenu();
|
||||
};
|
||||
document.addEventListener('mousedown', closeMenu);
|
||||
document.addEventListener('keydown', handleKeyDown);
|
||||
window.addEventListener('blur', closeMenu);
|
||||
window.addEventListener('resize', closeMenu);
|
||||
return () => {
|
||||
document.removeEventListener('mousedown', closeMenu);
|
||||
document.removeEventListener('keydown', handleKeyDown);
|
||||
window.removeEventListener('blur', closeMenu);
|
||||
window.removeEventListener('resize', closeMenu);
|
||||
};
|
||||
}, [gridContextMenuPosition]);
|
||||
const selectedNodeKeys = useMemo(
|
||||
() => new Set(selectedContentNodes.map((node) => getSelectionKey(node.contentKey, node.id))),
|
||||
[selectedContentNodes],
|
||||
@ -1654,9 +1680,16 @@ function App() {
|
||||
};
|
||||
|
||||
const togglePivotView = useCallback(() => {
|
||||
setChartViewKey((current) => (current === 'trend' ? 'pivot' : 'trend'));
|
||||
setChartViewKey((current) => {
|
||||
if (current === 'trend') {
|
||||
setMetricKey((selectedKey) => selectedKey === 'dataCount' ? metricOptions[0].key : selectedKey);
|
||||
return 'pivot';
|
||||
}
|
||||
return 'trend';
|
||||
});
|
||||
setMetricMenuOpen(false);
|
||||
setStatisticMenuOpen(false);
|
||||
setGridContextMenuPosition(null);
|
||||
}, []);
|
||||
|
||||
const toggleWorkspaceFullscreen = useCallback(() => {
|
||||
@ -1926,10 +1959,6 @@ function App() {
|
||||
handleToolbarAction(button);
|
||||
};
|
||||
|
||||
const suppressBrowserContextMenu = (event: MouseEvent) => {
|
||||
event.preventDefault();
|
||||
};
|
||||
|
||||
const observer = new MutationObserver(syncToolbarButtons);
|
||||
const initialSyncTimers = [
|
||||
window.setTimeout(syncToolbarButtons, 0),
|
||||
@ -1939,8 +1968,6 @@ function App() {
|
||||
];
|
||||
document.addEventListener('keydown', handleKeyDown, true);
|
||||
document.addEventListener('fullscreenchange', handleFullscreenChange);
|
||||
document.addEventListener('contextmenu', suppressBrowserContextMenu);
|
||||
frame.addEventListener('contextmenu', suppressBrowserContextMenu);
|
||||
frame.addEventListener('click', handleToolbarClick, true);
|
||||
frame.addEventListener('keydown', handleToolbarKeyDown, true);
|
||||
observer.observe(frame, { childList: true, subtree: true });
|
||||
@ -1950,8 +1977,6 @@ function App() {
|
||||
initialSyncTimers.forEach((timer) => window.clearTimeout(timer));
|
||||
document.removeEventListener('keydown', handleKeyDown, true);
|
||||
document.removeEventListener('fullscreenchange', handleFullscreenChange);
|
||||
document.removeEventListener('contextmenu', suppressBrowserContextMenu);
|
||||
frame.removeEventListener('contextmenu', suppressBrowserContextMenu);
|
||||
frame.removeEventListener('click', handleToolbarClick, true);
|
||||
frame.removeEventListener('keydown', handleToolbarKeyDown, true);
|
||||
observer.disconnect();
|
||||
@ -2217,7 +2242,7 @@ function App() {
|
||||
</button>
|
||||
{metricMenuOpen ? (
|
||||
<div className="metric-switcher-menu" role="menu" aria-label="切换纵坐标指标">
|
||||
{metricOptions.map((option) => (
|
||||
{(variant === 'grid' ? gridMetricOptions : metricOptions).map((option) => (
|
||||
<button
|
||||
className="metric-switcher-menu-item"
|
||||
type="button"
|
||||
@ -2325,7 +2350,30 @@ function App() {
|
||||
{loading || loadError ? <div className="chart-status">{loading ? loadingHint || '加载中' : loadError}</div> : null}
|
||||
<AgCharts options={chartOptions} />
|
||||
{chartViewKey === 'pivot' ? (
|
||||
<div className="chart-pivot-grid-panel ag-theme-quartz">
|
||||
<div
|
||||
className="chart-pivot-grid-panel ag-theme-quartz"
|
||||
onContextMenu={(event) => {
|
||||
event.preventDefault();
|
||||
setMetricMenuOpen(false);
|
||||
setStatisticMenuOpen(false);
|
||||
setGridContextMenuPosition({
|
||||
left: Math.max(8, Math.min(event.clientX, window.innerWidth - 132)),
|
||||
top: Math.max(8, Math.min(event.clientY, window.innerHeight - 44)),
|
||||
});
|
||||
}}
|
||||
>
|
||||
{gridContextMenuPosition ? (
|
||||
<div
|
||||
className="grid-context-menu"
|
||||
role="menu"
|
||||
style={gridContextMenuPosition}
|
||||
onMouseDown={(event) => event.stopPropagation()}
|
||||
>
|
||||
<button type="button" role="menuitem" onClick={exportPivotGrid}>
|
||||
导出表格
|
||||
</button>
|
||||
</div>
|
||||
) : null}
|
||||
<button
|
||||
className="chart-grid-tool-button chart-grid-tool-button--template"
|
||||
type="button"
|
||||
|
||||
@ -452,6 +452,39 @@ button {
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.grid-context-menu {
|
||||
position: fixed;
|
||||
z-index: 50;
|
||||
min-width: 128px;
|
||||
padding: 4px;
|
||||
border: 1px solid rgba(90, 82, 72, 0.22);
|
||||
border-radius: 3px;
|
||||
background: #fffaf4;
|
||||
box-shadow: 0 6px 18px rgba(69, 54, 36, 0.18);
|
||||
}
|
||||
|
||||
.grid-context-menu button {
|
||||
display: block;
|
||||
width: 100%;
|
||||
min-height: 32px;
|
||||
padding: 0 10px;
|
||||
border: 0;
|
||||
border-radius: 2px;
|
||||
color: #262a33;
|
||||
background: transparent;
|
||||
font-size: 13px;
|
||||
line-height: 32px;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.grid-context-menu button:hover,
|
||||
.grid-context-menu button:focus-visible {
|
||||
color: #0078a8;
|
||||
background: rgba(0, 120, 168, 0.08);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.chart-grid-tool-button {
|
||||
position: absolute;
|
||||
left: 24px;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user