@@ -174,6 +175,14 @@
:is-running="isRunning"
:execution-time="lastExecutionTime"
@clear="clearOutput"/>
+
+
+
@@ -197,6 +206,7 @@
· {{ currentFileName }}
@@ -347,6 +357,8 @@ import JsonView from "./components/JsonView.vue";
import MarkdownView from "./components/MarkdownView.vue";
import XmlView from "./components/XmlView.vue";
import YamlView from "./components/YamlView.vue";
+import SqlTableView from "./components/SqlTableView.vue";
+import SqlSourceSelect from "./components/SqlSourceSelect.vue";
import StatusBar from './components/StatusBar.vue'
import About from './components/About.vue'
import Settings from './components/Settings.vue'
@@ -375,6 +387,7 @@ import Terminal from './components/Terminal.vue'
import Breadcrumbs from './components/Breadcrumbs.vue'
import {initSnippets} from './composables/useSnippets'
import {kvGet, kvGetJSON, kvSet, kvSetJSON} from './composables/useKvStore'
+import {useDbConnections} from './composables/useDbConnections'
import {useAiConfig} from './composables/useAiConfig'
import {setGhost, clearGhostIn, ghostActive} from './editor/aiComplete'
import {cursorInfo} from './editor/cursorInfo'
@@ -1286,6 +1299,39 @@ const showRunPrompt = ref(false)
// 包装运行:仅编辑器模式下点击运行时自动展开控制台;关联文件则按策略就地运行
// 运行选中片段:以选中文本作为临时代码运行(不就地、不关联文件)
+// SQL 走专用执行(结构化结果 + 错误 + 数据源:内存/SQLite/MySQL)
+const {resolveActiveSource} = useDbConnections()
+const runSql = async (sqlOverride?: string) => {
+ const sql = sqlOverride ?? code.value
+ if (!sql.trim()) {
+ toast.info('没有可执行的 SQL')
+ return
+ }
+ if (layoutMode.value === 'editor') {
+ showConsole.value = true
+ }
+ isRunning.value = true
+ output.value = ''
+ isSuccess.value = false
+ try {
+ const source = resolveActiveSource()
+ const res = await invoke
('run_sql', {sql, source})
+ output.value = JSON.stringify(res)
+ isSuccess.value = !res.error
+ lastExecutionTime.value = res.elapsed_ms || 0
+ if (res.error) {
+ toast.error('SQL 执行失败')
+ }
+ }
+ catch (error) {
+ output.value = JSON.stringify({result_sets: [], messages: [], error: String(error)})
+ toast.error('SQL 执行失败: ' + error)
+ }
+ finally {
+ isRunning.value = false
+ }
+}
+
const runSelection = () => {
const view = editorView.value
if (!view) {
@@ -1297,6 +1343,10 @@ const runSelection = () => {
return
}
const selected = view.state.sliceDoc(from, to)
+ if (currentLanguage.value === 'sql') {
+ runSql(selected)
+ return
+ }
if (layoutMode.value === 'editor') {
showConsole.value = true
}
@@ -1304,6 +1354,10 @@ const runSelection = () => {
}
const handleRunCode = async () => {
+ if (currentLanguage.value === 'sql') {
+ runSql()
+ return
+ }
if (layoutMode.value === 'editor') {
showConsole.value = true
}
diff --git a/src/components/ExecutionHistory.vue b/src/components/ExecutionHistory.vue
index 70aeebe..9c21712 100644
--- a/src/components/ExecutionHistory.vue
+++ b/src/components/ExecutionHistory.vue
@@ -104,7 +104,11 @@
输出
-
+
+
+
+ {{ selectedOutput }}
@@ -139,6 +143,7 @@ import { invoke } from '@tauri-apps/api/core'
import { Copy, History, Play, RefreshCw, RotateCcw, Sparkles, Trash2 } from 'lucide-vue-next'
import Modal from '../ui/Modal.vue'
import Button from '../ui/Button.vue'
+import SqlResultTable from './SqlResultTable.vue'
import type { ExecutionResult, Language } from '../types/app'
import { useToast } from '../plugins/toast'
diff --git a/src/components/MarkdownView.vue b/src/components/MarkdownView.vue
index fe753b0..1246312 100644
--- a/src/components/MarkdownView.vue
+++ b/src/components/MarkdownView.vue
@@ -8,7 +8,9 @@