Compare commits

..

3 Commits

9 changed files with 220 additions and 91 deletions

View File

@ -0,0 +1,3 @@
[ 6918ms] [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
[ 7315ms] [ERROR] Failed to load resource: the server responded with a status of 404 (Not Found) @ http://127.0.0.1:5173/favicon.ico:0
[ 331036ms] [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

View File

@ -1 +1,6 @@
[ 550538ms] [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 [ 300ms] [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
[ 1230ms] [ERROR] Failed to load resource: the server responded with a status of 404 (Not Found) @ http://127.0.0.1:5173/favicon.ico:0
[ 40506ms] [ERROR] Failed to load resource: the server responded with a status of 401 () @ https://nest.zwgczx.com/api/v1/zw/getBuildingFunctionCostFilterTree?key=templateLibrary&currenttime=1778660578349&__random__=1778660578349:0
[ 40812ms] [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&currenttime=1778660578682&__random__=1778660578682:0
[ 52231ms] [ERROR] Failed to load resource: the server responded with a status of 401 () @ https://nest.zwgczx.com/api/v1/zw/getBuildingFunctionCostFilterTree?key=templateLibrary&currenttime=1778660590101&__random__=1778660590101:0
[ 53824ms] [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&currenttime=1778660591693&__random__=1778660591693:0

View File

@ -1,2 +0,0 @@
[ 136ms] [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
[ 595ms] [ERROR] Failed to load resource: the server responded with a status of 404 (Not Found) @ http://127.0.0.1:5173/favicon.ico:0

View File

@ -0,0 +1,84 @@
- 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=e27]: 建筑功能
- button "建设阶段" [ref=e28] [cursor=pointer]:
- img [ref=e29]
- generic [ref=e34]: 建设阶段
- button "规划形式" [ref=e35] [cursor=pointer]:
- img [ref=e36]
- generic [ref=e41]: 规划形式
- region "年度总费用图表" [ref=e42]:
- generic [ref=e43]:
- button "纵坐标:造价(元)" [ref=e45] [cursor=pointer]: 造价(元)
- generic [ref=e46]:
- figure "图表共有0个系列":
- generic [ref=e47]:
- img "interactive chart":
- generic:
- img
- img
- region [ref=e48]
- toolbar "标注" [ref=e49]:
- button "库" [ref=e50] [cursor=pointer]:
- generic:
- generic:
- button "树" [ref=e51] [cursor=pointer]:
- generic:
- generic:
- button "均" [ref=e52] [cursor=pointer]:
- generic:
- button "Line Tool" [disabled] [ref=e53]
- button "Text Tool" [disabled] [ref=e54]
- button "Shape Tool" [disabled] [ref=e55]
- button "Fibonacci Tool" [disabled] [ref=e56]
- button "全屏(F11)" [ref=e57] [cursor=pointer]
- button "Clear annotations" [disabled] [ref=e58]
- status:
- generic: 请选择右侧分类项
- toolbar "缩放" [ref=e59]:
- button "缩小" [disabled] [ref=e60]
- button "放大" [ref=e61] [cursor=pointer]
- button "左移" [disabled] [ref=e62]
- button "右移" [disabled] [ref=e63]
- button "重置" [disabled] [ref=e64]
- complementary "选择内容" [ref=e65]:
- tablist "选择内容切换项" [ref=e66]:
- tab "自然地理区位" [selected] [ref=e67] [cursor=pointer]
- tab "设施类别" [ref=e68] [cursor=pointer]
- tab "建筑功能" [ref=e69] [cursor=pointer]
- tab "建设阶段" [ref=e70] [cursor=pointer]
- tab "规划形式" [ref=e71] [cursor=pointer]
- generic [ref=e72]:
- generic [ref=e73]: 自然地理区位
- generic [ref=e74]: 加载中

View File

@ -0,0 +1,84 @@
- 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=e27]: 建筑功能
- button "建设阶段" [ref=e28] [cursor=pointer]:
- img [ref=e29]
- generic [ref=e34]: 建设阶段
- button "规划形式" [ref=e35] [cursor=pointer]:
- img [ref=e36]
- generic [ref=e41]: 规划形式
- region "年度总费用图表" [ref=e42]:
- generic [ref=e43]:
- button "纵坐标:造价(元)" [ref=e45] [cursor=pointer]: 造价(元)
- generic [ref=e46]:
- figure "图表共有0个系列":
- generic [ref=e47]:
- img "interactive chart":
- generic:
- img
- img
- region [ref=e48]
- toolbar "标注" [ref=e49]:
- button "库" [ref=e50] [cursor=pointer]:
- generic:
- generic:
- button "树" [ref=e51] [cursor=pointer]:
- generic:
- generic:
- button "均" [ref=e52] [cursor=pointer]:
- generic:
- button "Line Tool" [disabled] [ref=e53]
- button "Text Tool" [disabled] [ref=e54]
- button "Shape Tool" [disabled] [ref=e55]
- button "Fibonacci Tool" [disabled] [ref=e56]
- button "全屏(F11)" [ref=e57] [cursor=pointer]
- button "Clear annotations" [disabled] [ref=e58]
- status:
- generic: 请选择右侧分类项
- toolbar "缩放" [ref=e59]:
- button "缩小" [disabled] [ref=e60]
- button "放大" [ref=e61] [cursor=pointer]
- button "左移" [disabled] [ref=e62]
- button "右移" [disabled] [ref=e63]
- button "重置" [disabled] [ref=e64]
- complementary "选择内容" [ref=e65]:
- tablist "选择内容切换项" [ref=e66]:
- tab "自然地理区位" [selected] [ref=e67] [cursor=pointer]
- tab "设施类别" [ref=e68] [cursor=pointer]
- tab "建筑功能" [ref=e69] [cursor=pointer]
- tab "建设阶段" [ref=e70] [cursor=pointer]
- tab "规划形式" [ref=e71] [cursor=pointer]
- generic [ref=e72]:
- generic [ref=e73]: 自然地理区位
- generic [ref=e74]: 加载中

View File

@ -1,80 +0,0 @@
- 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 "库" [ref=e45] [cursor=pointer]:
- generic:
- generic:
- button "树" [ref=e46] [cursor=pointer]:
- generic:
- generic:
- button "均" [ref=e47] [cursor=pointer]:
- 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)" [ref=e52] [cursor=pointer]
- 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]: 加载中

View File

@ -1,10 +1,10 @@
# 组团趋势图 # 建筑设施对象趋势图
这是一个基于 `React + AG Charts`组团趋势图页面,用来查看不同分类维度下的年度统计趋势,并通过右侧筛选条件联动图表结果。 这是一个基于 `React + AG Charts`建筑设施对象趋势图页面,用来查看不同分类维度下的年度统计趋势,并通过右侧筛选条件联动图表结果。
## 功能 ## 功能
- 左侧展示组团趋势图,支持最低值、最高值、平均值、中位数和数据量切换 - 左侧展示建筑设施对象趋势图,支持最低值、最高值、平均值、中位数和数据量切换
- 右侧展示分类树,支持按 `自然地理区位 / 设施类别 / 建设阶段 / 规划形式` 选择节点 - 右侧展示分类树,支持按 `自然地理区位 / 设施类别 / 建设阶段 / 规划形式` 选择节点
- 筛选条件支持 `省市区`,后端会根据 `uf_xzqy` 展开到区级 `id` 后再过滤 - 筛选条件支持 `省市区`,后端会根据 `uf_xzqy` 展开到区级 `id` 后再过滤
- 支持搜索筛选树节点,支持多条件叠加 - 支持搜索筛选树节点,支持多条件叠加

View File

@ -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, Library, LocateFixed, MapPinned, Waypoints } from 'lucide-react'; import { Building2, Construction, LayoutGrid, Library, LocateFixed, MapPinned, SquareFunction, Waypoints } from 'lucide-react';
import { import {
AnnotationsModule, AnnotationsModule,
ContextMenuModule, ContextMenuModule,
@ -18,6 +18,12 @@ ModuleRegistry.registerModules([AnnotationsModule, ContextMenuModule, ZoomModule
const API_BASE_URL = 'https://nest.zwgczx.com/api/v1'; const API_BASE_URL = 'https://nest.zwgczx.com/api/v1';
// const API_BASE_URL = 'http://127.0.0.1:9089/api/v1'; // const API_BASE_URL = 'http://127.0.0.1:9089/api/v1';
const API_ROUTES = {
filterTree: '/zw/getBuildingFacilityObjectFilterTree',
filterTreeSearch: '/zw/getBuildingFacilityObjectFilterTreeSearch',
statsBatch: '/zw/getBuildingFacilityObjectStatsBatch',
} as const;
const statisticOptions = [ const statisticOptions = [
{ key: 'minValue', label: '最低值', shortLabel: '低' }, { key: 'minValue', label: '最低值', shortLabel: '低' },
{ key: 'maxValue', label: '最高值', shortLabel: '高' }, { key: 'maxValue', label: '最高值', shortLabel: '高' },
@ -36,6 +42,7 @@ const metricOptions = [
const contentOptions = [ const contentOptions = [
{ key: 'geoLocation', label: '自然地理区位' }, { key: 'geoLocation', label: '自然地理区位' },
{ key: 'facilityType', label: '设施类别' }, { key: 'facilityType', label: '设施类别' },
{ key: 'buildingFunction', label: '建筑功能' },
{ key: 'constructionStage', label: '建设阶段' }, { key: 'constructionStage', label: '建设阶段' },
{ key: 'planningForm', label: '规划形式' }, { key: 'planningForm', label: '规划形式' },
] as const; ] as const;
@ -46,6 +53,7 @@ const filterOptions = [
{ 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: 'buildingFunction', label: '建筑功能', icon: SquareFunction },
{ key: 'constructionStage', label: '建设阶段', icon: Construction }, { key: 'constructionStage', label: '建设阶段', icon: Construction },
{ key: 'planningForm', label: '规划形式', icon: LayoutGrid }, { key: 'planningForm', label: '规划形式', icon: LayoutGrid },
] as const; ] as const;
@ -84,6 +92,17 @@ const contentTreeConfigs = {
fieldid: '305426', fieldid: '305426',
defaultExpandedLevel: 3, defaultExpandedLevel: 3,
}, },
buildingFunction: {
endpoint: '/api/public/browser/data/256',
treeid: '95004',
fieldid: '305919',
defaultExpandedLevel: 0,
browserParams: {
workflowid: '182032',
wfid: '182032',
billid: '-1817',
},
},
constructionStage: { constructionStage: {
endpoint: '/api/public/browser/data/256', endpoint: '/api/public/browser/data/256',
treeid: '94007', treeid: '94007',
@ -643,6 +662,7 @@ function App() {
const treeInitialLoadStartedRef = useRef<Record<ContentKey, boolean>>({ const treeInitialLoadStartedRef = useRef<Record<ContentKey, boolean>>({
geoLocation: false, geoLocation: false,
facilityType: false, facilityType: false,
buildingFunction: false,
constructionStage: false, constructionStage: false,
planningForm: false, planningForm: false,
}); });
@ -652,6 +672,7 @@ function App() {
region: false, region: false,
geoLocation: false, geoLocation: false,
facilityType: false, facilityType: false,
buildingFunction: false,
constructionStage: false, constructionStage: false,
planningForm: false, planningForm: false,
}); });
@ -664,18 +685,21 @@ function App() {
const [treeByContent, setTreeByContent] = useState<Record<ContentKey, TreeNode[]>>({ const [treeByContent, setTreeByContent] = useState<Record<ContentKey, TreeNode[]>>({
geoLocation: [], geoLocation: [],
facilityType: [], facilityType: [],
buildingFunction: [],
constructionStage: [], constructionStage: [],
planningForm: [], planningForm: [],
}); });
const [treeLoadingByContent, setTreeLoadingByContent] = useState<Record<ContentKey, boolean>>({ const [treeLoadingByContent, setTreeLoadingByContent] = useState<Record<ContentKey, boolean>>({
geoLocation: false, geoLocation: false,
facilityType: false, facilityType: false,
buildingFunction: false,
constructionStage: false, constructionStage: false,
planningForm: false, planningForm: false,
}); });
const [treeErrorByContent, setTreeErrorByContent] = useState<Record<ContentKey, string | null>>({ const [treeErrorByContent, setTreeErrorByContent] = useState<Record<ContentKey, string | null>>({
geoLocation: null, geoLocation: null,
facilityType: null, facilityType: null,
buildingFunction: null,
constructionStage: null, constructionStage: null,
planningForm: null, planningForm: null,
}); });
@ -691,6 +715,7 @@ function App() {
region: [], region: [],
geoLocation: [], geoLocation: [],
facilityType: [], facilityType: [],
buildingFunction: [],
constructionStage: [], constructionStage: [],
planningForm: [], planningForm: [],
}); });
@ -700,6 +725,7 @@ function App() {
region: false, region: false,
geoLocation: false, geoLocation: false,
facilityType: false, facilityType: false,
buildingFunction: false,
constructionStage: false, constructionStage: false,
planningForm: false, planningForm: false,
}); });
@ -709,6 +735,7 @@ function App() {
region: null, region: null,
geoLocation: null, geoLocation: null,
facilityType: null, facilityType: null,
buildingFunction: null,
constructionStage: null, constructionStage: null,
planningForm: null, planningForm: null,
}); });
@ -718,6 +745,7 @@ function App() {
region: [], region: [],
geoLocation: [], geoLocation: [],
facilityType: [], facilityType: [],
buildingFunction: [],
constructionStage: [], constructionStage: [],
planningForm: [], planningForm: [],
}); });
@ -727,6 +755,7 @@ function App() {
region: false, region: false,
geoLocation: false, geoLocation: false,
facilityType: false, facilityType: false,
buildingFunction: false,
constructionStage: false, constructionStage: false,
planningForm: false, planningForm: false,
}); });
@ -736,6 +765,7 @@ function App() {
region: null, region: null,
geoLocation: null, geoLocation: null,
facilityType: null, facilityType: null,
buildingFunction: null,
constructionStage: null, constructionStage: null,
planningForm: null, planningForm: null,
}); });
@ -745,6 +775,7 @@ function App() {
region: [], region: [],
geoLocation: [], geoLocation: [],
facilityType: [], facilityType: [],
buildingFunction: [],
constructionStage: [], constructionStage: [],
planningForm: [], planningForm: [],
}); });
@ -759,6 +790,7 @@ function App() {
region: 0, region: 0,
geoLocation: 0, geoLocation: 0,
facilityType: 0, facilityType: 0,
buildingFunction: 0,
constructionStage: 0, constructionStage: 0,
planningForm: 0, planningForm: 0,
}); });
@ -828,6 +860,7 @@ function App() {
} }
const treeParams = { const treeParams = {
...browserTreeDefaults, ...browserTreeDefaults,
...('browserParams' in config ? config.browserParams : {}),
treeid: config.treeid, treeid: config.treeid,
cube_treeid: config.treeid, cube_treeid: config.treeid,
fieldid: config.fieldid, fieldid: config.fieldid,
@ -885,7 +918,7 @@ function App() {
}; };
const fetchRegionFilterTree = async (signal?: AbortSignal) => { const fetchRegionFilterTree = async (signal?: AbortSignal) => {
const response = await fetch(`${API_BASE_URL}/zw/getBuildingFunctionCostFilterTree?${buildQuery({ key: 'region' })}`, { const response = await fetch(`${API_BASE_URL}${API_ROUTES.filterTree}?${buildQuery({ key: 'region' })}`, {
signal, signal,
headers: { headers: {
'X-Requested-With': 'XMLHttpRequest', 'X-Requested-With': 'XMLHttpRequest',
@ -930,7 +963,7 @@ function App() {
}; };
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}${API_ROUTES.filterTreeSearch}?${buildQuery({
key: filterKey, key: filterKey,
keyword, keyword,
nodePrefix: isContentFilterKey(filterKey) ? getTreeNodePrefix(filterTreeByKey[filterKey]) : '', nodePrefix: isContentFilterKey(filterKey) ? getTreeNodePrefix(filterTreeByKey[filterKey]) : '',
@ -1402,7 +1435,7 @@ function App() {
return; return;
} }
const response = await fetch(`${API_BASE_URL}/zw/getBuildingFunctionCostStatsBatch`, { const response = await fetch(`${API_BASE_URL}${API_ROUTES.statsBatch}`, {
method: 'POST', method: 'POST',
signal: controller.signal, signal: controller.signal,
headers: { headers: {
@ -1873,6 +1906,7 @@ function App() {
region: [], region: [],
geoLocation: [], geoLocation: [],
facilityType: [], facilityType: [],
buildingFunction: [],
constructionStage: [], constructionStage: [],
planningForm: [], planningForm: [],
}); });

View File

@ -1,5 +1,6 @@
VITE v7.3.2 ready in 283 ms VITE v7.3.2 ready in 307 ms
➜ Local: http://127.0.0.1:5173/ ➜ Local: http://127.0.0.1:5173/
 ➜ press h + enter to show help  ➜ press h + enter to show help
16:10:18 [vite] (client) hmr update /src/App.tsx