1
@ -21,3 +21,30 @@
|
|||||||
[ 807915ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
[ 807915ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
[ 809704ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
[ 809704ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
[ 809719ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
[ 809719ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 1130928ms] [INFO] %cDownload the React DevTools for a better development experience: https://react.dev/link/react-devtools font-weight:bold @ http://localhost:5174/node_modules/.vite/deps/react-dom_client.js?v=2852bbef:20102
|
||||||
|
[ 1131032ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 1131104ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 1131280ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 1135080ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 1159795ms] [INFO] %cDownload the React DevTools for a better development experience: https://react.dev/link/react-devtools font-weight:bold @ http://localhost:5174/node_modules/.vite/deps/react-dom_client.js?v=2852bbef:20102
|
||||||
|
[ 1159877ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 1159909ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 1160035ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 1161960ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 1217476ms] [INFO] %cDownload the React DevTools for a better development experience: https://react.dev/link/react-devtools font-weight:bold @ http://localhost:5174/node_modules/.vite/deps/react-dom_client.js?v=2852bbef:20102
|
||||||
|
[ 1217588ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 1217664ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 1217706ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 1221050ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 1222400ms] [INFO] %cDownload the React DevTools for a better development experience: https://react.dev/link/react-devtools font-weight:bold @ http://localhost:5174/node_modules/.vite/deps/react-dom_client.js?v=2852bbef:20102
|
||||||
|
[ 1222501ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 1222577ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 1222714ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 1251951ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 1481087ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 1606956ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 1609277ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 1610697ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 2630632ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 2682900ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 2683117ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
|||||||
30
.playwright-mcp/console-2026-05-07T02-28-20-118Z.log
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
[ 2749778ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 2749924ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 2949730ms] [INFO] %cDownload the React DevTools for a better development experience: https://react.dev/link/react-devtools font-weight:bold @ http://localhost:5174/node_modules/.vite/deps/react-dom_client.js?v=2852bbef:20102
|
||||||
|
[ 2949812ms] Error: Target container is not a DOM element.
|
||||||
|
at exports.createRoot (http://localhost:5174/node_modules/.vite/deps/react-dom_client.js?v=2852bbef:20110:17)
|
||||||
|
at http://localhost:5174/src/main.tsx?t=1778123649466:8:1
|
||||||
|
[ 2963427ms] [INFO] %cDownload the React DevTools for a better development experience: https://react.dev/link/react-devtools font-weight:bold @ http://localhost:5174/node_modules/.vite/deps/react-dom_client.js?v=2852bbef:20102
|
||||||
|
[ 2963551ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 2963676ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 2963871ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 3837344ms] [INFO] %cDownload the React DevTools for a better development experience: https://react.dev/link/react-devtools font-weight:bold @ http://localhost:5174/node_modules/.vite/deps/react-dom_client.js?v=2852bbef:20102
|
||||||
|
[ 3837478ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 3837562ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 3837717ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 4034117ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 4034271ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 4870001ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 4870144ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 4901299ms] [INFO] %cDownload the React DevTools for a better development experience: https://react.dev/link/react-devtools font-weight:bold @ http://localhost:5174/node_modules/.vite/deps/react-dom_client.js?v=2852bbef:20102
|
||||||
|
[ 4901407ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 4901477ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 4901535ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 4911798ms] [INFO] %cDownload the React DevTools for a better development experience: https://react.dev/link/react-devtools font-weight:bold @ http://localhost:5174/node_modules/.vite/deps/react-dom_client.js?v=2852bbef:20102
|
||||||
|
[ 4911890ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 4911967ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 4912020ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 5117456ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 5117598ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 5342970ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 5443217ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://localhost:5174/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
5
.playwright-mcp/console-2026-05-07T07-18-02-154Z.log
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[ 773ms] [INFO] %cDownload the React DevTools for a better development experience: https://react.dev/link/react-devtools font-weight:bold @ http://127.0.0.1:5173/node_modules/.vite/deps/react-dom_client.js?v=2852bbef:20102
|
||||||
|
[ 893ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://127.0.0.1:5173/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 1181ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://127.0.0.1:5173/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 1214ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"statistic-select"`; expecting a keyword such as 'line-menu', 'fibonacci-menu', 'text-menu', 'shape-menu', 'measurer-menu', 'line', 'horizontal-line', 'vertical-line', 'parallel-channel', 'disjoint-channel', 'fibonacci-retracement', 'fibonacci-retracement-trend-based', 'text', 'comment', 'callout', 'note' or 'clear', ignoring. @ http://127.0.0.1:5173/node_modules/.vite/deps/chunk-XDC3NMYR.js?v=2852bbef:834
|
||||||
|
[ 1220ms] [ERROR] Failed to load resource: the server responded with a status of 404 (Not Found) @ http://127.0.0.1:5173/favicon.ico:0
|
||||||
59
.playwright-mcp/page-2026-05-07T07-18-03-376Z.yml
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
- main [ref=e3]:
|
||||||
|
- generic:
|
||||||
|
- generic: 众为数字化管理平台
|
||||||
|
- generic: 众为数字化管理平台
|
||||||
|
- generic: 众为数字化管理平台
|
||||||
|
- generic: 众为数字化管理平台
|
||||||
|
- generic: 众为数字化管理平台
|
||||||
|
- generic: 众为数字化管理平台
|
||||||
|
- generic: 众为数字化管理平台
|
||||||
|
- generic: 众为数字化管理平台
|
||||||
|
- generic: 众为数字化管理平台
|
||||||
|
- generic: 众为数字化管理平台
|
||||||
|
- generic: 众为数字化管理平台
|
||||||
|
- generic: 众为数字化管理平台
|
||||||
|
- generic: 众为数字化管理平台
|
||||||
|
- generic: 众为数字化管理平台
|
||||||
|
- generic: 众为数字化管理平台
|
||||||
|
- generic: 众为数字化管理平台
|
||||||
|
- generic: 众为数字化管理平台
|
||||||
|
- generic: 众为数字化管理平台
|
||||||
|
- region "年度费用模板" [ref=e4]:
|
||||||
|
- region "年度总费用图表" [ref=e5]:
|
||||||
|
- generic [ref=e6]:
|
||||||
|
- button "纵坐标:造价(元)" [ref=e8] [cursor=pointer]: 造价(元)
|
||||||
|
- generic [ref=e9]: 请选择右侧分类项
|
||||||
|
- button "全屏(F11)" [ref=e10] [cursor=pointer]
|
||||||
|
- generic [ref=e12]:
|
||||||
|
- figure "图表,共有0个系列":
|
||||||
|
- generic [ref=e13]:
|
||||||
|
- img "interactive chart":
|
||||||
|
- generic:
|
||||||
|
- img
|
||||||
|
- img
|
||||||
|
- region [ref=e14]
|
||||||
|
- toolbar "标注" [ref=e15]:
|
||||||
|
- button "均" [disabled] [ref=e16]:
|
||||||
|
- generic: 均
|
||||||
|
- button "Line Tool" [disabled] [ref=e17]
|
||||||
|
- button "Text Tool" [disabled] [ref=e18]
|
||||||
|
- button "Shape Tool" [disabled] [ref=e19]
|
||||||
|
- button "Fibonacci Tool" [disabled] [ref=e20]
|
||||||
|
- button "Clear annotations" [disabled] [ref=e21]
|
||||||
|
- status:
|
||||||
|
- generic: 没有数据显示
|
||||||
|
- toolbar "缩放" [ref=e22]:
|
||||||
|
- button "缩小" [disabled] [ref=e23]
|
||||||
|
- button "放大" [ref=e24] [cursor=pointer]
|
||||||
|
- button "左移" [disabled] [ref=e25]
|
||||||
|
- button "右移" [disabled] [ref=e26]
|
||||||
|
- button "重置" [disabled] [ref=e27]
|
||||||
|
- complementary "选择内容" [ref=e28]:
|
||||||
|
- tablist "选择内容切换项" [ref=e29]:
|
||||||
|
- tab "自然地理区位" [selected] [ref=e30] [cursor=pointer]
|
||||||
|
- tab "设施类别" [ref=e31] [cursor=pointer]
|
||||||
|
- tab "建设阶段" [ref=e32] [cursor=pointer]
|
||||||
|
- tab "规划形式" [ref=e33] [cursor=pointer]
|
||||||
|
- generic [ref=e34]:
|
||||||
|
- generic [ref=e35]: 自然地理区位
|
||||||
|
- generic [ref=e36]: 加载中
|
||||||
|
Before Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 68 KiB |
BIN
chart-before.png
|
Before Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 73 KiB |
BIN
chart-tools.png
|
Before Width: | Height: | Size: 71 KiB |
BIN
chart-zoomed.png
|
Before Width: | Height: | Size: 73 KiB |
@ -6,7 +6,7 @@
|
|||||||
<title>AG Chart Service</title>
|
<title>AG Chart Service</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="zbChart"></div>
|
||||||
<script type="module" src="/src/main.tsx"></script>
|
<script type="module" src="/src/main.tsx"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 75 KiB |
|
Before Width: | Height: | Size: 74 KiB |
|
Before Width: | Height: | Size: 74 KiB |
|
Before Width: | Height: | Size: 74 KiB |
|
Before Width: | Height: | Size: 74 KiB |
|
Before Width: | Height: | Size: 74 KiB |
619
src/App.tsx
@ -31,8 +31,93 @@ const metricOptions = [
|
|||||||
{ key: 'usableArea', label: '使用面积指标(元/m²)' },
|
{ key: 'usableArea', label: '使用面积指标(元/m²)' },
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
|
const contentOptions = [
|
||||||
|
{ key: 'geoLocation', label: '自然地理区位' },
|
||||||
|
{ key: 'facilityType', label: '设施类别' },
|
||||||
|
{ key: 'constructionStage', label: '建设阶段' },
|
||||||
|
{ key: 'planningForm', label: '规划形式' },
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
const browserTreeDefaults = {
|
||||||
|
treetype: '256',
|
||||||
|
checkStrictly: 'true',
|
||||||
|
requestid: '-1',
|
||||||
|
workflowid: '181028',
|
||||||
|
wfid: '181028',
|
||||||
|
billid: '-1812',
|
||||||
|
isbill: '1',
|
||||||
|
f_weaver_belongto_userid: '267',
|
||||||
|
f_weaver_belongto_usertype: '0',
|
||||||
|
wf_isagent: '0',
|
||||||
|
wf_beagenter: '0',
|
||||||
|
wfTestStr: '',
|
||||||
|
viewtype: '1',
|
||||||
|
fromModule: 'workflow',
|
||||||
|
wfCreater: '267',
|
||||||
|
disabledConditionCache: 'true',
|
||||||
|
companyId: '1',
|
||||||
|
};
|
||||||
|
|
||||||
|
const contentTreeConfigs = {
|
||||||
|
geoLocation: {
|
||||||
|
endpoint: '/api/public/browser/data/256',
|
||||||
|
treeid: '94004',
|
||||||
|
fieldid: '305425',
|
||||||
|
defaultExpandedLevel: 1,
|
||||||
|
},
|
||||||
|
facilityType: {
|
||||||
|
endpoint: '/api/public/browser/data/256',
|
||||||
|
treeid: '94005',
|
||||||
|
fieldid: '305426',
|
||||||
|
defaultExpandedLevel: 3,
|
||||||
|
},
|
||||||
|
constructionStage: {
|
||||||
|
endpoint: '/api/public/browser/data/256',
|
||||||
|
treeid: '94007',
|
||||||
|
fieldid: '305428',
|
||||||
|
defaultExpandedLevel: 1,
|
||||||
|
},
|
||||||
|
planningForm: {
|
||||||
|
endpoint: '/api/public/browser/data/256',
|
||||||
|
treeid: '94006',
|
||||||
|
fieldid: '305427',
|
||||||
|
defaultExpandedLevel: 1,
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
const chartLineColors = ['#0078a8', '#d14d72', '#1f8f4d', '#d96f23', '#6b5cc8', '#0d7680', '#9a6b12', '#b24b38'];
|
||||||
|
|
||||||
|
// const mockGeoLocationPayload = {
|
||||||
|
// checkStrictly: true,
|
||||||
|
// type: 3,
|
||||||
|
// datas: [
|
||||||
|
// {
|
||||||
|
// allVersionIds: '',
|
||||||
|
// canClick: false,
|
||||||
|
// checkStrictly: true,
|
||||||
|
// dsporder: 0,
|
||||||
|
// icon: '',
|
||||||
|
// id: '95005_22',
|
||||||
|
// isImgIcon: false,
|
||||||
|
// isParent: true,
|
||||||
|
// linkUrl: '/formmode/search/CustomSearchOpenTree.jsp?pid=95005_22',
|
||||||
|
// name: '中国',
|
||||||
|
// pid: '0_0',
|
||||||
|
// selected: false,
|
||||||
|
// title: '中国',
|
||||||
|
// type: '2',
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// iconSetting: {
|
||||||
|
// bgColor: '#96358a',
|
||||||
|
// icon: 'icon-coms-ModelingEngine',
|
||||||
|
// fontColor: '#fff',
|
||||||
|
// },
|
||||||
|
// };
|
||||||
|
|
||||||
type StatisticKey = (typeof statisticOptions)[number]['key'];
|
type StatisticKey = (typeof statisticOptions)[number]['key'];
|
||||||
type MetricKey = (typeof metricOptions)[number]['key'];
|
type MetricKey = (typeof metricOptions)[number]['key'];
|
||||||
|
type ContentKey = (typeof contentOptions)[number]['key'];
|
||||||
type GroupKey = 'year';
|
type GroupKey = 'year';
|
||||||
type ApiBuildingFunctionStat = {
|
type ApiBuildingFunctionStat = {
|
||||||
group_key?: string | number | null;
|
group_key?: string | number | null;
|
||||||
@ -51,9 +136,30 @@ type ChartDatum = {
|
|||||||
medianValue: number | null;
|
medianValue: number | null;
|
||||||
dataCount: number | null;
|
dataCount: number | null;
|
||||||
};
|
};
|
||||||
|
type TreeNode = {
|
||||||
|
id: string;
|
||||||
|
label: string;
|
||||||
|
children: TreeNode[];
|
||||||
|
hasChildren: boolean;
|
||||||
|
canClick: boolean;
|
||||||
|
expanded: boolean;
|
||||||
|
loading: boolean;
|
||||||
|
loaded: boolean;
|
||||||
|
};
|
||||||
|
type SelectedContentNode = {
|
||||||
|
id: string;
|
||||||
|
contentKey: ContentKey;
|
||||||
|
label: string;
|
||||||
|
color: string;
|
||||||
|
};
|
||||||
|
|
||||||
function formatWan(value: number) {
|
function formatWan(value: number) {
|
||||||
return `${Math.round(value / 10000).toLocaleString('zh-CN')}万`;
|
const wanValue = value / 10000;
|
||||||
|
const fractionDigits = Math.abs(wanValue) < 1 ? 4 : 2;
|
||||||
|
return `${wanValue.toLocaleString('zh-CN', {
|
||||||
|
minimumFractionDigits: 0,
|
||||||
|
maximumFractionDigits: fractionDigits,
|
||||||
|
})}万`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeStat(row: ApiBuildingFunctionStat): ChartDatum {
|
function normalizeStat(row: ApiBuildingFunctionStat): ChartDatum {
|
||||||
@ -67,44 +173,422 @@ function normalizeStat(row: ApiBuildingFunctionStat): ChartDatum {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildQuery(params: Record<string, string | number | boolean | null | undefined>) {
|
||||||
|
const search = new URLSearchParams();
|
||||||
|
Object.entries(params).forEach(([key, value]) => {
|
||||||
|
if (value == null) return;
|
||||||
|
search.set(key, String(value));
|
||||||
|
});
|
||||||
|
search.set('currenttime', String(Date.now()));
|
||||||
|
search.set('__random__', String(Date.now()));
|
||||||
|
return search.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
function pickArray(payload: unknown): unknown[] {
|
||||||
|
if (Array.isArray(payload)) return payload;
|
||||||
|
if (!payload || typeof payload !== 'object') return [];
|
||||||
|
|
||||||
|
const source = payload as Record<string, unknown>;
|
||||||
|
const candidates = [
|
||||||
|
source.datas,
|
||||||
|
source.data,
|
||||||
|
source.data && typeof source.data === 'object' ? (source.data as Record<string, unknown>).datas : null,
|
||||||
|
source.data && typeof source.data === 'object' ? (source.data as Record<string, unknown>).list : null,
|
||||||
|
source.data && typeof source.data === 'object' ? (source.data as Record<string, unknown>).treeDatas : null,
|
||||||
|
source.result,
|
||||||
|
source.rows,
|
||||||
|
source.list,
|
||||||
|
source.treeDatas,
|
||||||
|
source.children,
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const candidate of candidates) {
|
||||||
|
if (Array.isArray(candidate)) return candidate;
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function readText(row: Record<string, unknown>, keys: string[]) {
|
||||||
|
for (const key of keys) {
|
||||||
|
const value = row[key];
|
||||||
|
if (value !== null && value !== undefined && String(value).trim()) {
|
||||||
|
return String(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeTreeRows(rows: unknown[]): TreeNode[] {
|
||||||
|
return rows
|
||||||
|
.filter((row): row is Record<string, unknown> => !!row && typeof row === 'object')
|
||||||
|
.map((row, index) => {
|
||||||
|
const children = normalizeTreeRows(pickArray(row.children ?? row.childs ?? row.subs));
|
||||||
|
const id = readText(row, ['id', 'key', 'value', 'nodeid', 'treeid', 'browserid']) || `node-${index}`;
|
||||||
|
const label = readText(row, ['name', 'label', 'title', 'text', 'showname', 'showName', 'browsername', 'displayName']) || id;
|
||||||
|
const hasChildren =
|
||||||
|
children.length > 0 ||
|
||||||
|
row.hasChild === true ||
|
||||||
|
row.haschild === true ||
|
||||||
|
row.isParent === true ||
|
||||||
|
row.isparent === true ||
|
||||||
|
row.children === true ||
|
||||||
|
row.child === true;
|
||||||
|
const canClick = row.canClick === true || row.canClick === 'true' || row.canclick === true || row.canclick === 'true';
|
||||||
|
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
label,
|
||||||
|
children,
|
||||||
|
hasChildren,
|
||||||
|
canClick,
|
||||||
|
expanded: children.length > 0,
|
||||||
|
loading: false,
|
||||||
|
loaded: children.length > 0,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateNode(nodes: TreeNode[], nodeId: string, updater: (node: TreeNode) => TreeNode): TreeNode[] {
|
||||||
|
return nodes.map((node) => {
|
||||||
|
if (node.id === nodeId) return updater(node);
|
||||||
|
return {
|
||||||
|
...node,
|
||||||
|
children: updateNode(node.children, nodeId, updater),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSelectionKey(contentKey: ContentKey, nodeId: string) {
|
||||||
|
return `${contentKey}:${nodeId}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSeriesValueKey(index: number) {
|
||||||
|
return `amount${index}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderTreeNodes(
|
||||||
|
nodes: TreeNode[],
|
||||||
|
contentKey: ContentKey,
|
||||||
|
selectedNodeKeys: Set<string>,
|
||||||
|
getNodeColor: (contentKey: ContentKey, nodeId: string) => string,
|
||||||
|
onToggle: (nodeId: string) => void,
|
||||||
|
onSelect: (node: TreeNode) => void,
|
||||||
|
depth = 0,
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
<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;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<li className="content-tree-node" role="treeitem" aria-expanded={node.hasChildren ? node.expanded : undefined} key={node.id}>
|
||||||
|
<div className="content-tree-row" style={{ paddingLeft: 8 + depth * 18 }}>
|
||||||
|
{node.hasChildren ? (
|
||||||
|
<button className="content-tree-caret" type="button" aria-label={node.expanded ? '收起' : '展开'} onClick={() => onToggle(node.id)}>
|
||||||
|
{node.expanded ? '▾' : '▸'}
|
||||||
|
</button>
|
||||||
|
) : (
|
||||||
|
<span className="content-tree-caret is-leaf" />
|
||||||
|
)}
|
||||||
|
<button
|
||||||
|
className="content-tree-select"
|
||||||
|
type="button"
|
||||||
|
aria-pressed={selected}
|
||||||
|
disabled={!node.canClick}
|
||||||
|
onClick={() => {
|
||||||
|
if (node.canClick) onSelect(node);
|
||||||
|
}}
|
||||||
|
title={node.label}
|
||||||
|
>
|
||||||
|
{node.canClick ? <span className="content-tree-series-mark" style={{ backgroundColor: color }} /> : null}
|
||||||
|
<span className="content-tree-label">{node.label}</span>
|
||||||
|
</button>
|
||||||
|
{node.loading ? <span className="content-tree-loading">加载中</span> : null}
|
||||||
|
</div>
|
||||||
|
{node.expanded && node.children.length > 0
|
||||||
|
? renderTreeNodes(node.children, contentKey, selectedNodeKeys, getNodeColor, onToggle, onSelect, depth + 1)
|
||||||
|
: null}
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const workspaceRef = useRef<HTMLElement>(null);
|
const workspaceRef = useRef<HTMLElement>(null);
|
||||||
const chartFrameRef = useRef<HTMLDivElement>(null);
|
const chartFrameRef = useRef<HTMLDivElement>(null);
|
||||||
|
const treeInitialLoadStartedRef = useRef<Record<ContentKey, boolean>>({
|
||||||
|
geoLocation: false,
|
||||||
|
facilityType: false,
|
||||||
|
constructionStage: false,
|
||||||
|
planningForm: false,
|
||||||
|
});
|
||||||
const [statisticKey, setStatisticKey] = useState<StatisticKey>('avgValue');
|
const [statisticKey, setStatisticKey] = useState<StatisticKey>('avgValue');
|
||||||
const [metricKey, setMetricKey] = useState<MetricKey>('cost');
|
const [metricKey, setMetricKey] = useState<MetricKey>('cost');
|
||||||
const [groupKey, setGroupKey] = useState<GroupKey>('year');
|
const [groupKey, setGroupKey] = useState<GroupKey>('year');
|
||||||
const [statisticMenuOpen, setStatisticMenuOpen] = useState(false);
|
const [statisticMenuOpen, setStatisticMenuOpen] = useState(false);
|
||||||
const [metricMenuOpen, setMetricMenuOpen] = useState(false);
|
const [metricMenuOpen, setMetricMenuOpen] = useState(false);
|
||||||
const [chartData, setChartData] = useState<ChartDatum[]>([]);
|
const [activeContentKey, setActiveContentKey] = useState<ContentKey>('geoLocation');
|
||||||
const [loading, setLoading] = useState(true);
|
const [treeByContent, setTreeByContent] = useState<Record<ContentKey, TreeNode[]>>({
|
||||||
|
geoLocation: [],
|
||||||
|
facilityType: [],
|
||||||
|
constructionStage: [],
|
||||||
|
planningForm: [],
|
||||||
|
});
|
||||||
|
const [treeLoadingByContent, setTreeLoadingByContent] = useState<Record<ContentKey, boolean>>({
|
||||||
|
geoLocation: false,
|
||||||
|
facilityType: false,
|
||||||
|
constructionStage: false,
|
||||||
|
planningForm: false,
|
||||||
|
});
|
||||||
|
const [treeErrorByContent, setTreeErrorByContent] = useState<Record<ContentKey, string | null>>({
|
||||||
|
geoLocation: null,
|
||||||
|
facilityType: null,
|
||||||
|
constructionStage: null,
|
||||||
|
planningForm: null,
|
||||||
|
});
|
||||||
|
const [selectedContentNodes, setSelectedContentNodes] = useState<SelectedContentNode[]>([]);
|
||||||
|
const [chartDataBySelection, setChartDataBySelection] = useState<Record<string, ChartDatum[]>>({});
|
||||||
|
const [chartQueryVersion, setChartQueryVersion] = useState(0);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
const [loadError, setLoadError] = useState<string | null>(null);
|
const [loadError, setLoadError] = useState<string | null>(null);
|
||||||
|
|
||||||
const selectedStatistic = statisticOptions.find((option) => option.key === statisticKey) ?? statisticOptions[0];
|
const selectedStatistic = statisticOptions.find((option) => option.key === statisticKey) ?? statisticOptions[0];
|
||||||
const selectedMetric = metricOptions.find((option) => option.key === metricKey) ?? metricOptions[0];
|
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 selectedNodeKeys = useMemo(
|
||||||
|
() => new Set(selectedContentNodes.map((node) => getSelectionKey(node.contentKey, node.id))),
|
||||||
|
[selectedContentNodes],
|
||||||
|
);
|
||||||
|
|
||||||
|
const getNodeColor = (contentKey: ContentKey, nodeId: string) => {
|
||||||
|
const selectedIndex = selectedContentNodes.findIndex((node) => node.contentKey === contentKey && node.id === nodeId);
|
||||||
|
if (selectedIndex >= 0) return selectedContentNodes[selectedIndex].color;
|
||||||
|
|
||||||
|
let hash = 0;
|
||||||
|
const key = getSelectionKey(contentKey, nodeId);
|
||||||
|
for (let index = 0; index < key.length; index += 1) {
|
||||||
|
hash = (hash * 31 + key.charCodeAt(index)) % chartLineColors.length;
|
||||||
|
}
|
||||||
|
return chartLineColors[hash];
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchContentTree = async (contentKey: ContentKey, nodeId?: string) => {
|
||||||
|
const config = contentTreeConfigs[contentKey];
|
||||||
|
if (!config) {
|
||||||
|
throw new Error('接口待接入');
|
||||||
|
}
|
||||||
|
const treeParams = {
|
||||||
|
...browserTreeDefaults,
|
||||||
|
treeid: config.treeid,
|
||||||
|
cube_treeid: config.treeid,
|
||||||
|
fieldid: config.fieldid,
|
||||||
|
};
|
||||||
|
const params = nodeId
|
||||||
|
? {
|
||||||
|
...treeParams,
|
||||||
|
type: '2',
|
||||||
|
id: nodeId,
|
||||||
|
isVirtual: '',
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
...treeParams,
|
||||||
|
pageSize: '10',
|
||||||
|
current: '1',
|
||||||
|
min: '1',
|
||||||
|
max: '10',
|
||||||
|
};
|
||||||
|
const response = await fetch(`${config.endpoint}?${buildQuery(params)}`, {
|
||||||
|
credentials: 'include',
|
||||||
|
headers: {
|
||||||
|
'X-Requested-With': 'XMLHttpRequest',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP ${response.status}`);
|
||||||
|
}
|
||||||
|
return normalizeTreeRows(pickArray(await response.json()));
|
||||||
|
};
|
||||||
|
|
||||||
|
const loadContentTreeWithDefaultExpansion = async (contentKey: ContentKey) => {
|
||||||
|
const defaultExpandedLevel = contentTreeConfigs[contentKey]?.defaultExpandedLevel ?? 0;
|
||||||
|
const loadChildren = async (nodes: TreeNode[], level: number): Promise<TreeNode[]> => {
|
||||||
|
if (level > defaultExpandedLevel) return nodes;
|
||||||
|
|
||||||
|
return Promise.all(
|
||||||
|
nodes.map(async (node) => {
|
||||||
|
if (!node.hasChildren) return node;
|
||||||
|
|
||||||
|
const children = node.loaded ? node.children : await fetchContentTree(contentKey, node.id);
|
||||||
|
return {
|
||||||
|
...node,
|
||||||
|
children: await loadChildren(children, level + 1),
|
||||||
|
expanded: true,
|
||||||
|
loading: false,
|
||||||
|
loaded: true,
|
||||||
|
hasChildren: node.hasChildren || children.length > 0,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return loadChildren(await fetchContentTree(contentKey), 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleContentNode = (nodeId: string) => {
|
||||||
|
if (!contentTreeConfigs[activeContentKey]) return;
|
||||||
|
const target = activeTree.find((node) => node.id === nodeId);
|
||||||
|
const visit = (nodes: TreeNode[]): TreeNode | null => {
|
||||||
|
for (const node of nodes) {
|
||||||
|
if (node.id === nodeId) return node;
|
||||||
|
const matched = visit(node.children);
|
||||||
|
if (matched) return matched;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
const node = target ?? visit(activeTree);
|
||||||
|
if (!node?.hasChildren) return;
|
||||||
|
|
||||||
|
setTreeByContent((current) => ({
|
||||||
|
...current,
|
||||||
|
[activeContentKey]: updateNode(current[activeContentKey], nodeId, (node) => ({
|
||||||
|
...node,
|
||||||
|
expanded: node.loaded ? !node.expanded : node.expanded,
|
||||||
|
loading: node.loaded ? node.loading : true,
|
||||||
|
})),
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (node.loaded) return;
|
||||||
|
|
||||||
|
const currentContentKey = activeContentKey;
|
||||||
|
fetchContentTree(currentContentKey, nodeId)
|
||||||
|
.then((children) => {
|
||||||
|
setTreeByContent((current) => ({
|
||||||
|
...current,
|
||||||
|
[currentContentKey]: updateNode(current[currentContentKey], nodeId, (currentNode) => ({
|
||||||
|
...currentNode,
|
||||||
|
children,
|
||||||
|
expanded: true,
|
||||||
|
loading: false,
|
||||||
|
loaded: true,
|
||||||
|
hasChildren: currentNode.hasChildren || children.length > 0,
|
||||||
|
})),
|
||||||
|
}));
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
setTreeByContent((current) => ({
|
||||||
|
...current,
|
||||||
|
[currentContentKey]: updateNode(current[currentContentKey], nodeId, (currentNode) => ({
|
||||||
|
...currentNode,
|
||||||
|
loading: false,
|
||||||
|
})),
|
||||||
|
}));
|
||||||
|
setTreeErrorByContent((current) => ({
|
||||||
|
...current,
|
||||||
|
[currentContentKey]: error instanceof Error ? error.message : '加载失败',
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleSelectedContentNode = (node: TreeNode) => {
|
||||||
|
const contentKey = activeContentKey;
|
||||||
|
setSelectedContentNodes((current) => {
|
||||||
|
const selectionKey = getSelectionKey(contentKey, node.id);
|
||||||
|
const existingIndex = current.findIndex((item) => getSelectionKey(item.contentKey, item.id) === selectionKey);
|
||||||
|
if (existingIndex >= 0) {
|
||||||
|
setChartDataBySelection((data) => {
|
||||||
|
const { [selectionKey]: _removed, ...rest } = data;
|
||||||
|
return rest;
|
||||||
|
});
|
||||||
|
return current.filter((_, index) => index !== existingIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
const usedColors = new Set(current.map((item) => item.color));
|
||||||
|
const color = chartLineColors.find((item) => !usedColors.has(item)) ?? chartLineColors[current.length % chartLineColors.length];
|
||||||
|
return [...current, { id: node.id, contentKey, label: node.label, color }];
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateMetricKey = (nextMetricKey: MetricKey) => {
|
||||||
|
setMetricKey(nextMetricKey);
|
||||||
|
setChartDataBySelection({});
|
||||||
|
setChartQueryVersion((version) => version + 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!contentTreeConfigs[activeContentKey]) return;
|
||||||
|
if (treeByContent[activeContentKey].length > 0 || treeInitialLoadStartedRef.current[activeContentKey]) return;
|
||||||
|
|
||||||
|
const currentContentKey = activeContentKey;
|
||||||
|
treeInitialLoadStartedRef.current[currentContentKey] = true;
|
||||||
|
setTreeLoadingByContent((current) => ({ ...current, [currentContentKey]: true }));
|
||||||
|
setTreeErrorByContent((current) => ({ ...current, [currentContentKey]: null }));
|
||||||
|
|
||||||
|
loadContentTreeWithDefaultExpansion(currentContentKey)
|
||||||
|
.then((nodes) => {
|
||||||
|
setTreeByContent((current) => ({ ...current, [currentContentKey]: nodes }));
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
treeInitialLoadStartedRef.current[currentContentKey] = false;
|
||||||
|
setTreeErrorByContent((current) => ({
|
||||||
|
...current,
|
||||||
|
[currentContentKey]: error instanceof Error ? error.message : '加载失败',
|
||||||
|
}));
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setTreeLoadingByContent((current) => ({ ...current, [currentContentKey]: false }));
|
||||||
|
});
|
||||||
|
}, [activeContentKey, treeByContent]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const controller = new AbortController();
|
const controller = new AbortController();
|
||||||
|
|
||||||
async function loadStats() {
|
async function loadStats() {
|
||||||
|
if (selectedContentNodes.length === 0) {
|
||||||
|
setChartDataBySelection({});
|
||||||
|
setLoading(false);
|
||||||
|
setLoadError(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
setLoadError(null);
|
setLoadError(null);
|
||||||
try {
|
try {
|
||||||
const search = new URLSearchParams({
|
const missingNodes = selectedContentNodes.filter((node) => !chartDataBySelection[getSelectionKey(node.contentKey, node.id)]);
|
||||||
groupBy: groupKey,
|
if (missingNodes.length === 0) {
|
||||||
metric: metricKey,
|
setLoading(false);
|
||||||
});
|
return;
|
||||||
const response = await fetch(`${API_BASE_URL}/zw/getBuildingFunctionCostStats?${search.toString()}`, {
|
|
||||||
signal: controller.signal,
|
|
||||||
});
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(`HTTP ${response.status}`);
|
|
||||||
}
|
}
|
||||||
const payload = (await response.json()) as { data?: ApiBuildingFunctionStat[] };
|
|
||||||
setChartData((payload.data ?? []).map(normalizeStat).slice(0, 36));
|
const results = await Promise.all(
|
||||||
|
missingNodes.map(async (node) => {
|
||||||
|
const search = new URLSearchParams({
|
||||||
|
groupBy: groupKey,
|
||||||
|
metric: metricKey,
|
||||||
|
contentKey: node.contentKey,
|
||||||
|
nodeId: node.id,
|
||||||
|
});
|
||||||
|
const response = await fetch(`${API_BASE_URL}/zw/getBuildingFunctionCostStats?${search.toString()}`, {
|
||||||
|
signal: controller.signal,
|
||||||
|
});
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP ${response.status}`);
|
||||||
|
}
|
||||||
|
const payload = (await response.json()) as { data?: ApiBuildingFunctionStat[] };
|
||||||
|
return [getSelectionKey(node.contentKey, node.id), (payload.data ?? []).map(normalizeStat).slice(0, 36)] as const;
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
setChartDataBySelection((current) => ({
|
||||||
|
...current,
|
||||||
|
...Object.fromEntries(results),
|
||||||
|
}));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (controller.signal.aborted) return;
|
if (controller.signal.aborted) return;
|
||||||
setLoadError(error instanceof Error ? error.message : '接口请求失败');
|
setLoadError(error instanceof Error ? error.message : '接口请求失败');
|
||||||
setChartData([]);
|
setChartDataBySelection({});
|
||||||
} finally {
|
} finally {
|
||||||
if (!controller.signal.aborted) {
|
if (!controller.signal.aborted) {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
@ -117,7 +601,7 @@ function App() {
|
|||||||
return () => {
|
return () => {
|
||||||
controller.abort();
|
controller.abort();
|
||||||
};
|
};
|
||||||
}, [groupKey, metricKey]);
|
}, [chartDataBySelection, chartQueryVersion, groupKey, metricKey, selectedContentNodes]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const frame = chartFrameRef.current;
|
const frame = chartFrameRef.current;
|
||||||
@ -126,7 +610,6 @@ function App() {
|
|||||||
|
|
||||||
const getFullscreenButton = () => frame.querySelector<HTMLButtonElement>('.chart-fullscreen-button');
|
const getFullscreenButton = () => frame.querySelector<HTMLButtonElement>('.chart-fullscreen-button');
|
||||||
const getStatisticButton = () => frame.querySelector<HTMLElement>('.ag-charts-myButton-statistic')?.closest<HTMLButtonElement>('.ag-charts-toolbar__button');
|
const getStatisticButton = () => frame.querySelector<HTMLElement>('.ag-charts-myButton-statistic')?.closest<HTMLButtonElement>('.ag-charts-toolbar__button');
|
||||||
|
|
||||||
const syncToolbarButtons = () => {
|
const syncToolbarButtons = () => {
|
||||||
const button = getFullscreenButton();
|
const button = getFullscreenButton();
|
||||||
if (button) {
|
if (button) {
|
||||||
@ -145,6 +628,7 @@ function App() {
|
|||||||
const statisticButton = getStatisticButton();
|
const statisticButton = getStatisticButton();
|
||||||
if (statisticButton) {
|
if (statisticButton) {
|
||||||
statisticButton.classList.add('chart-statistic-button');
|
statisticButton.classList.add('chart-statistic-button');
|
||||||
|
statisticButton.setAttribute('aria-expanded', String(statisticMenuOpen));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -177,6 +661,7 @@ function App() {
|
|||||||
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
event.stopImmediatePropagation();
|
||||||
if (button.classList.contains('chart-statistic-button')) {
|
if (button.classList.contains('chart-statistic-button')) {
|
||||||
setMetricMenuOpen(false);
|
setMetricMenuOpen(false);
|
||||||
setStatisticMenuOpen((open) => !open);
|
setStatisticMenuOpen((open) => !open);
|
||||||
@ -196,6 +681,7 @@ function App() {
|
|||||||
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
event.stopImmediatePropagation();
|
||||||
if (button.classList.contains('chart-statistic-button')) {
|
if (button.classList.contains('chart-statistic-button')) {
|
||||||
setMetricMenuOpen(false);
|
setMetricMenuOpen(false);
|
||||||
setStatisticMenuOpen((open) => !open);
|
setStatisticMenuOpen((open) => !open);
|
||||||
@ -227,14 +713,28 @@ function App() {
|
|||||||
frame.removeEventListener('keydown', handleToolbarKeyDown, true);
|
frame.removeEventListener('keydown', handleToolbarKeyDown, true);
|
||||||
observer.disconnect();
|
observer.disconnect();
|
||||||
};
|
};
|
||||||
}, []);
|
}, [statisticMenuOpen]);
|
||||||
|
|
||||||
const chartOptions = useMemo<AgCartesianChartOptions>(() => {
|
const chartOptions = useMemo<AgCartesianChartOptions>(() => {
|
||||||
const isCount = statisticKey === 'dataCount';
|
const isCount = statisticKey === 'dataCount';
|
||||||
const visibleData = chartData.map((datum) => ({
|
const groupNames: string[] = [];
|
||||||
groupName: datum.groupName,
|
const groupNameSeen = new Set<string>();
|
||||||
amount: datum[statisticKey],
|
selectedContentNodes.forEach((node) => {
|
||||||
}));
|
const rows = chartDataBySelection[getSelectionKey(node.contentKey, node.id)] ?? [];
|
||||||
|
rows.forEach((datum) => {
|
||||||
|
if (groupNameSeen.has(datum.groupName)) return;
|
||||||
|
groupNameSeen.add(datum.groupName);
|
||||||
|
groupNames.push(datum.groupName);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
const visibleData = groupNames.map((groupName) => {
|
||||||
|
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;
|
||||||
|
});
|
||||||
|
return row;
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
theme: {
|
theme: {
|
||||||
@ -290,7 +790,7 @@ function App() {
|
|||||||
toolbar: {
|
toolbar: {
|
||||||
buttons: ([
|
buttons: ([
|
||||||
{
|
{
|
||||||
value: 'statistic-select',
|
value: 'note',
|
||||||
tooltip: '切换统计指标',
|
tooltip: '切换统计指标',
|
||||||
label: `<span class="ag-charts-myButton-statistic ag-charts-diy-button">${selectedStatistic.shortLabel}</span>`,
|
label: `<span class="ag-charts-myButton-statistic ag-charts-diy-button">${selectedStatistic.shortLabel}</span>`,
|
||||||
},
|
},
|
||||||
@ -322,25 +822,23 @@ function App() {
|
|||||||
] as unknown as NonNullable<NonNullable<AgCartesianChartOptions['annotations']>['toolbar']>['buttons']),
|
] as unknown as NonNullable<NonNullable<AgCartesianChartOptions['annotations']>['toolbar']>['buttons']),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
series: [
|
series: selectedContentNodes.map((node, index) => ({
|
||||||
{
|
type: 'line',
|
||||||
type: 'line',
|
xKey: 'groupName',
|
||||||
xKey: 'groupName',
|
yKey: getSeriesValueKey(index),
|
||||||
yKey: 'amount',
|
yName: `${node.label} ${selectedStatistic.label}`,
|
||||||
yName: `${selectedMetric.label} ${selectedStatistic.label}`,
|
stroke: node.color,
|
||||||
stroke: '#0078a8',
|
strokeWidth: 2,
|
||||||
strokeWidth: 2,
|
marker: {
|
||||||
marker: {
|
enabled: true,
|
||||||
enabled: true,
|
fill: node.color,
|
||||||
fill: '#0078a8',
|
stroke: node.color,
|
||||||
stroke: '#0078a8',
|
size: 5,
|
||||||
size: 5,
|
|
||||||
},
|
|
||||||
interpolation: {
|
|
||||||
type: 'smooth',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
],
|
interpolation: {
|
||||||
|
type: 'smooth',
|
||||||
|
},
|
||||||
|
})),
|
||||||
axes: {
|
axes: {
|
||||||
x: {
|
x: {
|
||||||
type: 'category',
|
type: 'category',
|
||||||
@ -398,13 +896,13 @@ function App() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
enabled: false,
|
enabled: selectedContentNodes.length > 1,
|
||||||
},
|
},
|
||||||
tooltip: {
|
tooltip: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}, [chartData, selectedMetric.label, selectedStatistic.label, statisticKey]);
|
}, [chartDataBySelection, selectedContentNodes, selectedMetric.label, selectedStatistic.label, statisticKey]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="dashboard-shell">
|
<main className="dashboard-shell">
|
||||||
@ -461,7 +959,7 @@ function App() {
|
|||||||
key={option.key}
|
key={option.key}
|
||||||
aria-current={option.key === metricKey}
|
aria-current={option.key === metricKey}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setMetricKey(option.key);
|
updateMetricKey(option.key);
|
||||||
setMetricMenuOpen(false);
|
setMetricMenuOpen(false);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -471,7 +969,9 @@ function App() {
|
|||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
{loading || loadError ? <div className="chart-status">{loading ? '加载中' : loadError}</div> : null}
|
{loading || loadError || selectedContentNodes.length === 0 ? (
|
||||||
|
<div className="chart-status">{loading ? '加载中' : loadError || '请选择右侧分类项'}</div>
|
||||||
|
) : null}
|
||||||
<button className="chart-fullscreen-button ag-charts-toolbar__button" type="button" title="全屏(F11)">
|
<button className="chart-fullscreen-button ag-charts-toolbar__button" type="button" title="全屏(F11)">
|
||||||
<i className="anticon anticon-arrow-salt ag-charts-myButton-fullScreen ag-charts-diy-button" />
|
<i className="anticon anticon-arrow-salt ag-charts-myButton-fullScreen ag-charts-diy-button" />
|
||||||
</button>
|
</button>
|
||||||
@ -479,7 +979,34 @@ function App() {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<aside className="right-placeholder" aria-label="右侧预留区域" />
|
<aside className="right-panel" aria-label="选择内容">
|
||||||
|
<div className="content-tabs" role="tablist" aria-label="选择内容切换项">
|
||||||
|
{contentOptions.map((option) => (
|
||||||
|
<button
|
||||||
|
className="content-tab"
|
||||||
|
type="button"
|
||||||
|
role="tab"
|
||||||
|
key={option.key}
|
||||||
|
aria-selected={option.key === activeContentKey}
|
||||||
|
onClick={() => setActiveContentKey(option.key)}
|
||||||
|
>
|
||||||
|
{option.label}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className="content-tree-panel">
|
||||||
|
<div className="content-tree-title">{activeContent.label}</div>
|
||||||
|
{treeLoadingByContent[activeContentKey] ? (
|
||||||
|
<div className="content-tree-empty">加载中</div>
|
||||||
|
) : treeErrorByContent[activeContentKey] ? (
|
||||||
|
<div className="content-tree-empty">{treeErrorByContent[activeContentKey]}</div>
|
||||||
|
) : activeTree.length > 0 ? (
|
||||||
|
renderTreeNodes(activeTree, activeContentKey, selectedNodeKeys, getNodeColor, toggleContentNode, toggleSelectedContentNode)
|
||||||
|
) : (
|
||||||
|
<div className="content-tree-empty">接口待接入</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
|
|||||||
36
src/main.tsx
@ -6,8 +6,34 @@ import './styles.css';
|
|||||||
|
|
||||||
ModuleRegistry.registerModules([AllCommunityModule]);
|
ModuleRegistry.registerModules([AllCommunityModule]);
|
||||||
|
|
||||||
createRoot(document.getElementById('root')!).render(
|
declare global {
|
||||||
<StrictMode>
|
interface Window {
|
||||||
<App />
|
__zbChartRoot?: ReturnType<typeof createRoot>;
|
||||||
</StrictMode>,
|
}
|
||||||
);
|
}
|
||||||
|
|
||||||
|
const mount = () => {
|
||||||
|
const container = document.getElementById('zbChart');
|
||||||
|
if (!container) return false;
|
||||||
|
|
||||||
|
window.__zbChartRoot ??= createRoot(container);
|
||||||
|
window.__zbChartRoot.render(
|
||||||
|
<StrictMode>
|
||||||
|
<App />
|
||||||
|
</StrictMode>,
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!mount()) {
|
||||||
|
let retryCount = 0;
|
||||||
|
const timer = window.setInterval(() => {
|
||||||
|
retryCount += 1;
|
||||||
|
if (mount() || retryCount >= 40) {
|
||||||
|
window.clearInterval(timer);
|
||||||
|
if (retryCount >= 40) {
|
||||||
|
console.warn('zbChart container was not found.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 50);
|
||||||
|
}
|
||||||
|
|||||||
189
src/styles.css
@ -176,7 +176,7 @@ button {
|
|||||||
height: calc(100vh - 26px);
|
height: calc(100vh - 26px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.workspace:fullscreen .right-placeholder {
|
.workspace:fullscreen .right-panel {
|
||||||
display: block;
|
display: block;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@ -252,6 +252,17 @@ button {
|
|||||||
background: rgba(255, 252, 248, 0.94);
|
background: rgba(255, 252, 248, 0.94);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.chart-frame .chart-statistic-button {
|
||||||
|
color: #46413b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-frame .chart-statistic-button[aria-expanded="true"] {
|
||||||
|
color: #0078a8;
|
||||||
|
border-color: rgba(0, 120, 168, 0.36);
|
||||||
|
background: rgba(255, 252, 248, 0.94);
|
||||||
|
box-shadow: 0 1px 5px rgba(69, 54, 36, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
.metric-switcher {
|
.metric-switcher {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 74px;
|
left: 74px;
|
||||||
@ -481,9 +492,177 @@ button {
|
|||||||
opacity: 0.38;
|
opacity: 0.38;
|
||||||
}
|
}
|
||||||
|
|
||||||
.right-placeholder {
|
.right-panel {
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: auto minmax(0, 1fr);
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
padding-top: 24px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-tabs {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
min-width: 0;
|
||||||
|
padding-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-tab {
|
||||||
|
height: 32px;
|
||||||
|
padding: 0 12px;
|
||||||
|
border: 1px solid rgba(90, 82, 72, 0.18);
|
||||||
|
border-radius: 3px;
|
||||||
|
color: #46413b;
|
||||||
|
background: rgba(255, 249, 241, 0.62);
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 30px;
|
||||||
|
white-space: nowrap;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-tab:hover,
|
||||||
|
.content-tab[aria-selected="true"] {
|
||||||
|
color: #0078a8;
|
||||||
|
border-color: rgba(0, 120, 168, 0.36);
|
||||||
|
background: rgba(255, 252, 248, 0.94);
|
||||||
|
box-shadow: 0 1px 5px rgba(69, 54, 36, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-tree-panel {
|
||||||
|
min-width: 0;
|
||||||
|
min-height: 0;
|
||||||
|
max-height: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
padding: 14px 6px 14px 0;
|
||||||
|
border-top: 1px solid rgba(90, 82, 72, 0.14);
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-tree-title {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
color: #262a33;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-tree-list {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-tree-node {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-tree-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
min-height: 42px;
|
||||||
|
border-radius: 3px;
|
||||||
|
color: #262a33;
|
||||||
|
background: transparent;
|
||||||
|
font-size: 17px;
|
||||||
|
line-height: 42px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-tree-row:hover {
|
||||||
|
color: #0078a8;
|
||||||
|
background: rgba(255, 252, 248, 0.74);
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-tree-caret {
|
||||||
|
display: inline-grid;
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
place-items: center;
|
||||||
|
flex: 0 0 24px;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
color: #6f665e;
|
||||||
|
background: transparent;
|
||||||
|
font-size: 15px;
|
||||||
|
line-height: 24px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-tree-caret.is-leaf {
|
||||||
|
color: transparent;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-tree-select {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
min-width: 0;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
gap: 10px;
|
||||||
|
height: 38px;
|
||||||
|
padding: 0 6px 0 2px;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 3px;
|
||||||
|
color: inherit;
|
||||||
|
background: transparent;
|
||||||
|
text-align: left;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-tree-select:disabled {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-tree-select:hover,
|
||||||
|
.content-tree-select[aria-pressed="true"] {
|
||||||
|
color: #0078a8;
|
||||||
|
background: rgba(255, 252, 248, 0.78);
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-tree-select:disabled:hover {
|
||||||
|
color: inherit;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-tree-select[aria-pressed="true"] {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-tree-series-mark {
|
||||||
|
width: 24px;
|
||||||
|
height: 4px;
|
||||||
|
flex: 0 0 24px;
|
||||||
|
border-radius: 2px;
|
||||||
|
opacity: 0.55;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-tree-select[aria-pressed="true"] .content-tree-series-mark {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-tree-label {
|
||||||
|
min-width: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-tree-loading {
|
||||||
|
margin-left: 8px;
|
||||||
|
color: #7a7067;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-tree-empty {
|
||||||
|
padding: 16px 0;
|
||||||
|
color: #7a7067;
|
||||||
|
font-size: 17px;
|
||||||
|
line-height: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 900px) {
|
@media (max-width: 900px) {
|
||||||
@ -502,7 +681,11 @@ button {
|
|||||||
min-height: 520px;
|
min-height: 520px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.right-placeholder {
|
.right-panel {
|
||||||
min-height: 280px;
|
min-height: 280px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.content-tabs {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
34
vite-dev.log
@ -64,3 +64,37 @@ Port 5173 is in use, trying another one...
|
|||||||
[2m09:35:53[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/App.tsx[22m
|
[2m09:35:53[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/App.tsx[22m
|
||||||
[2m09:35:53[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/styles.css[22m
|
[2m09:35:53[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/styles.css[22m
|
||||||
[2m09:36:43[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/App.tsx[22m
|
[2m09:36:43[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/App.tsx[22m
|
||||||
|
[2m09:40:50[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/App.tsx[22m
|
||||||
|
[2m09:41:06[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/styles.css[22m
|
||||||
|
[2m09:42:18[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/styles.css[22m
|
||||||
|
[2m09:55:02[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/App.tsx[22m
|
||||||
|
[2m09:55:36[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/App.tsx[22m
|
||||||
|
[2m09:55:49[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/styles.css[22m
|
||||||
|
[2m10:07:23[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/App.tsx[22m
|
||||||
|
[2m10:26:33[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/App.tsx[22m
|
||||||
|
[2m10:27:25[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/App.tsx[22m
|
||||||
|
[2m10:27:56[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/styles.css[22m
|
||||||
|
[2m11:14:09[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/App.tsx[22m
|
||||||
|
[2m11:16:09[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mpage reload [39m[2mzbChart/index.html[22m
|
||||||
|
[2m11:17:29[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mpage reload [39m[2mindex.html[22m
|
||||||
|
[2m11:17:43[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mpage reload [39m[2msrc/main.tsx[22m
|
||||||
|
[2m11:32:17[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mpage reload [39m[2msrc/main.tsx[22m
|
||||||
|
[2m11:35:33[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/App.tsx[22m
|
||||||
|
[2m11:35:45[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/styles.css[22m
|
||||||
|
[2m11:49:29[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/App.tsx[22m
|
||||||
|
[2m11:52:03[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/styles.css[22m
|
||||||
|
[2m11:53:37[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/App.tsx[22m
|
||||||
|
[2m11:57:22[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/App.tsx[22m
|
||||||
|
[2m11:59:02[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/App.tsx[22m
|
||||||
|
[2m15:00:25[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/App.tsx[22m
|
||||||
|
[2m15:14:46[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/App.tsx[22m
|
||||||
|
[2m15:14:56[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/App.tsx[22m
|
||||||
|
[2m15:15:05[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/App.tsx[22m
|
||||||
|
[2m15:15:18[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/App.tsx[22m
|
||||||
|
[2m15:15:29[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/App.tsx[22m
|
||||||
|
[2m15:15:39[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/App.tsx[22m
|
||||||
|
[2m15:15:49[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/styles.css[22m
|
||||||
|
[2m15:54:06[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/App.tsx[22m
|
||||||
|
[2m15:54:29[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/styles.css[22m
|
||||||
|
[2m16:29:28[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/App.tsx[22m
|
||||||
|
[2m16:29:37[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/App.tsx[22m
|
||||||
|
|||||||
42
zbChart/assets/index-BBo2g0gG.js
Normal file
1
zbChart/assets/index-hvfQ0T_3.css
Normal file
13
zbChart/index.html
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>AG Chart Service</title>
|
||||||
|
<script type="module" crossorigin src="/assets/index-BBo2g0gG.js"></script>
|
||||||
|
<link rel="stylesheet" crossorigin href="/assets/index-hvfQ0T_3.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="root"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||