fix
This commit is contained in:
parent
7845ae8eb0
commit
53c1b6f523
2
.playwright-mcp/console-2026-05-12T03-32-51-357Z.log
Normal file
2
.playwright-mcp/console-2026-05-12T03-32-51-357Z.log
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[ 1001ms] [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=ae174d51:20102
|
||||||
|
[ 1337ms] [ERROR] Failed to load resource: the server responded with a status of 404 (Not Found) @ http://127.0.0.1:5173/favicon.ico:0
|
||||||
8
.playwright-mcp/console-2026-05-12T03-33-46-269Z.log
Normal file
8
.playwright-mcp/console-2026-05-12T03-33-46-269Z.log
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
[ 79ms] [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=ae174d51:20102
|
||||||
|
[ 255622ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"reset"`; 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=ae174d51:834
|
||||||
|
[ 255658ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"reset"`; 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=ae174d51:834
|
||||||
|
[ 268128ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"reset"`; 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=ae174d51:834
|
||||||
|
[ 268149ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"reset"`; 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=ae174d51:834
|
||||||
|
[ 282018ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"reset"`; 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=ae174d51:834
|
||||||
|
[ 282037ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"reset"`; 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=ae174d51:834
|
||||||
|
[ 282064ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"reset"`; 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=ae174d51:834
|
||||||
4
.playwright-mcp/console-2026-05-12T03-38-57-686Z.log
Normal file
4
.playwright-mcp/console-2026-05-12T03-38-57-686Z.log
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[ 47ms] [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=ae174d51:20102
|
||||||
|
[ 194ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"reset"`; 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=ae174d51:834
|
||||||
|
[ 244ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"reset"`; 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=ae174d51:834
|
||||||
|
[ 293ms] [WARNING] AG Charts - Option `annotations.toolbar.buttons[0].value` cannot be set to `"reset"`; 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=ae174d51:834
|
||||||
1
.playwright-mcp/console-2026-05-12T03-39-25-518Z.log
Normal file
1
.playwright-mcp/console-2026-05-12T03-39-25-518Z.log
Normal file
@ -0,0 +1 @@
|
|||||||
|
[ 26ms] [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=ae174d51:20102
|
||||||
2
.playwright-mcp/console-2026-05-12T03-41-17-981Z.log
Normal file
2
.playwright-mcp/console-2026-05-12T03-41-17-981Z.log
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[ 32ms] [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=ae174d51:20102
|
||||||
|
[ 371068ms] [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=ae174d51:20102
|
||||||
1
.playwright-mcp/console-2026-05-12T03-48-27-372Z.log
Normal file
1
.playwright-mcp/console-2026-05-12T03-48-27-372Z.log
Normal file
@ -0,0 +1 @@
|
|||||||
|
[ 99ms] [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=ae174d51:20102
|
||||||
5
.playwright-mcp/console-2026-05-12T03-50-50-051Z.log
Normal file
5
.playwright-mcp/console-2026-05-12T03-50-50-051Z.log
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[ 77ms] [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=ae174d51:20102
|
||||||
|
[ 1186370ms] [ERROR] The final argument passed to %s changed size between renders. The order and size of this array must remain constant.
|
||||||
|
|
||||||
|
Previous: %s
|
||||||
|
Incoming: %s useEffect [false] [[object Object], , [object Object], false] @ http://127.0.0.1:5173/node_modules/.vite/deps/react-dom_client.js?v=ae174d51:5627
|
||||||
1
.playwright-mcp/console-2026-05-12T04-17-37-255Z.log
Normal file
1
.playwright-mcp/console-2026-05-12T04-17-37-255Z.log
Normal file
@ -0,0 +1 @@
|
|||||||
|
[ 854ms] [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=ae174d51:20102
|
||||||
1
.playwright-mcp/console-2026-05-12T04-19-14-036Z.log
Normal file
1
.playwright-mcp/console-2026-05-12T04-19-14-036Z.log
Normal file
@ -0,0 +1 @@
|
|||||||
|
[ 88ms] [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=ae174d51:20102
|
||||||
5
.playwright-mcp/console-2026-05-12T04-27-12-424Z.log
Normal file
5
.playwright-mcp/console-2026-05-12T04-27-12-424Z.log
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[ 219ms] [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=ae174d51:20102
|
||||||
|
[ 139728ms] [ERROR] Failed to load resource: the server responded with a status of 401 () @ https://nest.zwgczx.com/api/v1/zw/getBuildingFunctionCostFilterTree?key=templateLibrary¤ttime=1778560172021&__random__=1778560172021:0
|
||||||
|
[ 142705ms] [ERROR] Failed to load resource: the server responded with a status of 401 () @ https://nest.zwgczx.com/api/v1/zw/getBuildingFunctionCostFilterTree?key=indicatorTree&templateId=3¤ttime=1778560175114&__random__=1778560175114:0
|
||||||
|
[ 304362ms] [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=ae174d51:20102
|
||||||
|
[ 307069ms] [ERROR] Failed to load resource: the server responded with a status of 401 () @ https://nest.zwgczx.com/api/v1/zw/getBuildingFunctionCostFilterTree?key=indicatorTree&templateId=3¤ttime=1778560339458&__random__=1778560339458:0
|
||||||
81
.playwright-mcp/page-2026-05-12T03-32-52-698Z.yml
Normal file
81
.playwright-mcp/page-2026-05-12T03-32-52-698Z.yml
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
- 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]:
|
||||||
|
- generic "筛选条件" [ref=e5]:
|
||||||
|
- button "模板库 1" [pressed] [ref=e6] [cursor=pointer]:
|
||||||
|
- img [ref=e7]
|
||||||
|
- generic [ref=e9]: 模板库
|
||||||
|
- strong [ref=e10]: "1"
|
||||||
|
- button "指标树形" [ref=e11] [cursor=pointer]:
|
||||||
|
- img [ref=e12]
|
||||||
|
- generic [ref=e19]: 指标树形
|
||||||
|
- button "省市区" [ref=e20] [cursor=pointer]:
|
||||||
|
- img [ref=e21]
|
||||||
|
- generic [ref=e25]: 省市区
|
||||||
|
- button "自然地理区位" [ref=e26] [cursor=pointer]:
|
||||||
|
- img [ref=e27]
|
||||||
|
- generic [ref=e30]: 自然地理区位
|
||||||
|
- button "设施类别" [ref=e31] [cursor=pointer]:
|
||||||
|
- img [ref=e32]
|
||||||
|
- generic [ref=e36]: 设施类别
|
||||||
|
- button "建设阶段" [ref=e37] [cursor=pointer]:
|
||||||
|
- img [ref=e38]
|
||||||
|
- generic [ref=e43]: 建设阶段
|
||||||
|
- button "规划形式" [ref=e44] [cursor=pointer]:
|
||||||
|
- img [ref=e45]
|
||||||
|
- generic [ref=e50]: 规划形式
|
||||||
|
- region "年度总费用图表" [ref=e51]:
|
||||||
|
- generic [ref=e52]:
|
||||||
|
- button "纵坐标:造价(元)" [ref=e54] [cursor=pointer]: 造价(元)
|
||||||
|
- button "全屏(F11)" [ref=e55] [cursor=pointer]
|
||||||
|
- generic [ref=e57]:
|
||||||
|
- figure "图表,共有0个系列":
|
||||||
|
- generic [ref=e58]:
|
||||||
|
- img "interactive chart":
|
||||||
|
- generic:
|
||||||
|
- img
|
||||||
|
- img
|
||||||
|
- region [ref=e59]
|
||||||
|
- toolbar "标注" [ref=e60]:
|
||||||
|
- button "均" [disabled] [ref=e61]:
|
||||||
|
- generic: 均
|
||||||
|
- button "Line Tool" [disabled] [ref=e62]
|
||||||
|
- button "Text Tool" [disabled] [ref=e63]
|
||||||
|
- button "Shape Tool" [disabled] [ref=e64]
|
||||||
|
- button "Fibonacci Tool" [disabled] [ref=e65]
|
||||||
|
- button "Clear annotations" [disabled] [ref=e66]
|
||||||
|
- status:
|
||||||
|
- generic: 请选择右侧分类项
|
||||||
|
- toolbar "缩放" [ref=e67]:
|
||||||
|
- button "缩小" [disabled] [ref=e68]
|
||||||
|
- button "放大" [ref=e69] [cursor=pointer]
|
||||||
|
- button "左移" [disabled] [ref=e70]
|
||||||
|
- button "右移" [disabled] [ref=e71]
|
||||||
|
- button "重置" [disabled] [ref=e72]
|
||||||
|
- complementary "选择内容" [ref=e73]:
|
||||||
|
- tablist "选择内容切换项" [ref=e74]:
|
||||||
|
- tab "自然地理区位" [selected] [ref=e75] [cursor=pointer]
|
||||||
|
- tab "设施类别" [ref=e76] [cursor=pointer]
|
||||||
|
- tab "建设阶段" [ref=e77] [cursor=pointer]
|
||||||
|
- tab "规划形式" [ref=e78] [cursor=pointer]
|
||||||
|
- generic [ref=e79]:
|
||||||
|
- generic [ref=e80]: 自然地理区位
|
||||||
|
- generic [ref=e81]: 加载中
|
||||||
81
.playwright-mcp/page-2026-05-12T03-33-46-589Z.yml
Normal file
81
.playwright-mcp/page-2026-05-12T03-33-46-589Z.yml
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
- 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]:
|
||||||
|
- generic "筛选条件" [ref=e5]:
|
||||||
|
- button "模板库 1" [pressed] [ref=e6] [cursor=pointer]:
|
||||||
|
- img [ref=e7]
|
||||||
|
- generic [ref=e9]: 模板库
|
||||||
|
- strong [ref=e10]: "1"
|
||||||
|
- button "指标树形" [ref=e11] [cursor=pointer]:
|
||||||
|
- img [ref=e12]
|
||||||
|
- generic [ref=e19]: 指标树形
|
||||||
|
- button "省市区" [ref=e20] [cursor=pointer]:
|
||||||
|
- img [ref=e21]
|
||||||
|
- generic [ref=e25]: 省市区
|
||||||
|
- button "自然地理区位" [ref=e26] [cursor=pointer]:
|
||||||
|
- img [ref=e27]
|
||||||
|
- generic [ref=e30]: 自然地理区位
|
||||||
|
- button "设施类别" [ref=e31] [cursor=pointer]:
|
||||||
|
- img [ref=e32]
|
||||||
|
- generic [ref=e36]: 设施类别
|
||||||
|
- button "建设阶段" [ref=e37] [cursor=pointer]:
|
||||||
|
- img [ref=e38]
|
||||||
|
- generic [ref=e43]: 建设阶段
|
||||||
|
- button "规划形式" [ref=e44] [cursor=pointer]:
|
||||||
|
- img [ref=e45]
|
||||||
|
- generic [ref=e50]: 规划形式
|
||||||
|
- region "年度总费用图表" [ref=e51]:
|
||||||
|
- generic [ref=e52]:
|
||||||
|
- button "纵坐标:造价(元)" [ref=e54] [cursor=pointer]: 造价(元)
|
||||||
|
- button "全屏(F11)" [ref=e55] [cursor=pointer]
|
||||||
|
- generic [ref=e57]:
|
||||||
|
- figure "图表,共有0个系列":
|
||||||
|
- generic [ref=e58]:
|
||||||
|
- img "interactive chart":
|
||||||
|
- generic:
|
||||||
|
- img
|
||||||
|
- img
|
||||||
|
- region [ref=e59]
|
||||||
|
- toolbar "标注" [ref=e60]:
|
||||||
|
- button "均" [disabled] [ref=e61]:
|
||||||
|
- generic: 均
|
||||||
|
- button "Line Tool" [disabled] [ref=e62]
|
||||||
|
- button "Text Tool" [disabled] [ref=e63]
|
||||||
|
- button "Shape Tool" [disabled] [ref=e64]
|
||||||
|
- button "Fibonacci Tool" [disabled] [ref=e65]
|
||||||
|
- button "Clear annotations" [disabled] [ref=e66]
|
||||||
|
- status:
|
||||||
|
- generic: 请选择右侧分类项
|
||||||
|
- toolbar "缩放" [ref=e67]:
|
||||||
|
- button "缩小" [disabled] [ref=e68]
|
||||||
|
- button "放大" [ref=e69] [cursor=pointer]
|
||||||
|
- button "左移" [disabled] [ref=e70]
|
||||||
|
- button "右移" [disabled] [ref=e71]
|
||||||
|
- button "重置" [disabled] [ref=e72]
|
||||||
|
- complementary "选择内容" [ref=e73]:
|
||||||
|
- tablist "选择内容切换项" [ref=e74]:
|
||||||
|
- tab "自然地理区位" [selected] [ref=e75] [cursor=pointer]
|
||||||
|
- tab "设施类别" [ref=e76] [cursor=pointer]
|
||||||
|
- tab "建设阶段" [ref=e77] [cursor=pointer]
|
||||||
|
- tab "规划形式" [ref=e78] [cursor=pointer]
|
||||||
|
- generic [ref=e79]:
|
||||||
|
- generic [ref=e80]: 自然地理区位
|
||||||
|
- generic [ref=e81]: 加载中
|
||||||
81
.playwright-mcp/page-2026-05-12T03-38-57-987Z.yml
Normal file
81
.playwright-mcp/page-2026-05-12T03-38-57-987Z.yml
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
- 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]:
|
||||||
|
- generic "筛选条件" [ref=e5]:
|
||||||
|
- button "模板库 1" [pressed] [ref=e6] [cursor=pointer]:
|
||||||
|
- img [ref=e7]
|
||||||
|
- generic [ref=e9]: 模板库
|
||||||
|
- strong [ref=e10]: "1"
|
||||||
|
- button "指标树形" [ref=e11] [cursor=pointer]:
|
||||||
|
- img [ref=e12]
|
||||||
|
- generic [ref=e19]: 指标树形
|
||||||
|
- button "省市区" [ref=e20] [cursor=pointer]:
|
||||||
|
- img [ref=e21]
|
||||||
|
- generic [ref=e25]: 省市区
|
||||||
|
- button "自然地理区位" [ref=e26] [cursor=pointer]:
|
||||||
|
- img [ref=e27]
|
||||||
|
- generic [ref=e30]: 自然地理区位
|
||||||
|
- button "设施类别" [ref=e31] [cursor=pointer]:
|
||||||
|
- img [ref=e32]
|
||||||
|
- generic [ref=e36]: 设施类别
|
||||||
|
- button "建设阶段" [ref=e37] [cursor=pointer]:
|
||||||
|
- img [ref=e38]
|
||||||
|
- generic [ref=e43]: 建设阶段
|
||||||
|
- button "规划形式" [ref=e44] [cursor=pointer]:
|
||||||
|
- img [ref=e45]
|
||||||
|
- generic [ref=e50]: 规划形式
|
||||||
|
- region "年度总费用图表" [ref=e51]:
|
||||||
|
- generic [ref=e52]:
|
||||||
|
- button "纵坐标:造价(元)" [ref=e54] [cursor=pointer]: 造价(元)
|
||||||
|
- generic [ref=e55]:
|
||||||
|
- figure "图表,共有0个系列":
|
||||||
|
- generic [ref=e56]:
|
||||||
|
- img "interactive chart":
|
||||||
|
- generic:
|
||||||
|
- img
|
||||||
|
- img
|
||||||
|
- region [ref=e57]
|
||||||
|
- toolbar "标注" [ref=e58]:
|
||||||
|
- button "全屏(F11)" [disabled] [ref=e59]
|
||||||
|
- button "均" [disabled] [ref=e60]:
|
||||||
|
- generic: 均
|
||||||
|
- button "Line Tool" [disabled] [ref=e61]
|
||||||
|
- button "Text Tool" [disabled] [ref=e62]
|
||||||
|
- button "Shape Tool" [disabled] [ref=e63]
|
||||||
|
- button "Fibonacci Tool" [disabled] [ref=e64]
|
||||||
|
- button "Clear annotations" [disabled] [ref=e65]
|
||||||
|
- status:
|
||||||
|
- generic: 请选择右侧分类项
|
||||||
|
- toolbar "缩放" [ref=e66]:
|
||||||
|
- button "缩小" [disabled] [ref=e67]
|
||||||
|
- button "放大" [ref=e68] [cursor=pointer]
|
||||||
|
- button "左移" [disabled] [ref=e69]
|
||||||
|
- button "右移" [disabled] [ref=e70]
|
||||||
|
- button "重置" [disabled] [ref=e71]
|
||||||
|
- complementary "选择内容" [ref=e72]:
|
||||||
|
- tablist "选择内容切换项" [ref=e73]:
|
||||||
|
- tab "自然地理区位" [selected] [ref=e74] [cursor=pointer]
|
||||||
|
- tab "设施类别" [ref=e75] [cursor=pointer]
|
||||||
|
- tab "建设阶段" [ref=e76] [cursor=pointer]
|
||||||
|
- tab "规划形式" [ref=e77] [cursor=pointer]
|
||||||
|
- generic [ref=e78]:
|
||||||
|
- generic [ref=e79]: 自然地理区位
|
||||||
|
- generic [ref=e80]: 加载中
|
||||||
81
.playwright-mcp/page-2026-05-12T03-39-25-782Z.yml
Normal file
81
.playwright-mcp/page-2026-05-12T03-39-25-782Z.yml
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
- 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]:
|
||||||
|
- generic "筛选条件" [ref=e5]:
|
||||||
|
- button "模板库 1" [pressed] [ref=e6] [cursor=pointer]:
|
||||||
|
- img [ref=e7]
|
||||||
|
- generic [ref=e9]: 模板库
|
||||||
|
- strong [ref=e10]: "1"
|
||||||
|
- button "指标树形" [ref=e11] [cursor=pointer]:
|
||||||
|
- img [ref=e12]
|
||||||
|
- generic [ref=e19]: 指标树形
|
||||||
|
- button "省市区" [ref=e20] [cursor=pointer]:
|
||||||
|
- img [ref=e21]
|
||||||
|
- generic [ref=e25]: 省市区
|
||||||
|
- button "自然地理区位" [ref=e26] [cursor=pointer]:
|
||||||
|
- img [ref=e27]
|
||||||
|
- generic [ref=e30]: 自然地理区位
|
||||||
|
- button "设施类别" [ref=e31] [cursor=pointer]:
|
||||||
|
- img [ref=e32]
|
||||||
|
- generic [ref=e36]: 设施类别
|
||||||
|
- button "建设阶段" [ref=e37] [cursor=pointer]:
|
||||||
|
- img [ref=e38]
|
||||||
|
- generic [ref=e43]: 建设阶段
|
||||||
|
- button "规划形式" [ref=e44] [cursor=pointer]:
|
||||||
|
- img [ref=e45]
|
||||||
|
- generic [ref=e50]: 规划形式
|
||||||
|
- region "年度总费用图表" [ref=e51]:
|
||||||
|
- generic [ref=e52]:
|
||||||
|
- button "纵坐标:造价(元)" [ref=e54] [cursor=pointer]: 造价(元)
|
||||||
|
- generic [ref=e55]:
|
||||||
|
- figure "图表,共有0个系列":
|
||||||
|
- generic [ref=e56]:
|
||||||
|
- img "interactive chart":
|
||||||
|
- generic:
|
||||||
|
- img
|
||||||
|
- img
|
||||||
|
- region [ref=e57]
|
||||||
|
- toolbar "标注" [ref=e58]:
|
||||||
|
- button "全屏(F11)" [disabled] [ref=e59]
|
||||||
|
- button "均" [disabled] [ref=e60]:
|
||||||
|
- generic: 均
|
||||||
|
- button "Line Tool" [disabled] [ref=e61]
|
||||||
|
- button "Text Tool" [disabled] [ref=e62]
|
||||||
|
- button "Shape Tool" [disabled] [ref=e63]
|
||||||
|
- button "Fibonacci Tool" [disabled] [ref=e64]
|
||||||
|
- button "Clear annotations" [disabled] [ref=e65]
|
||||||
|
- status:
|
||||||
|
- generic: 请选择右侧分类项
|
||||||
|
- toolbar "缩放" [ref=e66]:
|
||||||
|
- button "缩小" [disabled] [ref=e67]
|
||||||
|
- button "放大" [ref=e68] [cursor=pointer]
|
||||||
|
- button "左移" [disabled] [ref=e69]
|
||||||
|
- button "右移" [disabled] [ref=e70]
|
||||||
|
- button "重置" [disabled] [ref=e71]
|
||||||
|
- complementary "选择内容" [ref=e72]:
|
||||||
|
- tablist "选择内容切换项" [ref=e73]:
|
||||||
|
- tab "自然地理区位" [selected] [ref=e74] [cursor=pointer]
|
||||||
|
- tab "设施类别" [ref=e75] [cursor=pointer]
|
||||||
|
- tab "建设阶段" [ref=e76] [cursor=pointer]
|
||||||
|
- tab "规划形式" [ref=e77] [cursor=pointer]
|
||||||
|
- generic [ref=e78]:
|
||||||
|
- generic [ref=e79]: 自然地理区位
|
||||||
|
- generic [ref=e80]: 加载中
|
||||||
81
.playwright-mcp/page-2026-05-12T03-41-18-222Z.yml
Normal file
81
.playwright-mcp/page-2026-05-12T03-41-18-222Z.yml
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
- 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]:
|
||||||
|
- generic "筛选条件" [ref=e5]:
|
||||||
|
- button "模板库 1" [pressed] [ref=e6] [cursor=pointer]:
|
||||||
|
- img [ref=e7]
|
||||||
|
- generic [ref=e9]: 模板库
|
||||||
|
- strong [ref=e10]: "1"
|
||||||
|
- button "指标树形" [ref=e11] [cursor=pointer]:
|
||||||
|
- img [ref=e12]
|
||||||
|
- generic [ref=e19]: 指标树形
|
||||||
|
- button "省市区" [ref=e20] [cursor=pointer]:
|
||||||
|
- img [ref=e21]
|
||||||
|
- generic [ref=e25]: 省市区
|
||||||
|
- button "自然地理区位" [ref=e26] [cursor=pointer]:
|
||||||
|
- img [ref=e27]
|
||||||
|
- generic [ref=e30]: 自然地理区位
|
||||||
|
- button "设施类别" [ref=e31] [cursor=pointer]:
|
||||||
|
- img [ref=e32]
|
||||||
|
- generic [ref=e36]: 设施类别
|
||||||
|
- button "建设阶段" [ref=e37] [cursor=pointer]:
|
||||||
|
- img [ref=e38]
|
||||||
|
- generic [ref=e43]: 建设阶段
|
||||||
|
- button "规划形式" [ref=e44] [cursor=pointer]:
|
||||||
|
- img [ref=e45]
|
||||||
|
- generic [ref=e50]: 规划形式
|
||||||
|
- region "年度总费用图表" [ref=e51]:
|
||||||
|
- generic [ref=e52]:
|
||||||
|
- button "纵坐标:造价(元)" [ref=e54] [cursor=pointer]: 造价(元)
|
||||||
|
- generic [ref=e55]:
|
||||||
|
- figure "图表,共有0个系列":
|
||||||
|
- generic [ref=e56]:
|
||||||
|
- img "interactive chart":
|
||||||
|
- generic:
|
||||||
|
- img
|
||||||
|
- img
|
||||||
|
- region [ref=e57]
|
||||||
|
- toolbar "标注" [ref=e58]:
|
||||||
|
- button "全屏(F11)" [disabled] [ref=e59]
|
||||||
|
- button "均" [disabled] [ref=e60]:
|
||||||
|
- generic: 均
|
||||||
|
- button "Line Tool" [disabled] [ref=e61]
|
||||||
|
- button "Text Tool" [disabled] [ref=e62]
|
||||||
|
- button "Shape Tool" [disabled] [ref=e63]
|
||||||
|
- button "Fibonacci Tool" [disabled] [ref=e64]
|
||||||
|
- button "Clear annotations" [disabled] [ref=e65]
|
||||||
|
- status:
|
||||||
|
- generic: 请选择右侧分类项
|
||||||
|
- toolbar "缩放" [ref=e66]:
|
||||||
|
- button "缩小" [disabled] [ref=e67]
|
||||||
|
- button "放大" [ref=e68] [cursor=pointer]
|
||||||
|
- button "左移" [disabled] [ref=e69]
|
||||||
|
- button "右移" [disabled] [ref=e70]
|
||||||
|
- button "重置" [disabled] [ref=e71]
|
||||||
|
- complementary "选择内容" [ref=e72]:
|
||||||
|
- tablist "选择内容切换项" [ref=e73]:
|
||||||
|
- tab "自然地理区位" [selected] [ref=e74] [cursor=pointer]
|
||||||
|
- tab "设施类别" [ref=e75] [cursor=pointer]
|
||||||
|
- tab "建设阶段" [ref=e76] [cursor=pointer]
|
||||||
|
- tab "规划形式" [ref=e77] [cursor=pointer]
|
||||||
|
- generic [ref=e78]:
|
||||||
|
- generic [ref=e79]: 自然地理区位
|
||||||
|
- generic [ref=e80]: 加载中
|
||||||
81
.playwright-mcp/page-2026-05-12T03-48-27-706Z.yml
Normal file
81
.playwright-mcp/page-2026-05-12T03-48-27-706Z.yml
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
- 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]:
|
||||||
|
- generic "筛选条件" [ref=e5]:
|
||||||
|
- button "模板库 1" [pressed] [ref=e6] [cursor=pointer]:
|
||||||
|
- img [ref=e7]
|
||||||
|
- generic [ref=e9]: 模板库
|
||||||
|
- strong [ref=e10]: "1"
|
||||||
|
- button "指标树形" [ref=e11] [cursor=pointer]:
|
||||||
|
- img [ref=e12]
|
||||||
|
- generic [ref=e19]: 指标树形
|
||||||
|
- button "省市区" [ref=e20] [cursor=pointer]:
|
||||||
|
- img [ref=e21]
|
||||||
|
- generic [ref=e25]: 省市区
|
||||||
|
- button "自然地理区位" [ref=e26] [cursor=pointer]:
|
||||||
|
- img [ref=e27]
|
||||||
|
- generic [ref=e30]: 自然地理区位
|
||||||
|
- button "设施类别" [ref=e31] [cursor=pointer]:
|
||||||
|
- img [ref=e32]
|
||||||
|
- generic [ref=e36]: 设施类别
|
||||||
|
- button "建设阶段" [ref=e37] [cursor=pointer]:
|
||||||
|
- img [ref=e38]
|
||||||
|
- generic [ref=e43]: 建设阶段
|
||||||
|
- button "规划形式" [ref=e44] [cursor=pointer]:
|
||||||
|
- img [ref=e45]
|
||||||
|
- generic [ref=e50]: 规划形式
|
||||||
|
- region "年度总费用图表" [ref=e51]:
|
||||||
|
- generic [ref=e52]:
|
||||||
|
- button "纵坐标:造价(元)" [ref=e54] [cursor=pointer]: 造价(元)
|
||||||
|
- generic [ref=e55]:
|
||||||
|
- figure "图表,共有0个系列":
|
||||||
|
- generic [ref=e56]:
|
||||||
|
- img "interactive chart":
|
||||||
|
- generic:
|
||||||
|
- img
|
||||||
|
- img
|
||||||
|
- region [ref=e57]
|
||||||
|
- toolbar "标注" [ref=e58]:
|
||||||
|
- button "均" [disabled] [ref=e59]:
|
||||||
|
- generic: 均
|
||||||
|
- button "Line Tool" [disabled] [ref=e60]
|
||||||
|
- button "Text Tool" [disabled] [ref=e61]
|
||||||
|
- button "Shape Tool" [disabled] [ref=e62]
|
||||||
|
- button "Fibonacci Tool" [disabled] [ref=e63]
|
||||||
|
- button "全屏(F11)" [disabled] [ref=e64]
|
||||||
|
- button "Clear annotations" [disabled] [ref=e65]
|
||||||
|
- status:
|
||||||
|
- generic: 请选择右侧分类项
|
||||||
|
- toolbar "缩放" [ref=e66]:
|
||||||
|
- button "缩小" [disabled] [ref=e67]
|
||||||
|
- button "放大" [ref=e68] [cursor=pointer]
|
||||||
|
- button "左移" [disabled] [ref=e69]
|
||||||
|
- button "右移" [disabled] [ref=e70]
|
||||||
|
- button "重置" [disabled] [ref=e71]
|
||||||
|
- complementary "选择内容" [ref=e72]:
|
||||||
|
- tablist "选择内容切换项" [ref=e73]:
|
||||||
|
- tab "自然地理区位" [selected] [ref=e74] [cursor=pointer]
|
||||||
|
- tab "设施类别" [ref=e75] [cursor=pointer]
|
||||||
|
- tab "建设阶段" [ref=e76] [cursor=pointer]
|
||||||
|
- tab "规划形式" [ref=e77] [cursor=pointer]
|
||||||
|
- generic [ref=e78]:
|
||||||
|
- generic [ref=e79]: 自然地理区位
|
||||||
|
- generic [ref=e80]: 加载中
|
||||||
81
.playwright-mcp/page-2026-05-12T03-50-50-349Z.yml
Normal file
81
.playwright-mcp/page-2026-05-12T03-50-50-349Z.yml
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
- 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]:
|
||||||
|
- generic "筛选条件" [ref=e5]:
|
||||||
|
- button "模板库 1" [pressed] [ref=e6] [cursor=pointer]:
|
||||||
|
- img [ref=e7]
|
||||||
|
- generic [ref=e9]: 模板库
|
||||||
|
- strong [ref=e10]: "1"
|
||||||
|
- button "指标树形" [ref=e11] [cursor=pointer]:
|
||||||
|
- img [ref=e12]
|
||||||
|
- generic [ref=e19]: 指标树形
|
||||||
|
- button "省市区" [ref=e20] [cursor=pointer]:
|
||||||
|
- img [ref=e21]
|
||||||
|
- generic [ref=e25]: 省市区
|
||||||
|
- button "自然地理区位" [ref=e26] [cursor=pointer]:
|
||||||
|
- img [ref=e27]
|
||||||
|
- generic [ref=e30]: 自然地理区位
|
||||||
|
- button "设施类别" [ref=e31] [cursor=pointer]:
|
||||||
|
- img [ref=e32]
|
||||||
|
- generic [ref=e36]: 设施类别
|
||||||
|
- button "建设阶段" [ref=e37] [cursor=pointer]:
|
||||||
|
- img [ref=e38]
|
||||||
|
- generic [ref=e43]: 建设阶段
|
||||||
|
- button "规划形式" [ref=e44] [cursor=pointer]:
|
||||||
|
- img [ref=e45]
|
||||||
|
- generic [ref=e50]: 规划形式
|
||||||
|
- region "年度总费用图表" [ref=e51]:
|
||||||
|
- generic [ref=e52]:
|
||||||
|
- button "纵坐标:造价(元)" [ref=e54] [cursor=pointer]: 造价(元)
|
||||||
|
- generic [ref=e55]:
|
||||||
|
- figure "图表,共有0个系列":
|
||||||
|
- generic [ref=e56]:
|
||||||
|
- img "interactive chart":
|
||||||
|
- generic:
|
||||||
|
- img
|
||||||
|
- img
|
||||||
|
- region [ref=e57]
|
||||||
|
- toolbar "标注" [ref=e58]:
|
||||||
|
- button "均" [disabled] [ref=e59]:
|
||||||
|
- generic: 均
|
||||||
|
- button "Line Tool" [disabled] [ref=e60]
|
||||||
|
- button "Text Tool" [disabled] [ref=e61]
|
||||||
|
- button "Shape Tool" [disabled] [ref=e62]
|
||||||
|
- button "Fibonacci Tool" [disabled] [ref=e63]
|
||||||
|
- button "全屏(F11)" [disabled] [ref=e64]
|
||||||
|
- button "Clear annotations" [disabled] [ref=e65]
|
||||||
|
- status:
|
||||||
|
- generic: 请选择右侧分类项
|
||||||
|
- toolbar "缩放" [ref=e66]:
|
||||||
|
- button "缩小" [disabled] [ref=e67]
|
||||||
|
- button "放大" [ref=e68] [cursor=pointer]
|
||||||
|
- button "左移" [disabled] [ref=e69]
|
||||||
|
- button "右移" [disabled] [ref=e70]
|
||||||
|
- button "重置" [disabled] [ref=e71]
|
||||||
|
- complementary "选择内容" [ref=e72]:
|
||||||
|
- tablist "选择内容切换项" [ref=e73]:
|
||||||
|
- tab "自然地理区位" [selected] [ref=e74] [cursor=pointer]
|
||||||
|
- tab "设施类别" [ref=e75] [cursor=pointer]
|
||||||
|
- tab "建设阶段" [ref=e76] [cursor=pointer]
|
||||||
|
- tab "规划形式" [ref=e77] [cursor=pointer]
|
||||||
|
- generic [ref=e78]:
|
||||||
|
- generic [ref=e79]: 自然地理区位
|
||||||
|
- generic [ref=e80]: 加载中
|
||||||
80
.playwright-mcp/page-2026-05-12T04-17-38-470Z.yml
Normal file
80
.playwright-mcp/page-2026-05-12T04-17-38-470Z.yml
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
- 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]:
|
||||||
|
- generic "筛选条件" [ref=e5]:
|
||||||
|
- button "省市区" [ref=e6] [cursor=pointer]:
|
||||||
|
- img [ref=e7]
|
||||||
|
- generic [ref=e11]: 省市区
|
||||||
|
- button "自然地理区位" [ref=e12] [cursor=pointer]:
|
||||||
|
- img [ref=e13]
|
||||||
|
- generic [ref=e16]: 自然地理区位
|
||||||
|
- button "设施类别" [ref=e17] [cursor=pointer]:
|
||||||
|
- img [ref=e18]
|
||||||
|
- generic [ref=e22]: 设施类别
|
||||||
|
- button "建设阶段" [ref=e23] [cursor=pointer]:
|
||||||
|
- img [ref=e24]
|
||||||
|
- generic [ref=e29]: 建设阶段
|
||||||
|
- button "规划形式" [ref=e30] [cursor=pointer]:
|
||||||
|
- img [ref=e31]
|
||||||
|
- generic [ref=e36]: 规划形式
|
||||||
|
- region "年度总费用图表" [ref=e37]:
|
||||||
|
- generic [ref=e38]:
|
||||||
|
- button "纵坐标:造价(元)" [ref=e40] [cursor=pointer]: 造价(元)
|
||||||
|
- generic [ref=e41]:
|
||||||
|
- figure "图表,共有0个系列":
|
||||||
|
- generic [ref=e42]:
|
||||||
|
- img "interactive chart":
|
||||||
|
- generic:
|
||||||
|
- img
|
||||||
|
- img
|
||||||
|
- region [ref=e43]
|
||||||
|
- toolbar "标注" [ref=e44]:
|
||||||
|
- button "库" [disabled] [ref=e45]:
|
||||||
|
- generic:
|
||||||
|
- generic: 库
|
||||||
|
- button "树" [disabled] [ref=e46]:
|
||||||
|
- generic:
|
||||||
|
- generic: 树
|
||||||
|
- button "均" [disabled] [ref=e47]:
|
||||||
|
- generic: 均
|
||||||
|
- button "Line Tool" [disabled] [ref=e48]
|
||||||
|
- button "Text Tool" [disabled] [ref=e49]
|
||||||
|
- button "Shape Tool" [disabled] [ref=e50]
|
||||||
|
- button "Fibonacci Tool" [disabled] [ref=e51]
|
||||||
|
- button "全屏(F11)" [disabled] [ref=e52]
|
||||||
|
- button "Clear annotations" [disabled] [ref=e53]
|
||||||
|
- status:
|
||||||
|
- generic: 请选择右侧分类项
|
||||||
|
- toolbar "缩放" [ref=e54]:
|
||||||
|
- button "缩小" [disabled] [ref=e55]
|
||||||
|
- button "放大" [ref=e56] [cursor=pointer]
|
||||||
|
- button "左移" [disabled] [ref=e57]
|
||||||
|
- button "右移" [disabled] [ref=e58]
|
||||||
|
- button "重置" [disabled] [ref=e59]
|
||||||
|
- complementary "选择内容" [ref=e60]:
|
||||||
|
- tablist "选择内容切换项" [ref=e61]:
|
||||||
|
- tab "自然地理区位" [selected] [ref=e62] [cursor=pointer]
|
||||||
|
- tab "设施类别" [ref=e63] [cursor=pointer]
|
||||||
|
- tab "建设阶段" [ref=e64] [cursor=pointer]
|
||||||
|
- tab "规划形式" [ref=e65] [cursor=pointer]
|
||||||
|
- generic [ref=e66]:
|
||||||
|
- generic [ref=e67]: 自然地理区位
|
||||||
|
- generic [ref=e68]: 加载中
|
||||||
BIN
fullscreen-button-position.png
Normal file
BIN
fullscreen-button-position.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 78 KiB |
393
src/App.tsx
393
src/App.tsx
@ -2,7 +2,7 @@ import { useEffect, useMemo, useRef, useState } from 'react';
|
|||||||
import { AgCharts } from 'ag-charts-react';
|
import { AgCharts } from 'ag-charts-react';
|
||||||
import type { AgCartesianChartOptions } from 'ag-charts-community';
|
import type { AgCartesianChartOptions } from 'ag-charts-community';
|
||||||
import { ModuleRegistry } from 'ag-charts-community';
|
import { ModuleRegistry } from 'ag-charts-community';
|
||||||
import { Building2, Construction, LayoutGrid, LocateFixed, MapPinned } from 'lucide-react';
|
import { Building2, Construction, LayoutGrid, Library, LocateFixed, MapPinned, Waypoints } from 'lucide-react';
|
||||||
import {
|
import {
|
||||||
AnnotationsModule,
|
AnnotationsModule,
|
||||||
ContextMenuModule,
|
ContextMenuModule,
|
||||||
@ -41,12 +41,15 @@ const contentOptions = [
|
|||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
const filterOptions = [
|
const filterOptions = [
|
||||||
|
{ key: 'templateLibrary', label: '模板库', icon: Library },
|
||||||
|
{ key: 'indicatorTree', label: '指标树形', icon: Waypoints },
|
||||||
{ key: 'region', label: '省市区', icon: MapPinned },
|
{ key: 'region', label: '省市区', icon: MapPinned },
|
||||||
{ key: 'geoLocation', label: '自然地理区位', icon: LocateFixed },
|
{ key: 'geoLocation', label: '自然地理区位', icon: LocateFixed },
|
||||||
{ key: 'facilityType', label: '设施类别', icon: Building2 },
|
{ key: 'facilityType', label: '设施类别', icon: Building2 },
|
||||||
{ key: 'constructionStage', label: '建设阶段', icon: Construction },
|
{ key: 'constructionStage', label: '建设阶段', icon: Construction },
|
||||||
{ key: 'planningForm', label: '规划形式', icon: LayoutGrid },
|
{ key: 'planningForm', label: '规划形式', icon: LayoutGrid },
|
||||||
] as const;
|
] as const;
|
||||||
|
const chartFilterOptions = filterOptions.filter((option) => option.key !== 'templateLibrary' && option.key !== 'indicatorTree');
|
||||||
|
|
||||||
const browserTreeDefaults = {
|
const browserTreeDefaults = {
|
||||||
treetype: '256',
|
treetype: '256',
|
||||||
@ -96,6 +99,11 @@ const contentTreeConfigs = {
|
|||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
const chartLineColors = ['#0078a8', '#d14d72', '#1f8f4d', '#d96f23', '#6b5cc8', '#0d7680', '#9a6b12', '#b24b38'];
|
const chartLineColors = ['#0078a8', '#d14d72', '#1f8f4d', '#d96f23', '#6b5cc8', '#0d7680', '#9a6b12', '#b24b38'];
|
||||||
|
const defaultTemplateFilterNode = {
|
||||||
|
id: '3',
|
||||||
|
filterKey: 'templateLibrary',
|
||||||
|
label: '默认模板',
|
||||||
|
} as const;
|
||||||
|
|
||||||
// const mockGeoLocationPayload = {
|
// const mockGeoLocationPayload = {
|
||||||
// checkStrictly: true,
|
// checkStrictly: true,
|
||||||
@ -291,6 +299,60 @@ function normalizeTreeRows(rows: unknown[]): TreeNode[] {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeFlatTemplateLibraryRows(rows: unknown[]): TreeNode[] {
|
||||||
|
return rows
|
||||||
|
.filter((row): row is Record<string, unknown> => !!row && typeof row === 'object')
|
||||||
|
.map((row, index) => {
|
||||||
|
const id = readText(row, ['id', 'mainid', 'mbid']) || `node-${index}`;
|
||||||
|
const label = readText(row, ['mbmc', 'label', 'name', 'title', 'text']) || id;
|
||||||
|
return createFilterTreeNode(id, label);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeFlatIndicatorRows(rows: unknown[]): TreeNode[] {
|
||||||
|
const sourceRows = rows.filter((row): row is Record<string, unknown> => !!row && typeof row === 'object');
|
||||||
|
const rowsById = new Map<string, Record<string, unknown>>();
|
||||||
|
const childrenByParent = new Map<string, string[]>();
|
||||||
|
|
||||||
|
sourceRows.forEach((row, index) => {
|
||||||
|
const id = readText(row, ['zbid', 'zjzbk', 'id']) || `node-${index}`;
|
||||||
|
if (!id) return;
|
||||||
|
rowsById.set(id, row);
|
||||||
|
|
||||||
|
const parentId = readText(row, ['sj', 'parentId', 'parentid', 'pid', 'pId']) || '';
|
||||||
|
const children = childrenByParent.get(parentId) || [];
|
||||||
|
children.push(id);
|
||||||
|
childrenByParent.set(parentId, children);
|
||||||
|
});
|
||||||
|
|
||||||
|
const buildNode = (id: string): TreeNode => {
|
||||||
|
const row = rowsById.get(id) || {};
|
||||||
|
const children = (childrenByParent.get(id) || [])
|
||||||
|
.filter((childId) => rowsById.has(childId))
|
||||||
|
.map(buildNode);
|
||||||
|
const label = readText(row, ['label', 'name', 'title', 'text', 'zbbh', 'mbmc']) || id;
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
label,
|
||||||
|
children,
|
||||||
|
hasChildren: children.length > 0,
|
||||||
|
canClick: true,
|
||||||
|
expanded: children.length > 0,
|
||||||
|
loading: false,
|
||||||
|
loaded: true,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return Array.from(rowsById.keys())
|
||||||
|
.filter((id) => {
|
||||||
|
const row = rowsById.get(id);
|
||||||
|
if (!row) return false;
|
||||||
|
const parentId = readText(row, ['sj', 'parentId', 'parentid', 'pid', 'pId']) || '';
|
||||||
|
return !parentId || parentId === '0' || parentId === '0_0' || !rowsById.has(parentId);
|
||||||
|
})
|
||||||
|
.map(buildNode);
|
||||||
|
}
|
||||||
|
|
||||||
const regionFieldKeys = {
|
const regionFieldKeys = {
|
||||||
provinceId: ['provinceId', 'province_id', 'provinceid', 'sfid', 'sf_id', 'shengId', 'sheng_id', 'sheng'],
|
provinceId: ['provinceId', 'province_id', 'provinceid', 'sfid', 'sf_id', 'shengId', 'sheng_id', 'sheng'],
|
||||||
provinceName: ['provinceName', 'province_name', 'province', 'sfmc', 'sf', 'shengName', 'sheng_name', 'shengmc'],
|
provinceName: ['provinceName', 'province_name', 'province', 'sfmc', 'sf', 'shengName', 'sheng_name', 'shengmc'],
|
||||||
@ -384,12 +446,56 @@ function getFilterSelectionKey(filterKey: FilterKey, nodeId: string) {
|
|||||||
return `${filterKey}:${nodeId}`;
|
return `${filterKey}:${nodeId}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSeriesValueKey(index: number) {
|
function getSeriesValueKey(contentKey: ContentKey, nodeId: string) {
|
||||||
return `amount${index}`;
|
return `amount_${getSelectionKey(contentKey, nodeId).replace(/[^a-zA-Z0-9_]/g, '_')}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function compareGroupNames(a: string, b: string) {
|
||||||
|
const numberA = Number(a);
|
||||||
|
const numberB = Number(b);
|
||||||
|
if (Number.isFinite(numberA) && Number.isFinite(numberB)) {
|
||||||
|
return numberA - numberB;
|
||||||
|
}
|
||||||
|
return a.localeCompare(b, 'zh-CN', { numeric: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
function isContentFilterKey(filterKey: FilterKey): filterKey is ContentKey {
|
function isContentFilterKey(filterKey: FilterKey): filterKey is ContentKey {
|
||||||
return filterKey !== 'region';
|
return Object.prototype.hasOwnProperty.call(contentTreeConfigs, filterKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isTemplateFilterKey(filterKey: FilterKey): filterKey is 'templateLibrary' {
|
||||||
|
return filterKey === 'templateLibrary';
|
||||||
|
}
|
||||||
|
|
||||||
|
function isIndicatorTreeFilterKey(filterKey: FilterKey): filterKey is 'indicatorTree' {
|
||||||
|
return filterKey === 'indicatorTree';
|
||||||
|
}
|
||||||
|
|
||||||
|
function isSingleSelectFilterKey(filterKey: FilterKey) {
|
||||||
|
return isTemplateFilterKey(filterKey) || isIndicatorTreeFilterKey(filterKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDefaultTemplateFilterNodes(): SelectedFilterNode[] {
|
||||||
|
return [{ ...defaultTemplateFilterNode }];
|
||||||
|
}
|
||||||
|
|
||||||
|
function isDefaultTemplateSelection(nodes: SelectedFilterNode[]) {
|
||||||
|
return nodes.length === 1 && nodes[0]?.id === defaultTemplateFilterNode.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDefaultIndicatorTreeFilterNodes(nodes: TreeNode[]): SelectedFilterNode[] {
|
||||||
|
const defaultNode = nodes[0];
|
||||||
|
if (!defaultNode) return [];
|
||||||
|
return [{
|
||||||
|
id: defaultNode.id,
|
||||||
|
filterKey: 'indicatorTree',
|
||||||
|
label: defaultNode.label,
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
function isDefaultIndicatorTreeSelection(nodes: SelectedFilterNode[], treeNodes: TreeNode[]) {
|
||||||
|
const defaultNode = treeNodes[0];
|
||||||
|
return Boolean(defaultNode) && nodes.length === 1 && nodes[0]?.id === defaultNode?.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterTreeNodesByKeyword(nodes: TreeNode[], keyword: string): TreeNode[] {
|
function filterTreeNodesByKeyword(nodes: TreeNode[], keyword: string): TreeNode[] {
|
||||||
@ -516,6 +622,8 @@ function App() {
|
|||||||
planningForm: false,
|
planningForm: false,
|
||||||
});
|
});
|
||||||
const filterTreeInitialLoadStartedRef = useRef<Record<FilterKey, boolean>>({
|
const filterTreeInitialLoadStartedRef = useRef<Record<FilterKey, boolean>>({
|
||||||
|
templateLibrary: false,
|
||||||
|
indicatorTree: false,
|
||||||
region: false,
|
region: false,
|
||||||
geoLocation: false,
|
geoLocation: false,
|
||||||
facilityType: false,
|
facilityType: false,
|
||||||
@ -553,6 +661,8 @@ function App() {
|
|||||||
const [loadError, setLoadError] = useState<string | null>(null);
|
const [loadError, setLoadError] = useState<string | null>(null);
|
||||||
const [loadingHint, setLoadingHint] = useState('');
|
const [loadingHint, setLoadingHint] = useState('');
|
||||||
const [filterTreeByKey, setFilterTreeByKey] = useState<Record<FilterKey, TreeNode[]>>({
|
const [filterTreeByKey, setFilterTreeByKey] = useState<Record<FilterKey, TreeNode[]>>({
|
||||||
|
templateLibrary: [],
|
||||||
|
indicatorTree: [],
|
||||||
region: [],
|
region: [],
|
||||||
geoLocation: [],
|
geoLocation: [],
|
||||||
facilityType: [],
|
facilityType: [],
|
||||||
@ -560,6 +670,8 @@ function App() {
|
|||||||
planningForm: [],
|
planningForm: [],
|
||||||
});
|
});
|
||||||
const [filterTreeLoadingByKey, setFilterTreeLoadingByKey] = useState<Record<FilterKey, boolean>>({
|
const [filterTreeLoadingByKey, setFilterTreeLoadingByKey] = useState<Record<FilterKey, boolean>>({
|
||||||
|
templateLibrary: false,
|
||||||
|
indicatorTree: false,
|
||||||
region: false,
|
region: false,
|
||||||
geoLocation: false,
|
geoLocation: false,
|
||||||
facilityType: false,
|
facilityType: false,
|
||||||
@ -567,6 +679,8 @@ function App() {
|
|||||||
planningForm: false,
|
planningForm: false,
|
||||||
});
|
});
|
||||||
const [filterTreeErrorByKey, setFilterTreeErrorByKey] = useState<Record<FilterKey, string | null>>({
|
const [filterTreeErrorByKey, setFilterTreeErrorByKey] = useState<Record<FilterKey, string | null>>({
|
||||||
|
templateLibrary: null,
|
||||||
|
indicatorTree: null,
|
||||||
region: null,
|
region: null,
|
||||||
geoLocation: null,
|
geoLocation: null,
|
||||||
facilityType: null,
|
facilityType: null,
|
||||||
@ -574,6 +688,8 @@ function App() {
|
|||||||
planningForm: null,
|
planningForm: null,
|
||||||
});
|
});
|
||||||
const [filterSearchTreeByKey, setFilterSearchTreeByKey] = useState<Record<FilterKey, TreeNode[]>>({
|
const [filterSearchTreeByKey, setFilterSearchTreeByKey] = useState<Record<FilterKey, TreeNode[]>>({
|
||||||
|
templateLibrary: [],
|
||||||
|
indicatorTree: [],
|
||||||
region: [],
|
region: [],
|
||||||
geoLocation: [],
|
geoLocation: [],
|
||||||
facilityType: [],
|
facilityType: [],
|
||||||
@ -581,6 +697,8 @@ function App() {
|
|||||||
planningForm: [],
|
planningForm: [],
|
||||||
});
|
});
|
||||||
const [filterSearchLoadingByKey, setFilterSearchLoadingByKey] = useState<Record<FilterKey, boolean>>({
|
const [filterSearchLoadingByKey, setFilterSearchLoadingByKey] = useState<Record<FilterKey, boolean>>({
|
||||||
|
templateLibrary: false,
|
||||||
|
indicatorTree: false,
|
||||||
region: false,
|
region: false,
|
||||||
geoLocation: false,
|
geoLocation: false,
|
||||||
facilityType: false,
|
facilityType: false,
|
||||||
@ -588,6 +706,8 @@ function App() {
|
|||||||
planningForm: false,
|
planningForm: false,
|
||||||
});
|
});
|
||||||
const [filterSearchErrorByKey, setFilterSearchErrorByKey] = useState<Record<FilterKey, string | null>>({
|
const [filterSearchErrorByKey, setFilterSearchErrorByKey] = useState<Record<FilterKey, string | null>>({
|
||||||
|
templateLibrary: null,
|
||||||
|
indicatorTree: null,
|
||||||
region: null,
|
region: null,
|
||||||
geoLocation: null,
|
geoLocation: null,
|
||||||
facilityType: null,
|
facilityType: null,
|
||||||
@ -595,6 +715,8 @@ function App() {
|
|||||||
planningForm: null,
|
planningForm: null,
|
||||||
});
|
});
|
||||||
const [appliedFilters, setAppliedFilters] = useState<Record<FilterKey, SelectedFilterNode[]>>({
|
const [appliedFilters, setAppliedFilters] = useState<Record<FilterKey, SelectedFilterNode[]>>({
|
||||||
|
templateLibrary: getDefaultTemplateFilterNodes(),
|
||||||
|
indicatorTree: [],
|
||||||
region: [],
|
region: [],
|
||||||
geoLocation: [],
|
geoLocation: [],
|
||||||
facilityType: [],
|
facilityType: [],
|
||||||
@ -607,6 +729,8 @@ function App() {
|
|||||||
const filterSearchComposingRef = useRef(false);
|
const filterSearchComposingRef = useRef(false);
|
||||||
const filterSearchTimerRef = useRef<number | null>(null);
|
const filterSearchTimerRef = useRef<number | null>(null);
|
||||||
const filterSearchRequestSeqRef = useRef<Record<FilterKey, number>>({
|
const filterSearchRequestSeqRef = useRef<Record<FilterKey, number>>({
|
||||||
|
templateLibrary: 0,
|
||||||
|
indicatorTree: 0,
|
||||||
region: 0,
|
region: 0,
|
||||||
geoLocation: 0,
|
geoLocation: 0,
|
||||||
facilityType: 0,
|
facilityType: 0,
|
||||||
@ -629,7 +753,14 @@ function App() {
|
|||||||
const activeFilterTreeError = filterModalKey
|
const activeFilterTreeError = filterModalKey
|
||||||
? trimmedFilterSearchValue ? filterSearchErrorByKey[filterModalKey] : filterTreeErrorByKey[filterModalKey]
|
? trimmedFilterSearchValue ? filterSearchErrorByKey[filterModalKey] : filterTreeErrorByKey[filterModalKey]
|
||||||
: null;
|
: null;
|
||||||
const activeFilterCount = Object.values(appliedFilters).reduce((total, nodes) => total + nodes.length, 0);
|
const selectedTemplateId = appliedFilters.templateLibrary[0]?.id || defaultTemplateFilterNode.id;
|
||||||
|
const defaultIndicatorTreeNodes = useMemo(
|
||||||
|
() => getDefaultIndicatorTreeFilterNodes(filterTreeByKey.indicatorTree),
|
||||||
|
[filterTreeByKey.indicatorTree],
|
||||||
|
);
|
||||||
|
const activeFilterCount = Object.entries(appliedFilters).reduce((total, [key, nodes]) => (
|
||||||
|
key === 'templateLibrary' && isDefaultTemplateSelection(nodes) ? total : total + nodes.length
|
||||||
|
), 0);
|
||||||
const chartEmptyText = selectedContentNodes.length === 0
|
const chartEmptyText = selectedContentNodes.length === 0
|
||||||
? '请选择右侧分类项'
|
? '请选择右侧分类项'
|
||||||
: activeFilterCount > 0
|
: activeFilterCount > 0
|
||||||
@ -743,6 +874,36 @@ function App() {
|
|||||||
return flatRegionTree.length > 0 ? flatRegionTree : normalizeBackendTree(normalizeTreeRows(rows));
|
return flatRegionTree.length > 0 ? flatRegionTree : normalizeBackendTree(normalizeTreeRows(rows));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const fetchTemplateLibraryTree = async (signal?: AbortSignal) => {
|
||||||
|
const response = await fetch(`${API_BASE_URL}/zw/getBuildingFunctionCostFilterTree?${buildQuery({ key: 'templateLibrary' })}`, {
|
||||||
|
signal,
|
||||||
|
headers: {
|
||||||
|
'X-Requested-With': 'XMLHttpRequest',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP ${response.status}`);
|
||||||
|
}
|
||||||
|
const rows = pickArray(await response.json());
|
||||||
|
const templateRows = normalizeFlatTemplateLibraryRows(rows);
|
||||||
|
return templateRows.length > 0 ? templateRows : normalizeBackendTree(normalizeTreeRows(rows));
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchIndicatorTree = async (signal?: AbortSignal) => {
|
||||||
|
const response = await fetch(`${API_BASE_URL}/zw/getBuildingFunctionCostFilterTree?${buildQuery({ key: 'indicatorTree', templateId: selectedTemplateId })}`, {
|
||||||
|
signal,
|
||||||
|
headers: {
|
||||||
|
'X-Requested-With': 'XMLHttpRequest',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP ${response.status}`);
|
||||||
|
}
|
||||||
|
const rows = pickArray(await response.json());
|
||||||
|
const indicatorRows = normalizeFlatIndicatorRows(rows);
|
||||||
|
return indicatorRows.length > 0 ? indicatorRows : normalizeBackendTree(normalizeTreeRows(rows));
|
||||||
|
};
|
||||||
|
|
||||||
const fetchBackendFilterTreeSearch = async (filterKey: FilterKey, keyword: string, signal?: AbortSignal) => {
|
const fetchBackendFilterTreeSearch = async (filterKey: FilterKey, keyword: string, signal?: AbortSignal) => {
|
||||||
const response = await fetch(`${API_BASE_URL}/zw/getBuildingFunctionCostFilterTreeSearch?${buildQuery({
|
const response = await fetch(`${API_BASE_URL}/zw/getBuildingFunctionCostFilterTreeSearch?${buildQuery({
|
||||||
key: filterKey,
|
key: filterKey,
|
||||||
@ -791,10 +952,21 @@ function App() {
|
|||||||
const nodes = await fetchRegionFilterTree(signal);
|
const nodes = await fetchRegionFilterTree(signal);
|
||||||
return keyword?.trim() ? filterTreeNodesByKeyword(nodes, keyword) : nodes;
|
return keyword?.trim() ? filterTreeNodesByKeyword(nodes, keyword) : nodes;
|
||||||
}
|
}
|
||||||
if (keyword?.trim()) {
|
if (isTemplateFilterKey(filterKey)) {
|
||||||
|
const nodes = await fetchTemplateLibraryTree(signal);
|
||||||
|
return keyword?.trim() ? filterTreeNodesByKeyword(nodes, keyword) : nodes;
|
||||||
|
}
|
||||||
|
if (filterKey === 'indicatorTree') {
|
||||||
|
const nodes = await fetchIndicatorTree(signal);
|
||||||
|
return keyword?.trim() ? filterTreeNodesByKeyword(nodes, keyword) : nodes;
|
||||||
|
}
|
||||||
|
if (keyword?.trim() && isContentFilterKey(filterKey)) {
|
||||||
return fetchBackendFilterTreeSearch(filterKey, keyword, signal);
|
return fetchBackendFilterTreeSearch(filterKey, keyword, signal);
|
||||||
}
|
}
|
||||||
return loadContentTreeWithDefaultExpansion(filterKey);
|
if (isContentFilterKey(filterKey)) {
|
||||||
|
return loadContentTreeWithDefaultExpansion(filterKey);
|
||||||
|
}
|
||||||
|
return [];
|
||||||
};
|
};
|
||||||
|
|
||||||
const toggleContentNode = (nodeId: string) => {
|
const toggleContentNode = (nodeId: string) => {
|
||||||
@ -880,6 +1052,17 @@ function App() {
|
|||||||
setLoading(false);
|
setLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const resetIndicatorTreeState = () => {
|
||||||
|
filterTreeInitialLoadStartedRef.current.indicatorTree = false;
|
||||||
|
filterSearchRequestSeqRef.current.indicatorTree += 1;
|
||||||
|
setFilterTreeByKey((current) => ({ ...current, indicatorTree: [] }));
|
||||||
|
setFilterTreeLoadingByKey((current) => ({ ...current, indicatorTree: false }));
|
||||||
|
setFilterTreeErrorByKey((current) => ({ ...current, indicatorTree: null }));
|
||||||
|
setFilterSearchTreeByKey((current) => ({ ...current, indicatorTree: [] }));
|
||||||
|
setFilterSearchLoadingByKey((current) => ({ ...current, indicatorTree: false }));
|
||||||
|
setFilterSearchErrorByKey((current) => ({ ...current, indicatorTree: null }));
|
||||||
|
};
|
||||||
|
|
||||||
const ensureFilterTreeLoaded = (filterKey: FilterKey) => {
|
const ensureFilterTreeLoaded = (filterKey: FilterKey) => {
|
||||||
if (filterTreeByKey[filterKey].length > 0 || filterTreeInitialLoadStartedRef.current[filterKey]) return;
|
if (filterTreeByKey[filterKey].length > 0 || filterTreeInitialLoadStartedRef.current[filterKey]) return;
|
||||||
|
|
||||||
@ -904,7 +1087,11 @@ function App() {
|
|||||||
|
|
||||||
const openFilterModal = (filterKey: FilterKey) => {
|
const openFilterModal = (filterKey: FilterKey) => {
|
||||||
setFilterModalKey(filterKey);
|
setFilterModalKey(filterKey);
|
||||||
setDraftFilterNodes(appliedFilters[filterKey]);
|
if (isIndicatorTreeFilterKey(filterKey) && appliedFilters[filterKey].length === 0 && defaultIndicatorTreeNodes.length > 0) {
|
||||||
|
setDraftFilterNodes(defaultIndicatorTreeNodes);
|
||||||
|
} else {
|
||||||
|
setDraftFilterNodes(appliedFilters[filterKey]);
|
||||||
|
}
|
||||||
setFilterSearchValue('');
|
setFilterSearchValue('');
|
||||||
lastFilterSearchRef.current = '';
|
lastFilterSearchRef.current = '';
|
||||||
if (filterSearchTimerRef.current != null) {
|
if (filterSearchTimerRef.current != null) {
|
||||||
@ -950,6 +1137,19 @@ function App() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isTemplateFilterKey(filterKey) || filterKey === 'indicatorTree') {
|
||||||
|
filterSearchTimerRef.current = window.setTimeout(() => {
|
||||||
|
setFilterSearchLoadingByKey((current) => ({ ...current, [filterKey]: true }));
|
||||||
|
setFilterSearchErrorByKey((current) => ({ ...current, [filterKey]: null }));
|
||||||
|
setFilterSearchTreeByKey((current) => ({
|
||||||
|
...current,
|
||||||
|
[filterKey]: filterTreeNodesByKeyword(filterTreeByKey[filterKey], keyword),
|
||||||
|
}));
|
||||||
|
setFilterSearchLoadingByKey((current) => ({ ...current, [filterKey]: false }));
|
||||||
|
}, 300);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
filterSearchTimerRef.current = window.setTimeout(() => {
|
filterSearchTimerRef.current = window.setTimeout(() => {
|
||||||
setFilterSearchLoadingByKey((current) => ({ ...current, [filterKey]: true }));
|
setFilterSearchLoadingByKey((current) => ({ ...current, [filterKey]: true }));
|
||||||
setFilterSearchErrorByKey((current) => ({ ...current, [filterKey]: null }));
|
setFilterSearchErrorByKey((current) => ({ ...current, [filterKey]: null }));
|
||||||
@ -1032,6 +1232,12 @@ function App() {
|
|||||||
setDraftFilterNodes((current) => {
|
setDraftFilterNodes((current) => {
|
||||||
const selectionKey = getFilterSelectionKey(currentFilterKey, node.id);
|
const selectionKey = getFilterSelectionKey(currentFilterKey, node.id);
|
||||||
const exists = current.some((item) => getFilterSelectionKey(item.filterKey, item.id) === selectionKey);
|
const exists = current.some((item) => getFilterSelectionKey(item.filterKey, item.id) === selectionKey);
|
||||||
|
if (isSingleSelectFilterKey(currentFilterKey)) {
|
||||||
|
if (exists) {
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
return [{ id: node.id, filterKey: currentFilterKey, label: node.label }];
|
||||||
|
}
|
||||||
if (exists) {
|
if (exists) {
|
||||||
return current.filter((item) => getFilterSelectionKey(item.filterKey, item.id) !== selectionKey);
|
return current.filter((item) => getFilterSelectionKey(item.filterKey, item.id) !== selectionKey);
|
||||||
}
|
}
|
||||||
@ -1041,10 +1247,31 @@ function App() {
|
|||||||
|
|
||||||
const applyFilterModal = () => {
|
const applyFilterModal = () => {
|
||||||
if (!filterModalKey) return;
|
if (!filterModalKey) return;
|
||||||
setAppliedFilters((current) => ({
|
let nextDraftNodes = draftFilterNodes;
|
||||||
...current,
|
if (isTemplateFilterKey(filterModalKey) && nextDraftNodes.length === 0) {
|
||||||
[filterModalKey]: draftFilterNodes,
|
nextDraftNodes = getDefaultTemplateFilterNodes();
|
||||||
}));
|
}
|
||||||
|
if (isIndicatorTreeFilterKey(filterModalKey)) {
|
||||||
|
if (nextDraftNodes.length === 0) {
|
||||||
|
nextDraftNodes = defaultIndicatorTreeNodes;
|
||||||
|
}
|
||||||
|
if (isDefaultIndicatorTreeSelection(nextDraftNodes, filterTreeByKey.indicatorTree)) {
|
||||||
|
nextDraftNodes = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setAppliedFilters((current) => {
|
||||||
|
const nextFilters = {
|
||||||
|
...current,
|
||||||
|
[filterModalKey]: nextDraftNodes,
|
||||||
|
};
|
||||||
|
if (isTemplateFilterKey(filterModalKey)) {
|
||||||
|
nextFilters.indicatorTree = [];
|
||||||
|
}
|
||||||
|
return nextFilters;
|
||||||
|
});
|
||||||
|
if (isTemplateFilterKey(filterModalKey)) {
|
||||||
|
resetIndicatorTreeState();
|
||||||
|
}
|
||||||
setChartDataBySelection({});
|
setChartDataBySelection({});
|
||||||
setLoadError(null);
|
setLoadError(null);
|
||||||
if (selectedContentNodes.length > 0) {
|
if (selectedContentNodes.length > 0) {
|
||||||
@ -1056,11 +1283,27 @@ function App() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const clearFilter = (filterKey: FilterKey) => {
|
const clearFilter = (filterKey: FilterKey) => {
|
||||||
if (appliedFilters[filterKey].length === 0) return;
|
const nextNodes = isTemplateFilterKey(filterKey)
|
||||||
setAppliedFilters((current) => ({
|
? getDefaultTemplateFilterNodes()
|
||||||
...current,
|
: isIndicatorTreeFilterKey(filterKey)
|
||||||
[filterKey]: [],
|
? defaultIndicatorTreeNodes
|
||||||
}));
|
: [];
|
||||||
|
if (appliedFilters[filterKey].length === nextNodes.length && appliedFilters[filterKey].every((node, index) => node.id === nextNodes[index]?.id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setAppliedFilters((current) => {
|
||||||
|
const nextFilters = {
|
||||||
|
...current,
|
||||||
|
[filterKey]: nextNodes,
|
||||||
|
};
|
||||||
|
if (isTemplateFilterKey(filterKey)) {
|
||||||
|
nextFilters.indicatorTree = [];
|
||||||
|
}
|
||||||
|
return nextFilters;
|
||||||
|
});
|
||||||
|
if (isTemplateFilterKey(filterKey)) {
|
||||||
|
resetIndicatorTreeState();
|
||||||
|
}
|
||||||
setChartDataBySelection({});
|
setChartDataBySelection({});
|
||||||
setLoadError(null);
|
setLoadError(null);
|
||||||
if (selectedContentNodes.length > 0) {
|
if (selectedContentNodes.length > 0) {
|
||||||
@ -1104,6 +1347,13 @@ function App() {
|
|||||||
});
|
});
|
||||||
}, [activeContentKey, treeByContent]);
|
}, [activeContentKey, treeByContent]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (filterModalKey !== 'indicatorTree') return;
|
||||||
|
if (draftFilterNodes.length > 0) return;
|
||||||
|
if (defaultIndicatorTreeNodes.length === 0) return;
|
||||||
|
setDraftFilterNodes(defaultIndicatorTreeNodes);
|
||||||
|
}, [defaultIndicatorTreeNodes, draftFilterNodes.length, filterModalKey]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const controller = new AbortController();
|
const controller = new AbortController();
|
||||||
|
|
||||||
@ -1136,6 +1386,7 @@ function App() {
|
|||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
groupBy: groupKey,
|
groupBy: groupKey,
|
||||||
metric: requestMetricKey,
|
metric: requestMetricKey,
|
||||||
|
templateId: selectedTemplateId,
|
||||||
filters: appliedFilterPayload,
|
filters: appliedFilterPayload,
|
||||||
nodes: selectedContentNodes.map((node) => ({
|
nodes: selectedContentNodes.map((node) => ({
|
||||||
key: getSelectionKey(node.contentKey, node.id),
|
key: getSelectionKey(node.contentKey, node.id),
|
||||||
@ -1171,16 +1422,37 @@ function App() {
|
|||||||
return () => {
|
return () => {
|
||||||
controller.abort();
|
controller.abort();
|
||||||
};
|
};
|
||||||
}, [appliedFilterPayload, chartQueryVersion, groupKey, metricKey, requestMetricKey, selectedContentNodes]);
|
}, [appliedFilterPayload, chartQueryVersion, groupKey, metricKey, requestMetricKey, selectedContentNodes, selectedTemplateId]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const frame = chartFrameRef.current;
|
const frame = chartFrameRef.current;
|
||||||
const fullscreenTarget = workspaceRef.current;
|
const fullscreenTarget = workspaceRef.current;
|
||||||
if (!frame || !fullscreenTarget) return;
|
if (!frame || !fullscreenTarget) return;
|
||||||
|
|
||||||
const getFullscreenButton = () => frame.querySelector<HTMLButtonElement>('.chart-fullscreen-button');
|
const getTemplateButton = () => frame.querySelector<HTMLElement>('.ag-charts-myButton-template')?.closest<HTMLButtonElement>('.ag-charts-toolbar__button');
|
||||||
|
const getIndicatorButton = () => frame.querySelector<HTMLElement>('.ag-charts-myButton-indicator')?.closest<HTMLButtonElement>('.ag-charts-toolbar__button');
|
||||||
|
const getFullscreenButton = () => frame.querySelector<HTMLElement>('.ag-charts-myButton-fullScreen')?.closest<HTMLButtonElement>('.ag-charts-toolbar__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 setButtonAttribute = (button: HTMLButtonElement, name: string, value: string) => {
|
||||||
|
if (button.getAttribute(name) !== value) {
|
||||||
|
button.setAttribute(name, value);
|
||||||
|
}
|
||||||
|
};
|
||||||
const syncToolbarButtons = () => {
|
const syncToolbarButtons = () => {
|
||||||
|
const templateButton = getTemplateButton();
|
||||||
|
if (templateButton) {
|
||||||
|
templateButton.classList.add('chart-template-button');
|
||||||
|
setButtonAttribute(templateButton, 'aria-disabled', 'false');
|
||||||
|
setButtonAttribute(templateButton, 'aria-expanded', String(filterModalKey === 'templateLibrary'));
|
||||||
|
}
|
||||||
|
|
||||||
|
const indicatorButton = getIndicatorButton();
|
||||||
|
if (indicatorButton) {
|
||||||
|
indicatorButton.classList.add('chart-indicator-button');
|
||||||
|
setButtonAttribute(indicatorButton, 'aria-disabled', 'false');
|
||||||
|
setButtonAttribute(indicatorButton, 'aria-expanded', String(filterModalKey === 'indicatorTree'));
|
||||||
|
}
|
||||||
|
|
||||||
const button = getFullscreenButton();
|
const button = getFullscreenButton();
|
||||||
if (button) {
|
if (button) {
|
||||||
let icon = button.querySelector<HTMLElement>('.ag-charts-myButton-fullScreen');
|
let icon = button.querySelector<HTMLElement>('.ag-charts-myButton-fullScreen');
|
||||||
@ -1190,7 +1462,10 @@ function App() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const isFullscreen = document.fullscreenElement === fullscreenTarget;
|
const isFullscreen = document.fullscreenElement === fullscreenTarget;
|
||||||
|
button.classList.add('chart-fullscreen-button');
|
||||||
button.classList.toggle('ag-charts-toolbar__button--active', isFullscreen);
|
button.classList.toggle('ag-charts-toolbar__button--active', isFullscreen);
|
||||||
|
setButtonAttribute(button, 'aria-disabled', 'false');
|
||||||
|
setButtonAttribute(button, 'aria-pressed', String(isFullscreen));
|
||||||
icon?.classList.toggle('anticon-arrow-salt', !isFullscreen);
|
icon?.classList.toggle('anticon-arrow-salt', !isFullscreen);
|
||||||
icon?.classList.toggle('anticon-shrink', isFullscreen);
|
icon?.classList.toggle('anticon-shrink', isFullscreen);
|
||||||
}
|
}
|
||||||
@ -1198,7 +1473,8 @@ 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));
|
setButtonAttribute(statisticButton, 'aria-disabled', 'false');
|
||||||
|
setButtonAttribute(statisticButton, 'aria-expanded', String(statisticMenuOpen));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1225,14 +1501,22 @@ function App() {
|
|||||||
const handleToolbarClick = (event: MouseEvent) => {
|
const handleToolbarClick = (event: MouseEvent) => {
|
||||||
const target = event.target as Element | null;
|
const target = event.target as Element | null;
|
||||||
const button = target?.closest<HTMLButtonElement>(
|
const button = target?.closest<HTMLButtonElement>(
|
||||||
'.chart-fullscreen-button, .chart-statistic-button',
|
'.chart-template-button, .chart-indicator-button, .chart-fullscreen-button, .chart-statistic-button',
|
||||||
);
|
);
|
||||||
if (!button || !frame.contains(button)) return;
|
if (!button || !frame.contains(button)) return;
|
||||||
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
event.stopImmediatePropagation();
|
event.stopImmediatePropagation();
|
||||||
if (button.classList.contains('chart-statistic-button')) {
|
if (button.classList.contains('chart-template-button')) {
|
||||||
|
setMetricMenuOpen(false);
|
||||||
|
setStatisticMenuOpen(false);
|
||||||
|
openFilterModal('templateLibrary');
|
||||||
|
} else if (button.classList.contains('chart-indicator-button')) {
|
||||||
|
setMetricMenuOpen(false);
|
||||||
|
setStatisticMenuOpen(false);
|
||||||
|
openFilterModal('indicatorTree');
|
||||||
|
} else if (button.classList.contains('chart-statistic-button')) {
|
||||||
setMetricMenuOpen(false);
|
setMetricMenuOpen(false);
|
||||||
setStatisticMenuOpen((open) => !open);
|
setStatisticMenuOpen((open) => !open);
|
||||||
} else {
|
} else {
|
||||||
@ -1245,14 +1529,22 @@ function App() {
|
|||||||
|
|
||||||
const target = event.target as Element | null;
|
const target = event.target as Element | null;
|
||||||
const button = target?.closest<HTMLButtonElement>(
|
const button = target?.closest<HTMLButtonElement>(
|
||||||
'.chart-fullscreen-button, .chart-statistic-button',
|
'.chart-template-button, .chart-indicator-button, .chart-fullscreen-button, .chart-statistic-button',
|
||||||
);
|
);
|
||||||
if (!button || !frame.contains(button)) return;
|
if (!button || !frame.contains(button)) return;
|
||||||
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
event.stopImmediatePropagation();
|
event.stopImmediatePropagation();
|
||||||
if (button.classList.contains('chart-statistic-button')) {
|
if (button.classList.contains('chart-template-button')) {
|
||||||
|
setMetricMenuOpen(false);
|
||||||
|
setStatisticMenuOpen(false);
|
||||||
|
openFilterModal('templateLibrary');
|
||||||
|
} else if (button.classList.contains('chart-indicator-button')) {
|
||||||
|
setMetricMenuOpen(false);
|
||||||
|
setStatisticMenuOpen(false);
|
||||||
|
openFilterModal('indicatorTree');
|
||||||
|
} else if (button.classList.contains('chart-statistic-button')) {
|
||||||
setMetricMenuOpen(false);
|
setMetricMenuOpen(false);
|
||||||
setStatisticMenuOpen((open) => !open);
|
setStatisticMenuOpen((open) => !open);
|
||||||
} else {
|
} else {
|
||||||
@ -1265,6 +1557,11 @@ function App() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const observer = new MutationObserver(syncToolbarButtons);
|
const observer = new MutationObserver(syncToolbarButtons);
|
||||||
|
const initialSyncTimers = [
|
||||||
|
window.setTimeout(syncToolbarButtons, 0),
|
||||||
|
window.setTimeout(syncToolbarButtons, 100),
|
||||||
|
window.setTimeout(syncToolbarButtons, 500),
|
||||||
|
];
|
||||||
document.addEventListener('keydown', handleKeyDown, true);
|
document.addEventListener('keydown', handleKeyDown, true);
|
||||||
document.addEventListener('fullscreenchange', handleFullscreenChange);
|
document.addEventListener('fullscreenchange', handleFullscreenChange);
|
||||||
document.addEventListener('contextmenu', suppressBrowserContextMenu);
|
document.addEventListener('contextmenu', suppressBrowserContextMenu);
|
||||||
@ -1275,6 +1572,7 @@ function App() {
|
|||||||
syncToolbarButtons();
|
syncToolbarButtons();
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
initialSyncTimers.forEach((timer) => window.clearTimeout(timer));
|
||||||
document.removeEventListener('keydown', handleKeyDown, true);
|
document.removeEventListener('keydown', handleKeyDown, true);
|
||||||
document.removeEventListener('fullscreenchange', handleFullscreenChange);
|
document.removeEventListener('fullscreenchange', handleFullscreenChange);
|
||||||
document.removeEventListener('contextmenu', suppressBrowserContextMenu);
|
document.removeEventListener('contextmenu', suppressBrowserContextMenu);
|
||||||
@ -1283,7 +1581,7 @@ function App() {
|
|||||||
frame.removeEventListener('keydown', handleToolbarKeyDown, true);
|
frame.removeEventListener('keydown', handleToolbarKeyDown, true);
|
||||||
observer.disconnect();
|
observer.disconnect();
|
||||||
};
|
};
|
||||||
}, [statisticMenuOpen]);
|
}, [appliedFilters, filterModalKey, filterTreeByKey, statisticMenuOpen]);
|
||||||
|
|
||||||
const chartOptions = useMemo<AgCartesianChartOptions>(() => {
|
const chartOptions = useMemo<AgCartesianChartOptions>(() => {
|
||||||
const groupNames: string[] = [];
|
const groupNames: string[] = [];
|
||||||
@ -1296,11 +1594,12 @@ function App() {
|
|||||||
groupNames.push(datum.groupName);
|
groupNames.push(datum.groupName);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
groupNames.sort(compareGroupNames);
|
||||||
const visibleData = groupNames.map((groupName) => {
|
const visibleData = groupNames.map((groupName) => {
|
||||||
const row: Record<string, string | number | null> = { groupName };
|
const row: Record<string, string | number | null> = { groupName };
|
||||||
selectedContentNodes.forEach((node, index) => {
|
selectedContentNodes.forEach((node) => {
|
||||||
const datum = chartDataBySelection[getSelectionKey(node.contentKey, node.id)]?.find((item) => item.groupName === groupName);
|
const datum = chartDataBySelection[getSelectionKey(node.contentKey, node.id)]?.find((item) => item.groupName === groupName);
|
||||||
row[getSeriesValueKey(index)] = datum?.[selectedValueKey] ?? null;
|
row[getSeriesValueKey(node.contentKey, node.id)] = datum?.[selectedValueKey] ?? null;
|
||||||
});
|
});
|
||||||
return row;
|
return row;
|
||||||
});
|
});
|
||||||
@ -1363,6 +1662,16 @@ function App() {
|
|||||||
enabled: true,
|
enabled: true,
|
||||||
toolbar: {
|
toolbar: {
|
||||||
buttons: ([
|
buttons: ([
|
||||||
|
{
|
||||||
|
value: 'callout',
|
||||||
|
tooltip: '模板库',
|
||||||
|
label: '<span class="ag-charts-myButton-template ag-charts-diy-button">库</span>',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'text',
|
||||||
|
tooltip: '指标树形',
|
||||||
|
label: '<span class="ag-charts-myButton-indicator ag-charts-diy-button">树</span>',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
value: 'note',
|
value: 'note',
|
||||||
tooltip: '切换统计指标',
|
tooltip: '切换统计指标',
|
||||||
@ -1388,6 +1697,11 @@ function App() {
|
|||||||
value: 'fibonacci-menu',
|
value: 'fibonacci-menu',
|
||||||
tooltip: 'Fibonacci Tool',
|
tooltip: 'Fibonacci Tool',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
value: 'comment',
|
||||||
|
tooltip: '全屏(F11)',
|
||||||
|
label: '<i class="anticon anticon-arrow-salt ag-charts-myButton-fullScreen ag-charts-diy-button"></i>',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
icon: 'delete',
|
icon: 'delete',
|
||||||
value: 'clear',
|
value: 'clear',
|
||||||
@ -1396,13 +1710,14 @@ function App() {
|
|||||||
] as unknown as NonNullable<NonNullable<AgCartesianChartOptions['annotations']>['toolbar']>['buttons']),
|
] as unknown as NonNullable<NonNullable<AgCartesianChartOptions['annotations']>['toolbar']>['buttons']),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
series: selectedContentNodes.map((node, index) => ({
|
series: selectedContentNodes.map((node) => ({
|
||||||
type: 'line',
|
type: 'line',
|
||||||
xKey: 'groupName',
|
xKey: 'groupName',
|
||||||
yKey: getSeriesValueKey(index),
|
yKey: getSeriesValueKey(node.contentKey, node.id),
|
||||||
yName: `${node.label} ${seriesValueLabel}`,
|
yName: `${node.label} ${seriesValueLabel}`,
|
||||||
stroke: node.color,
|
stroke: node.color,
|
||||||
strokeWidth: 2,
|
strokeWidth: 2,
|
||||||
|
connectMissingData: true,
|
||||||
marker: {
|
marker: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
fill: node.color,
|
fill: node.color,
|
||||||
@ -1492,7 +1807,7 @@ function App() {
|
|||||||
|
|
||||||
<section className="workspace" aria-label="年度费用模板" ref={workspaceRef}>
|
<section className="workspace" aria-label="年度费用模板" ref={workspaceRef}>
|
||||||
<div className="chart-filter-bar chart-filter-bar--workspace" aria-label="筛选条件">
|
<div className="chart-filter-bar chart-filter-bar--workspace" aria-label="筛选条件">
|
||||||
{filterOptions.map((option) => {
|
{chartFilterOptions.map((option) => {
|
||||||
const count = appliedFilters[option.key].length;
|
const count = appliedFilters[option.key].length;
|
||||||
const FilterIcon = option.icon;
|
const FilterIcon = option.icon;
|
||||||
return (
|
return (
|
||||||
@ -1516,7 +1831,10 @@ function App() {
|
|||||||
type="button"
|
type="button"
|
||||||
title="清空全部筛选"
|
title="清空全部筛选"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
resetIndicatorTreeState();
|
||||||
setAppliedFilters({
|
setAppliedFilters({
|
||||||
|
templateLibrary: getDefaultTemplateFilterNodes(),
|
||||||
|
indicatorTree: [],
|
||||||
region: [],
|
region: [],
|
||||||
geoLocation: [],
|
geoLocation: [],
|
||||||
facilityType: [],
|
facilityType: [],
|
||||||
@ -1593,9 +1911,6 @@ function App() {
|
|||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
{loading || loadError ? <div className="chart-status">{loading ? loadingHint || '加载中' : loadError}</div> : null}
|
{loading || loadError ? <div className="chart-status">{loading ? loadingHint || '加载中' : loadError}</div> : null}
|
||||||
<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" />
|
|
||||||
</button>
|
|
||||||
<AgCharts options={chartOptions} />
|
<AgCharts options={chartOptions} />
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<div className="chart-loading-mask" aria-live="polite" aria-busy="true">
|
<div className="chart-loading-mask" aria-live="polite" aria-busy="true">
|
||||||
@ -1687,7 +2002,17 @@ function App() {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<footer className="filter-modal-actions">
|
<footer className="filter-modal-actions">
|
||||||
<button className="filter-modal-clear" type="button" onClick={() => setDraftFilterNodes([])}>
|
<button
|
||||||
|
className="filter-modal-clear"
|
||||||
|
type="button"
|
||||||
|
onClick={() => setDraftFilterNodes(
|
||||||
|
isTemplateFilterKey(filterModalKey)
|
||||||
|
? getDefaultTemplateFilterNodes()
|
||||||
|
: isIndicatorTreeFilterKey(filterModalKey)
|
||||||
|
? defaultIndicatorTreeNodes
|
||||||
|
: [],
|
||||||
|
)}
|
||||||
|
>
|
||||||
清空当前
|
清空当前
|
||||||
</button>
|
</button>
|
||||||
<button className="filter-modal-cancel" type="button" onClick={closeFilterModal}>
|
<button className="filter-modal-cancel" type="button" onClick={closeFilterModal}>
|
||||||
|
|||||||
@ -359,10 +359,25 @@ button {
|
|||||||
background: rgba(255, 252, 248, 0.94);
|
background: rgba(255, 252, 248, 0.94);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.chart-frame .chart-template-button,
|
||||||
|
.chart-frame .chart-indicator-button,
|
||||||
.chart-frame .chart-statistic-button {
|
.chart-frame .chart-statistic-button {
|
||||||
color: #46413b;
|
color: #46413b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.chart-frame .ag-charts-myButton-template,
|
||||||
|
.chart-frame .ag-charts-myButton-indicator {
|
||||||
|
display: block;
|
||||||
|
min-width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 16px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-frame .chart-template-button[aria-expanded="true"],
|
||||||
|
.chart-frame .chart-indicator-button[aria-expanded="true"],
|
||||||
.chart-frame .chart-statistic-button[aria-expanded="true"] {
|
.chart-frame .chart-statistic-button[aria-expanded="true"] {
|
||||||
color: #0078a8;
|
color: #0078a8;
|
||||||
border-color: rgba(0, 120, 168, 0.36);
|
border-color: rgba(0, 120, 168, 0.36);
|
||||||
@ -456,29 +471,6 @@ button {
|
|||||||
line-height: 18px;
|
line-height: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chart-frame .chart-fullscreen-button {
|
|
||||||
position: absolute;
|
|
||||||
left: 24px;
|
|
||||||
top: 252px;
|
|
||||||
z-index: 9;
|
|
||||||
display: grid;
|
|
||||||
width: 34px;
|
|
||||||
height: 34px;
|
|
||||||
min-width: 34px;
|
|
||||||
min-height: 34px;
|
|
||||||
place-items: center;
|
|
||||||
padding: 0;
|
|
||||||
border: 1px solid rgba(90, 82, 72, 0.22);
|
|
||||||
border-radius: 3px;
|
|
||||||
color: #46413b;
|
|
||||||
background: rgba(255, 249, 241, 0.72);
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chart-frame .ag-charts-toolbar__button[title="Clear annotations"] {
|
|
||||||
transform: translateY(42px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.chart-frame .ag-charts-zoom-buttons {
|
.chart-frame .ag-charts-zoom-buttons {
|
||||||
top: auto !important;
|
top: auto !important;
|
||||||
right: 24px !important;
|
right: 24px !important;
|
||||||
|
|||||||
37
vite-dev.log
37
vite-dev.log
@ -194,3 +194,40 @@ Port 5173 is in use, trying another one...
|
|||||||
[2m15:44:06[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/App.tsx[22m
|
[2m15:44:06[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/App.tsx[22m
|
||||||
[2m16:32:19[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/App.tsx[22m
|
[2m16:32:19[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/App.tsx[22m
|
||||||
[2m17:15:32[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/App.tsx[22m
|
[2m17:15:32[22m [36m[1m[vite][22m[39m [90m[2m(client)[22m[39m [32mhmr update [39m[2m/src/App.tsx[22m
|
||||||
|
| ||||||