diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c79e201..b34692a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -24,8 +24,8 @@ importers: specifier: ^1.2.0 version: 1.2.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@kevisual/router': - specifier: 0.0.72 - version: 0.0.72 + specifier: 0.0.74 + version: 0.0.74 '@tanstack/react-router': specifier: ^1.160.2 version: 1.160.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -50,9 +50,6 @@ importers: dayjs: specifier: ^1.11.19 version: 1.11.19 - dotenv: - specifier: ^17.3.1 - version: 17.3.1 es-toolkit: specifier: ^1.44.0 version: 1.44.0 @@ -86,9 +83,6 @@ importers: sonner: specifier: ^2.0.7 version: 2.0.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - tailwind-merge: - specifier: ^3.4.1 - version: 3.4.1 valtio: specifier: ^2.3.0 version: 2.3.0(@types/react@19.2.14)(react@19.2.4) @@ -106,8 +100,8 @@ importers: specifier: ^0.0.5 version: 0.0.5 '@kevisual/query': - specifier: ^0.0.42 - version: 0.0.42 + specifier: ^0.0.46 + version: 0.0.46 '@kevisual/types': specifier: ^0.0.12 version: 0.0.12 @@ -132,6 +126,12 @@ importers: '@vitejs/plugin-react': specifier: ^5.1.4 version: 5.1.4(vite@8.0.0-beta.14(@types/node@25.2.3)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0)) + dotenv: + specifier: ^17.3.1 + version: 17.3.1 + tailwind-merge: + specifier: ^3.4.1 + version: 3.4.1 tailwindcss: specifier: ^4.1.18 version: 4.1.18 @@ -516,11 +516,11 @@ packages: '@kevisual/load@0.0.6': resolution: {integrity: sha512-+3YTFehRcZ1haGel5DKYMUwmi5i6f2psyaPZlfkKU/cOXgkpwoG9/BEqPCnPjicKqqnksEpixVRkyHJ+5bjLVA==} - '@kevisual/query@0.0.42': - resolution: {integrity: sha512-FW0DqeAsiAz6ABnjxXcAEzsvMtH59kfvCipuCQilIUvnTeM2tCYR7O7ll7I4KI70WpuxcfNVMFSDqiMrPwTthg==} + '@kevisual/query@0.0.46': + resolution: {integrity: sha512-JwHV16ehk8JWM5wiWW5kz9yTg4HrOmmnci5QvwQYdhXYXDzGpUrOxeoz3wloMs4kX3bkowz97iLLW6uQdgUoTw==} - '@kevisual/router@0.0.72': - resolution: {integrity: sha512-+HL4FINZsjnoRRa8Qs7xoPg+5/TcHR7jZQ7AHWHogo0BJzCAtnQwmidMQzeGL4z0WKNbbgVhXdz1wAYoxHJZTg==} + '@kevisual/router@0.0.74': + resolution: {integrity: sha512-J8qDsvrpf317H0Gq9YkeGwI+GS23RC0q/mYbKOia8wF33ylz+pDhBN8T1KmXx90AVBt/tMGNVJRgEhTVdTgpvA==} '@kevisual/types@0.0.12': resolution: {integrity: sha512-zJXH2dosir3jVrQ6QG4i0+iLQeT9gJ3H+cKXs8ReWboxBSYzUZO78XssVeVrFPsJ33iaAqo4q3DWbSS1dWGn7Q==} @@ -2877,9 +2877,9 @@ snapshots: dependencies: eventemitter3: 5.0.4 - '@kevisual/query@0.0.42': {} + '@kevisual/query@0.0.46': {} - '@kevisual/router@0.0.72': + '@kevisual/router@0.0.74': dependencies: es-toolkit: 1.44.0 diff --git a/web/.gitignore b/web/.gitignore index 9065d26..2a7fb8e 100644 --- a/web/.gitignore +++ b/web/.gitignore @@ -1,37 +1,18 @@ # Logs logs *.log -.env -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* node_modules dist -dist-ssr -*.local +pack-dist -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea .DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? - -tsconfig.app.tsbuildinfo -tsconfig.node.tsbuildinfo .turbo .pnpm-store .tanstack -.env +.env* !.env.example \ No newline at end of file diff --git a/web/bun.lock b/web/bun.lock index 07f033c..eccb913 100644 --- a/web/bun.lock +++ b/web/bun.lock @@ -6,7 +6,7 @@ "name": "@kevisual/router-studio", "dependencies": { "@base-ui/react": "^1.2.0", - "@kevisual/router": "0.0.72", + "@kevisual/router": "0.0.75", "@tanstack/react-router": "^1.160.2", "@tanstack/react-table": "^8.21.3", "@uiw/react-md-editor": "^4.0.11", @@ -33,7 +33,7 @@ "@kevisual/api": "^0.0.51", "@kevisual/context": "^0.0.6", "@kevisual/js-filter": "^0.0.5", - "@kevisual/query": "^0.0.42", + "@kevisual/query": "^0.0.47", "@kevisual/types": "^0.0.12", "@tailwindcss/vite": "^4.1.18", "@tanstack/react-router-devtools": "^1.160.2", @@ -202,9 +202,9 @@ "@kevisual/load": ["@kevisual/load@0.0.6", "", { "dependencies": { "eventemitter3": "^5.0.1" } }, "sha512-+3YTFehRcZ1haGel5DKYMUwmi5i6f2psyaPZlfkKU/cOXgkpwoG9/BEqPCnPjicKqqnksEpixVRkyHJ+5bjLVA=="], - "@kevisual/query": ["@kevisual/query@0.0.42", "", {}, "sha512-FW0DqeAsiAz6ABnjxXcAEzsvMtH59kfvCipuCQilIUvnTeM2tCYR7O7ll7I4KI70WpuxcfNVMFSDqiMrPwTthg=="], + "@kevisual/query": ["@kevisual/query@0.0.47", "", {}, "sha512-ZR7WXeDDGUSzBtcGVU3J173sA0hCqrGTw5ybGbdNGlM0VyJV/XQIovCcSoZh1YpnciLRRqJvzXUgTnCkam+M3g=="], - "@kevisual/router": ["@kevisual/router@0.0.72", "", { "dependencies": { "es-toolkit": "^1.44.0" } }, "sha512-+HL4FINZsjnoRRa8Qs7xoPg+5/TcHR7jZQ7AHWHogo0BJzCAtnQwmidMQzeGL4z0WKNbbgVhXdz1wAYoxHJZTg=="], + "@kevisual/router": ["@kevisual/router@0.0.75", "", { "dependencies": { "es-toolkit": "^1.44.0" } }, "sha512-WBDRKMjNYTP7ymkUUtiQwWYIcqnc+TGo3rFuRze8ovYV2UN5cQxIkIfsDbgWOdV1/v9b57gtiJvJRqWjCBWKRg=="], "@kevisual/types": ["@kevisual/types@0.0.12", "", {}, "sha512-zJXH2dosir3jVrQ6QG4i0+iLQeT9gJ3H+cKXs8ReWboxBSYzUZO78XssVeVrFPsJ33iaAqo4q3DWbSS1dWGn7Q=="], diff --git a/web/package.json b/web/package.json index aa3f165..31cce25 100644 --- a/web/package.json +++ b/web/package.json @@ -14,7 +14,7 @@ ], "dependencies": { "@base-ui/react": "^1.2.0", - "@kevisual/router": "0.0.72", + "@kevisual/router": "0.0.75", "@tanstack/react-router": "^1.160.2", "@tanstack/react-table": "^8.21.3", "@uiw/react-md-editor": "^4.0.11", @@ -41,7 +41,7 @@ "@kevisual/api": "^0.0.51", "@kevisual/context": "^0.0.6", "@kevisual/js-filter": "^0.0.5", - "@kevisual/query": "^0.0.42", + "@kevisual/query": "^0.0.47", "@kevisual/types": "^0.0.12", "@tailwindcss/vite": "^4.1.18", "@tanstack/react-router-devtools": "^1.160.2", diff --git a/web/src/app/query-view/components/DetailsDialog.tsx b/web/src/app/query-view/components/DetailsDialog.tsx new file mode 100644 index 0000000..eb3e3de --- /dev/null +++ b/web/src/app/query-view/components/DetailsDialog.tsx @@ -0,0 +1,151 @@ +import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'; +import { useQueryViewStore } from '../store'; +import { useShallow } from 'zustand/shallow'; +import { useStudioStore } from '@/app/studio/store'; +import { useState } from 'react'; +import { QueryView } from '..'; + +export const DetailsDialog = () => { + const [activeTab, setActiveTab] = useState('details'); + const { showDetailsDialog, setShowDetailsDialog, detailsData } = useQueryViewStore( + useShallow((state) => ({ + showDetailsDialog: state.showDetailsDialog, + setShowDetailsDialog: state.setShowDetailsDialog, + detailsData: state.detailsData, + })) + ); + const { currentView } = useStudioStore(useShallow((state) => ({ + currentView: state.currentView, + }))); + + if (!detailsData) return null; + console.log('activeTab ', activeTab); + return ( + + + + 详情信息 + + +
+ + + +
+ +
+ {/* 第一个标签页:详情信息 */} + {activeTab === 'details' && ( +
+ {/* Type */} + {detailsData.type && ( +
+ +
+ {detailsData.type} +
+
+ )} + + {/* Title */} + {detailsData.title && ( +
+ +
+ {detailsData.title} +
+
+ )} + + {/* Description */} + {detailsData.description && ( +
+ +
+ {detailsData.description} +
+
+ )} + + {/* Action */} + {detailsData.action && ( +
+ +
+
+                      {JSON.stringify(detailsData.action, null, 2)}
+                    
+
+
+ )} + + {/* 其他字段 */} + {detailsData.api && ( +
+ +
+
+                      {JSON.stringify(detailsData.api, null, 2)}
+                    
+
+
+ )} +
+ )} + + {/* 第二个标签页:当前视图 */} + {activeTab === 'view' && ( +
+ {currentView ? ( +
+ +
+ {currentView.viewId} +
+
+ ) : ( +
+ 当前没有视图信息 +
+ )} +
+ )} + + {/* 第三个标签页:响应 */} + {activeTab === 'response' && ( +
+ +
+ )} +
+
+
+ ); +}; diff --git a/web/src/app/query-view/index.tsx b/web/src/app/query-view/index.tsx index 6c20333..a050f9f 100644 --- a/web/src/app/query-view/index.tsx +++ b/web/src/app/query-view/index.tsx @@ -10,13 +10,16 @@ import { DropdownMenuItem, DropdownMenuSeparator, } from '@/components/ui/dropdown-menu' -import { useStudioStore } from '../studio/store' +import { Message, useStudioStore } from '../studio/store' +import { useQueryViewStore } from './store' +import { DetailsDialog } from './components/DetailsDialog' import { useShallow } from 'zustand/shallow' import { cloneDeep } from 'es-toolkit' import { toast } from 'sonner' +import { Result } from '@kevisual/query' type Props = { - type: 'component' | 'page', - viewData?: any + type: 'component' | 'page' | 'message', + viewData?: RouterViewItem } const queryProxy = new QueryProxy({ @@ -25,7 +28,7 @@ const queryProxy = new QueryProxy({ export const QueryView = (props: Props) => { const [data, setData] = useState([]) const [columns, setColumns] = useState[]>([]) - const [type] = useState<'component' | 'page'>(props.type || 'page') + const [type] = useState<'component' | 'page' | 'message'>(props.type || 'page') const [viewData, setViewData] = useState(null) const [isLoading, setIsLoading] = useState(false) const [showMoreMenu, setShowMoreMenu] = useState(false) @@ -40,33 +43,41 @@ export const QueryView = (props: Props) => { const studioStore = useStudioStore(useShallow((state) => ({ deleteMessage: state.deleteMessage }))) + const queryViewStore = useQueryViewStore(useShallow((state) => ({ + setShowDetailsDialog: state.setShowDetailsDialog, + setDetailsData: state.setDetailsData, + }))) + const handleResponse = (response: Result) => { + console.log('response', response, viewData); + const list = response.data?.list + if (!list) { + setIsList(false); + setObj(response.data); + return; + } + if (isList === false) { + setIsList(true); + } + setData(response.data.list) + const [_, firstItem] = response.data.list || [] + if (firstItem) { + const cols: ColumnDef[] = Object.keys(firstItem).map(key => ({ + accessorKey: key, + header: key.toUpperCase(), + cell: info => info.getValue() + '', + })) + setColumns(cols) + } + } const main = async () => { try { setIsLoading(true) const res = await queryProxy.runByRouteView(viewData!) const response = res.response; - console.log('response', response, viewData); - const list = response.data?.list - if (!list) { - setIsList(false); - setObj(response.data); - return; - } - if (isList === false) { - setIsList(true); - } - setData(response.data.list) + handleResponse(response) console.log('res', res); - const [_, firstItem] = response.data.list || [] - if (firstItem) { - const cols: ColumnDef[] = Object.keys(firstItem).map(key => ({ - accessorKey: key, - header: key.toUpperCase(), - cell: info => info.getValue() + '', - })) - setColumns(cols) - } toast.success('数据获取成功') + } finally { setIsLoading(false) } @@ -80,18 +91,19 @@ export const QueryView = (props: Props) => { const handleShowDetails = () => { console.log('Show details for row:', props.viewData) - const data = cloneDeep(props.viewData) - delete data.api?.proxy; - delete data.context?.router; - delete data.worker?.worker; - const str = JSON.stringify(data, null, 2) - // toast.info(
{str}
, { - // autoClose: 5000, - // closeOnClick: true, - // pauseOnHover: true, - // draggable: true, - // icon: false - // }); + const data = cloneDeep(props.viewData) as RouterViewItem + // 删除可能过大的字段,避免在详情弹窗展示 + if (data.type === 'api') { + delete data?.api?.query; + } + if (data.type === 'worker') { + delete data?.worker?.worker; + } + if (data.type === 'context') { + delete data?.context?.router; + } + queryViewStore.setDetailsData(data); + queryViewStore.setShowDetailsDialog(true); } const handleEdit = () => { @@ -106,7 +118,7 @@ export const QueryView = (props: Props) => { console.log('Delete row:', selectedRow) // 在这里添加删除逻辑 } - studioStore.deleteMessage(props.viewData!) + studioStore.deleteMessage(props.viewData! as Message) } const handleExport = () => { @@ -132,11 +144,19 @@ export const QueryView = (props: Props) => { // 在这里添加保存并打开逻辑 } } - useEffect(() => { - if (viewData) { - main() - } - }, [viewData]) + // useEffect(() => { + // console.log('执行查询', viewData, props.type) + // if (viewData && props.type !== 'message') { + // main() + // } else if (viewData && props.type === 'message') { + // console.log('viewData ', viewData, props.type) + // if (viewData.response) { + // handleResponse(viewData.response) + // } else { + // // + // } + // } + // }, [viewData, props.type]) useEffect(() => { props.viewData && setViewData(props.viewData as RouterViewItem) @@ -186,7 +206,8 @@ export const QueryView = (props: Props) => { } const isPage = type === 'page' - return
+ return
+

路由视图 - {viewData?.title || '未命名'}

@@ -280,7 +301,7 @@ export const QueryViewMessages = (props: Props) => { } // 查询query-view的保存的id,赋值后然后执行查询 // @ts-ignore - const DemoRouterView: RouterViewItem = { + const DemoRouterView: Message = { id: 'getData', description: '获取数据', title: '获取数据', @@ -294,7 +315,7 @@ export const QueryViewMessages = (props: Props) => { key: 'list' } } - studioStore.setMessages([DemoRouterView]) + studioStore.setMessages([DemoRouterView as Message]) } useEffect(() => { const type = props.type || 'page' diff --git a/web/src/app/query-view/store/index.ts b/web/src/app/query-view/store/index.ts new file mode 100644 index 0000000..ae85de9 --- /dev/null +++ b/web/src/app/query-view/store/index.ts @@ -0,0 +1,22 @@ +import { create } from 'zustand'; + +type QueryViewState = { + showDataDialog: boolean; + setShowDataDialog: (show: boolean) => void; + dataDialogContent: any; + setDataDialogContent: (content: any) => void; + showDetailsDialog: boolean; + setShowDetailsDialog: (show: boolean) => void; + detailsData: any; + setDetailsData: (data: any) => void; +}; +export const useQueryViewStore = create((set) => ({ + showDataDialog: false, + setShowDataDialog: (show) => set({ showDataDialog: show }), + dataDialogContent: null, + setDataDialogContent: (content) => set({ dataDialogContent: content }), + showDetailsDialog: false, + setShowDetailsDialog: (show) => set({ showDetailsDialog: show }), + detailsData: null, + setDetailsData: (data) => set({ detailsData: data }), +})); \ No newline at end of file diff --git a/web/src/app/studio/components/ExportDialog.tsx b/web/src/app/studio/components/ExportDialog.tsx new file mode 100644 index 0000000..db7a2f8 --- /dev/null +++ b/web/src/app/studio/components/ExportDialog.tsx @@ -0,0 +1,79 @@ +import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/dialog'; +import { useStudioStore } from '../store'; +import { useShallow } from 'zustand/shallow'; +import { createQueryByRoutes } from '@kevisual/query/api' +import { useMemo } from 'react'; +import { Button } from '@/components/ui/button'; +import { Copy, Check } from 'lucide-react'; +import { toast } from 'sonner'; +import { useState } from 'react'; +import { pick } from 'es-toolkit'; +export const ExportDialog = () => { + const { showExportDialog, setShowExportDialog, exportRoutes } = useStudioStore( + useShallow((state) => ({ + showExportDialog: state.showExportDialog, + setShowExportDialog: state.setShowExportDialog, + exportRoutes: state.exportRoutes, + })) + ); + const [copied, setCopied] = useState(false); + + const code = useMemo(() => { + if (!exportRoutes) return ''; + let routeInfo = exportRoutes.map(route => pick(route, ['path', 'key', 'id', 'description', 'metadata'])); + const query = createQueryByRoutes(routeInfo as any); + return query; + }, [exportRoutes]); + + const handleCopy = async () => { + try { + await navigator.clipboard.writeText(code); + setCopied(true); + toast.success('代码已复制到剪贴板'); + setTimeout(() => setCopied(false), 2000); + } catch (err) { + toast.error('复制失败,请重试'); + } + }; + + return ( + + + + 导出API代码 + +
+
+
+              {code}
+            
+
+
+ + + + +
+
+ ); +}; diff --git a/web/src/app/studio/index.tsx b/web/src/app/studio/index.tsx index a6f6938..de33548 100644 --- a/web/src/app/studio/index.tsx +++ b/web/src/app/studio/index.tsx @@ -1,11 +1,14 @@ import { useStudioStore } from './store.ts'; import { use, useEffect, useState } from 'react'; -import { MonitorPlay, Play, PanelLeft, PanelLeftClose, PanelRight, PanelRightClose, Filter, FilterX, Search, X } from 'lucide-react'; +import { MonitorPlay, Play, PanelLeft, PanelLeftClose, PanelRight, PanelRightClose, Filter, FilterX, Search, X, MoreHorizontal, Info, Code, RotateCcw } from 'lucide-react'; import { Panel, Group } from 'react-resizable-panels' import { ViewList } from '../view/list.tsx'; import { useShallow } from 'zustand/shallow'; import { Chat } from '../chat/index.tsx'; import { Input } from '@/components/ui/input.tsx'; +import { Button } from '@/components/ui/button.tsx'; +import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem } from '@/components/ui/dropdown-menu.tsx'; +import { ExportDialog } from './components/ExportDialog'; export const AppProvider = () => { const { showLeftPanel, showRightPanel } = useStudioStore(useShallow((state) => ({ showLeftPanel: state.showLeftPanel, @@ -66,7 +69,7 @@ export const WrapperHeader = (props: { children: React.ReactNode }) => {
-
+
{props.children}
@@ -89,11 +92,13 @@ export const App = () => { showFilter: state.showFilter, currentView: state.currentView, setShowFilter: state.setShowFilter, + setShowExportDialog: state.setShowExportDialog, + setExportRoutes: state.setExportRoutes, }))); const [expandedIds, setExpandedIds] = useState>(new Set()); const [visibleIds, setVisibleIds] = useState>(new Set()); const [searchKeyword, setSearchKeyword] = useState(''); - + const [defaultKeyword, setDefaultKeyword] = useState(''); useEffect(() => { queryRouteList(true); }, []); @@ -113,16 +118,13 @@ export const App = () => { const viewItem = store.currentView.views.find(v => v.id === viewId); if (viewItem && viewItem.query) { setSearchKeyword(viewItem.query); + setDefaultKeyword(viewItem.query); } return () => clearTimeout(timer); } }, [store.showFilter, store.currentView?.viewId]); const handleSearch = async (keyword: string) => { - if (keyword.trim()) { - await searchRoutes(keyword); - } else { - await queryRouteList(); - } + await searchRoutes(keyword.trim()); }; const handleKeyDown = async (e: React.KeyboardEvent) => { @@ -133,7 +135,7 @@ export const App = () => { const handleClear = async () => { setSearchKeyword(''); - await queryRouteList(); + handleSearch(''); }; const toggleDescription = (id: string) => { @@ -158,23 +160,36 @@ export const App = () => { }; return ( -
+
+ {loading &&
加载中...
} {store.showFilter && (
- + setSearchKeyword(e.target.value)} onKeyDown={handleKeyDown} /> + {defaultKeyword && searchKeyword !== defaultKeyword && ( + + )} {searchKeyword && (
)} -
+
{routes.map((route: RouteItem) => { const isExpanded = expandedIds.has(route.id); const isIdVisible = visibleIds.has(route.id); @@ -192,7 +207,7 @@ export const App = () => { return (
{/* ID and Path/Key in one line */} @@ -226,6 +241,43 @@ export const App = () => { onClick={() => run(route, 'custom')}> + + + + + + + { + e.stopPropagation(); + // TODO: 实现显示详情功能 + console.log('显示详情', route); + }} + > + + 显示详情 + + { + e.stopPropagation(); + store.setExportRoutes([route]); + store.setShowExportDialog(true); + }} + > + + 导出代码 + + + +
@@ -278,6 +330,18 @@ export const App = () => { ); })}
+
+ +
); } \ No newline at end of file diff --git a/web/src/app/studio/store.ts b/web/src/app/studio/store.ts index 0881ae3..dea152c 100644 --- a/web/src/app/studio/store.ts +++ b/web/src/app/studio/store.ts @@ -7,10 +7,9 @@ import { use } from '@kevisual/context' // import { MyCache } from '@kevisual/cache' import { persist } from 'zustand/middleware'; import { app } from '@/agent/index.ts' -import { cloneDeep, random } from 'es-toolkit' +import { cloneDeep } from 'es-toolkit' import { nanoid } from 'nanoid'; -import { filter } from '@kevisual/js-filter'; -import Fuse from 'fuse.js'; +import { Result } from '@kevisual/query'; const historyReplace = (url: string) => { if (window.history.replaceState) { window.history.replaceState(null, '', url); @@ -26,6 +25,17 @@ type RouteItem = { type RouteViewList = Array; +type MessageAction = { + path?: string; + key?: string; + [key: string]: any; +} +export type Message = RouterViewItem<{ + _id: string; + action: MessageAction; + description?: string; + response?: Result; +}> interface StudioState { loading: boolean; @@ -50,12 +60,16 @@ interface StudioState { setShowFilter: (show: boolean) => void; showRightPanel: boolean; setShowRightPanel: (show: boolean) => void; - messages: any[]; - setMessages: (messages: any[]) => void; - addMessage: (message: any) => void; - deleteMessage: (message: any) => void; + messages: Message[]; + setMessages: (messages: Message[]) => void; + addMessage: (message: Message) => void; + deleteMessage: (message: Message) => void; searchKeyword?: string; setSearchKeyword?: (keyword: string) => void; + showExportDialog: boolean; + setShowExportDialog: (show: boolean) => void; + exportRoutes?: RouteItem[]; + setExportRoutes: (routes?: RouteItem[]) => void; } const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); @@ -192,6 +206,7 @@ export const useStudioStore = create()( } } } + console.log('运行结果 route', route); if (showRightPanel) { if (route.metadata && route.metadata?.viewItem) { const messages = get().messages @@ -201,7 +216,7 @@ export const useStudioStore = create()( viewItem.description = route.description || viewItem.description; // @ts-ignore viewItem._id = nanoid(16); - set({ messages: [...messages, viewItem] }); + set({ messages: [...messages, viewItem as Message] }); } } }, @@ -293,7 +308,11 @@ export const useStudioStore = create()( addMessage: (message: any) => { const messages = get().messages; set({ messages: [...messages, message] }); - } + }, + showExportDialog: false, + setShowExportDialog: (show: boolean) => set({ showExportDialog: show }), + exportRoutes: undefined, + setExportRoutes: (routes?: RouteItem[]) => set({ exportRoutes: routes }) }), { name: 'studio-storage', diff --git a/web/src/app/view/components/ViewEditor.tsx b/web/src/app/view/components/ViewEditor.tsx index e379b92..34ae036 100644 --- a/web/src/app/view/components/ViewEditor.tsx +++ b/web/src/app/view/components/ViewEditor.tsx @@ -117,7 +117,7 @@ export const ViewEditor = ({ open, onOpenChange, data, onSave }: ViewEditorProps return ( - + {isUpdate ? '编辑视图' : '新增视图'} diff --git a/web/src/app/view/list.tsx b/web/src/app/view/list.tsx index 8663209..fe6707d 100644 --- a/web/src/app/view/list.tsx +++ b/web/src/app/view/list.tsx @@ -197,10 +197,10 @@ export const ViewList = () => { />
- -
diff --git a/web/src/modules/query.ts b/web/src/modules/query.ts index da6d547..0c773ca 100644 --- a/web/src/modules/query.ts +++ b/web/src/modules/query.ts @@ -1,9 +1,13 @@ -import { QueryClient } from '@kevisual/query'; - -export const query = new QueryClient({ +import { Query } from '@kevisual/query'; +import { QueryLoginBrowser } from '@kevisual/api/query-login' +export const query = new Query({ url: '/api/router', }); -export const queryClient = new QueryClient({ +export const queryClient = new Query({ url: '/client/router', +}); + +export const queryLogin = new QueryLoginBrowser({ + query: query }); \ No newline at end of file