diff --git a/homepage/dist/docs/ai/index.html b/homepage/dist/docs/ai/index.html new file mode 100644 index 0000000..a207831 --- /dev/null +++ b/homepage/dist/docs/ai/index.html @@ -0,0 +1,194 @@ + + + + + +AI 助手 · OpsxDB 文档 + + + + + + +
+
+ + + + OpsxDB 文档 + + v0.1 + + +
+
+ +
+ + +
+ +

AI 助手

+
更新于 2026-09-23
+
+

AI 面板的目标:让「写不出的 SQL」和「看不懂的 SQL」不再阻塞你。

+

侧栏支持 Ask | Agent:Ask 只生成 SQL;Agent 调用与 MCP 同源的只读工具真查库。外部编辑器可用 npx @rlwj-lab/opsxdb-mcp 接入(见应用内《AI 助手》文档)。

+

六种动作

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
动作用途
生成自然语言 → SQL(「查最近 7 天下单但未支付的用户」)
解释把一段复杂 SQL 翻译成中文说明
优化分析慢查询,给出索引 / 改写建议
修复报错信息 + SQL → 修正版本
方言MySQL ↔ PostgreSQL 等跨方言转换
样例按表结构生成示例查询
+

使用方式

+
    +
  1. 连接库后打开右侧 AI 面板;
  2. +
  3. 选择动作,输入需求或粘贴 SQL(可附上对象树上下文);
  4. +
  5. 生成结果一键放回编辑器,⌘/Ctrl + Enter 执行。
  6. +
+
+

提示:生成的 SQL 依旧走危险语句确认流程 —— AI 产出与手写 SQL 同等对待,不放宽防护。

+
+

接入真实模型

+

AI 面板支持任何 OpenAI 兼容协议的服务(OpenAI / DeepSeek / 通义 / 本地 vLLM 等),回复以 SSE 流式逐字输出,等待模型时不再面对空白。

+

配置入口(二选一):

+
    +
  1. AI 面板右上角「配置」:填 Base URL、API Key、模型名,保存后可一键测试;
  2. +
  3. 配置文件 ~/.opsxdb/ai.json(权限 0600),或环境变量 OPSXDB_AI_PROVIDER / OPSXDB_AI_BASE_URL / OPSXDB_AI_API_KEY / OPSXDB_AI_MODEL。
  4. +
+
+

说明:未配置 API Key 时回落本地 stub(离线占位,内容为模板演示);AI Key 保存后服务端只回显掩码(sk-***)。

+
+

数据流向承诺

+
    +
  • 默认只发送你明确提交的内容(附当前库表结构上下文,不含连接凭据);
  • +
  • 可完全关闭 AI 功能(顶栏隐藏面板即可,无后台请求);
  • +
  • 使用云端模型时在界面上明确标识,生成 SQL 依旧走危险语句确认流程。
  • +
+ +
+ + + + +
+ + +
+ + + + diff --git a/homepage/dist/docs/assets/docs.css b/homepage/dist/docs/assets/docs.css new file mode 100644 index 0000000..18dc68a --- /dev/null +++ b/homepage/dist/docs/assets/docs.css @@ -0,0 +1,246 @@ +/* OpsxDB 文档站 —— 清爽专业风格(浅色) */ +:root { + --blue: #059669; + --blue-dark: #047857; + --blue-soft: rgba(5, 150, 105, 0.08); + --bg: #f6f8fb; + --panel: #ffffff; + --border: #e4e9f1; + --text: #1c2434; + --text-2: #5b6880; + --text-3: #98a2b3; + --code-bg: #f3f6fb; + --code-border: #e1e8f3; + --green: #059669; + --amber: #b45309; + --red: #dc2626; + --sidebar-w: 262px; + --toc-w: 220px; + --topbar-h: 56px; + --radius: 10px; + --shadow: 0 1px 3px rgba(16, 24, 40, 0.06), 0 8px 24px rgba(16, 24, 40, 0.05); + --mono: "JetBrains Mono", SFMono-Regular, Menlo, Consolas, monospace; +} +* { box-sizing: border-box; } +html { scroll-behavior: smooth; scroll-padding-top: 72px; } +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", "Segoe UI", sans-serif; + background: var(--bg); + color: var(--text); + font-size: 14.5px; + line-height: 1.75; +} +a { color: var(--blue); text-decoration: none; } +.i { width: 15px; height: 15px; stroke: currentColor; fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; vertical-align: -2px; } +a:hover { color: var(--blue-dark); text-decoration: underline; } + +/* ---------- 顶栏 ---------- */ +.topbar { + position: sticky; top: 0; z-index: 50; + background: rgba(255, 255, 255, 0.92); + backdrop-filter: saturate(1.4) blur(8px); + border-bottom: 1px solid var(--border); +} +.topbar-inner { + max-width: 1440px; margin: 0 auto; height: var(--topbar-h); + display: flex; align-items: center; gap: 14px; padding: 0 20px; +} +.menu-btn { + display: none; border: 1px solid var(--border); background: #fff; + border-radius: 8px; width: 34px; height: 34px; cursor: pointer; color: var(--text-2); + place-items: center; +} +.menu-btn .i { width: 17px; height: 17px; } +.brand { display: flex; align-items: center; gap: 9px; text-decoration: none !important; } +.brand-logo { display: inline-flex; } +.brand-logo svg { display: block; border-radius: 7px; } +.brand-name { font-size: 16px; font-weight: 700; color: var(--text); } +.brand-name em { font-style: normal; font-weight: 500; color: var(--text-2); margin-left: 2px; } +.ver-badge { + font-size: 11px; font-weight: 600; color: var(--blue); + background: var(--blue-soft); border: 1px solid rgba(5, 150, 105, 0.22); + padding: 1px 9px; border-radius: 999px; white-space: nowrap; +} +.search { position: relative; flex: 1; max-width: 420px; margin-left: 8px; } +.search input { + width: 100%; height: 36px; border: 1px solid var(--border); border-radius: 9px; + background: var(--bg); padding: 0 14px 0 34px; font-size: 13.5px; color: var(--text); outline: none; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' fill='none' stroke='%2398a2b3' stroke-width='2' viewBox='0 0 24 24'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='m20 20-3.5-3.5'/%3E%3C/svg%3E"); + background-repeat: no-repeat; background-position: 12px center; +} +.search input:focus { border-color: var(--blue); background: #fff; box-shadow: 0 0 0 3px var(--blue-soft); } +.search-panel { + position: absolute; top: 44px; left: 0; right: 0; background: #fff; + border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow); + max-height: 420px; overflow: auto; padding: 6px; +} +.search-item { display: block; padding: 8px 12px; border-radius: 8px; text-decoration: none !important; } +.search-item:hover, .search-item.sel { background: var(--blue-soft); } +.search-item .si-title { font-weight: 600; color: var(--text); font-size: 13.5px; } +.search-item .si-group { color: var(--text-3); font-size: 11px; margin-left: 6px; } +.search-item .si-snippet { color: var(--text-2); font-size: 12px; margin-top: 2px; display: block; } +.search-empty { padding: 14px; text-align: center; color: var(--text-3); font-size: 13px; } +.top-links { margin-left: auto; display: flex; gap: 16px; align-items: center; } +.top-links a { font-size: 13.5px; font-weight: 500; } + +/* ---------- 三栏布局 ---------- */ +.layout { + max-width: 1440px; margin: 0 auto; display: grid; + grid-template-columns: var(--sidebar-w) minmax(0, 1fr) var(--toc-w); + gap: 0 28px; padding: 24px 20px 60px; +} + +/* 侧栏 */ +.sidebar { position: sticky; top: calc(var(--topbar-h) + 24px); align-self: start; max-height: calc(100vh - var(--topbar-h) - 48px); overflow-y: auto; padding-right: 8px; } +.sidebar::-webkit-scrollbar { width: 4px; } +.sidebar::-webkit-scrollbar-thumb { background: #d6dde8; border-radius: 4px; } +.nav-group { margin-bottom: 18px; } +.nav-group-title { + font-size: 11.5px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; + color: var(--text-3); padding: 0 10px 6px; +} +.nav-link { + display: block; padding: 6px 10px; border-radius: 8px; font-size: 13.5px; + color: var(--text-2); text-decoration: none !important; border-left: 2px solid transparent; +} +.nav-link:hover { background: rgba(5, 150, 105, 0.06); color: var(--text); } +.nav-link.active { + background: var(--blue-soft); color: var(--blue-dark); font-weight: 600; + border-left-color: var(--blue); +} +.sidebar-foot { margin-top: 24px; padding: 12px 10px 0; border-top: 1px solid var(--border); font-size: 11.5px; color: var(--text-3); } + +/* 内容 */ +.content { min-width: 0; max-width: 860px; } +.breadcrumb { font-size: 12.5px; color: var(--text-3); margin-bottom: 10px; } +.breadcrumb span { margin: 0 6px; } +.page-title { font-size: 30px; font-weight: 700; letter-spacing: -0.02em; margin: 0 0 6px; line-height: 1.3; } +.page-meta { font-size: 12.5px; color: var(--text-3); margin-bottom: 22px; } + +/* Markdown 排版 */ +.md h2 { font-size: 21px; font-weight: 700; margin: 38px 0 12px; padding-top: 8px; letter-spacing: -0.01em; } +.md h3 { font-size: 16.5px; font-weight: 700; margin: 26px 0 8px; } +.md h2 + h3, .md h1 + h2 { margin-top: 18px; } +.md p { margin: 10px 0; color: #2a3348; } +.md ul, .md ol { padding-left: 22px; margin: 10px 0; } +.md li { margin: 5px 0; color: #2a3348; } +.md li::marker { color: var(--blue); } +.md strong { color: var(--text); } +.md hr { border: none; border-top: 1px solid var(--border); margin: 30px 0; } +.md img { max-width: 100%; border-radius: var(--radius); border: 1px solid var(--border); } +.md blockquote { + margin: 14px 0; padding: 10px 16px; border-left: 3px solid var(--blue); + background: var(--blue-soft); border-radius: 0 8px 8px 0; color: #33415e; +} + +/* 表格 */ +.md table { border-collapse: collapse; width: 100%; margin: 16px 0; font-size: 13.5px; background: #fff; border-radius: var(--radius); overflow: hidden; box-shadow: 0 0 0 1px var(--border); } +.md th, .md td { padding: 9px 14px; text-align: left; border-bottom: 1px solid var(--border); vertical-align: top; } +.md th { background: #f7fbf9; font-weight: 600; color: var(--text); white-space: nowrap; } +.md tr:last-child td { border-bottom: none; } + +/* 代码块 */ +.md code { font-family: var(--mono); font-size: 12.8px; background: var(--code-bg); border: 1px solid var(--code-border); border-radius: 5px; padding: 1px 6px; color: #334155; } +.md pre { + position: relative; background: #0f172a; color: #dbe4f3; border-radius: var(--radius); + padding: 16px 16px 14px; overflow-x: auto; margin: 16px 0; font-size: 13px; line-height: 1.65; +} +.md pre code { background: none; border: none; color: inherit; padding: 0; font-size: inherit; } +.md pre .lang-tag { + position: absolute; top: 8px; right: 12px; font-size: 10.5px; color: #7c8db0; + font-family: var(--mono); text-transform: lowercase; letter-spacing: 0.04em; +} +.md pre .copy-btn { + position: absolute; top: 6px; right: 60px; font-size: 11px; color: #9fb0d0; + background: rgba(255, 255, 255, 0.07); border: none; border-radius: 6px; padding: 2px 9px; cursor: pointer; + opacity: 0; transition: opacity 0.15s; +} +.md pre:hover .copy-btn { opacity: 1; } +.md pre .copy-btn:hover { color: #fff; background: rgba(255, 255, 255, 0.14); } +/* 行内高亮 token */ +.md pre .tok-key { color: #7dd3fc; } +.md pre .tok-str { color: #86efac; } +.md pre .tok-num { color: #fcd34d; } +.md pre .tok-com { color: #64748b; font-style: italic; } + +/* 提示块(通过 blockquote 首字符约定) */ +.md blockquote.tip { border-left-color: var(--green); background: rgba(5, 150, 105, 0.07); } +.md blockquote.warn { border-left-color: var(--amber); background: rgba(180, 83, 9, 0.07); } + +/* 上下页 */ +.pn-nav { display: flex; gap: 14px; margin-top: 48px; } +.pn { + flex: 1; border: 1px solid var(--border); background: #fff; border-radius: var(--radius); + padding: 13px 16px; text-decoration: none !important; transition: border-color 0.15s, box-shadow 0.15s; +} +.pn:hover { border-color: var(--blue); box-shadow: var(--shadow); } +.pn.next { text-align: right; } +.pn-label { display: block; font-size: 11.5px; color: var(--text-3); } +.pn-title { display: block; font-weight: 600; color: var(--text); font-size: 14px; margin-top: 2px; } + +/* 反馈 */ +.feedback { + margin-top: 28px; padding: 16px 18px; border-top: 1px solid var(--border); + display: flex; align-items: center; gap: 10px; color: var(--text-2); font-size: 13px; flex-wrap: wrap; +} +.fb-btn { + border: 1px solid var(--border); background: #fff; border-radius: 8px; padding: 5px 12px; + font-size: 12.5px; cursor: pointer; color: var(--text-2); transition: all 0.15s; +} +.fb-btn:hover { border-color: var(--blue); color: var(--blue); } +.fb-btn.done { border-color: var(--green); color: var(--green); background: rgba(5, 150, 105, 0.06); } +.fb-thanks { color: var(--green); font-size: 12.5px; } + +/* 右侧目录 */ +.toc { position: sticky; top: calc(var(--topbar-h) + 24px); align-self: start; max-height: calc(100vh - var(--topbar-h) - 48px); overflow-y: auto; padding-top: 34px; } +.toc-title { font-size: 11.5px; font-weight: 700; letter-spacing: 0.08em; color: var(--text-3); margin-bottom: 8px; } +.toc-nav { display: flex; flex-direction: column; gap: 1px; border-left: 2px solid var(--border); padding-left: 0; } +.toc-nav a { + font-size: 12.5px; color: var(--text-2); padding: 4px 0 4px 12px; text-decoration: none !important; + border-left: 2px solid transparent; margin-left: -2px; line-height: 1.5; +} +.toc-nav a:hover { color: var(--blue); } +.toc-nav a.toc-l3 { padding-left: 26px; font-size: 12px; color: var(--text-3); } +.toc-nav a.active { color: var(--blue); border-left-color: var(--blue); font-weight: 600; } +.print-btn { + margin-top: 18px; width: 100%; border: 1px solid var(--border); background: #fff; + border-radius: 8px; padding: 7px; font-size: 12.5px; color: var(--text-2); cursor: pointer; +} +.print-btn:hover { border-color: var(--blue); color: var(--blue); } + +/* 404 */ +.doc-404 { display: grid; place-items: center; min-height: 100vh; text-align: center; } +.doc-404 h1 { font-size: 56px; margin: 0; color: var(--blue); } +.doc-404 .btn { + display: inline-block; margin-top: 12px; background: var(--blue); color: #fff; + padding: 8px 18px; border-radius: 8px; text-decoration: none !important; font-weight: 600; +} + +/* ---------- 响应式 ---------- */ +@media (max-width: 1200px) { + .layout { grid-template-columns: var(--sidebar-w) minmax(0, 1fr); } + .toc { display: none; } +} +@media (max-width: 880px) { + .menu-btn { display: inline-grid; place-items: center; } + .layout { grid-template-columns: minmax(0, 1fr); padding-top: 12px; } + .sidebar { + position: fixed; z-index: 60; left: 0; top: var(--topbar-h); bottom: 0; + width: 280px; background: #fff; border-right: 1px solid var(--border); + padding: 16px; transform: translateX(-100%); transition: transform 0.2s; max-height: none; + } + .sidebar.open { transform: none; box-shadow: var(--shadow); } + .ver-badge { display: none; } + .top-links a { font-size: 12.5px; } + .page-title { font-size: 24px; } +} + +/* ---------- 打印 ---------- */ +@media print { + .topbar, .sidebar, .toc, .pn-nav, .feedback, .menu-btn { display: none !important; } + .layout { display: block; max-width: none; padding: 0; } + body { background: #fff; } + .md pre { background: #f1f5f9 !important; color: #1e293b !important; } + .md pre .copy-btn, .md pre .lang-tag { display: none; } +} diff --git a/homepage/dist/docs/assets/docs.js b/homepage/dist/docs/assets/docs.js new file mode 100644 index 0000000..f3110c9 --- /dev/null +++ b/homepage/dist/docs/assets/docs.js @@ -0,0 +1,219 @@ +/* OpsxDB 文档站交互:搜索 / 代码复制 / 目录高亮 / 反馈 / 移动端导航 */ +(function () { + "use strict"; + + /* ---------- 代码块:语言标签 + 复制按钮 + 轻量高亮 ---------- */ + document.querySelectorAll("article.md pre").forEach(function (pre) { + var code = pre.querySelector("code"); + if (!code) return; + var lang = (code.className.match(/language-([\w-]+)/) || [, ""])[1]; + if (lang) { + var tag = document.createElement("span"); + tag.className = "lang-tag"; + tag.textContent = lang; + pre.appendChild(tag); + } + // 复制按钮 + var btn = document.createElement("button"); + btn.className = "copy-btn"; + btn.type = "button"; + btn.textContent = "复制"; + btn.addEventListener("click", function () { + navigator.clipboard.writeText(code.textContent).then( + function () { + btn.textContent = "已复制 ✓"; + setTimeout(function () { btn.textContent = "复制"; }, 1400); + }, + function () { btn.textContent = "复制失败"; } + ); + }); + pre.appendChild(btn); + // JSON / bash 轻量高亮 + if (lang === "json") highlightJSON(code); + else if (lang === "bash" || lang === "sh" || lang === "shell") highlightBash(code); + }); + + function esc(s) { + return s.replace(/&/g, "&").replace(//g, ">"); + } + function highlightJSON(code) { + var src = code.textContent; + code.innerHTML = esc(src).replace( + /("(?:\\.|[^"\\])*")(\s*:)?|\b(true|false|null)\b|(-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?)/g, + function (m, str, colon, kw, num) { + if (str && colon) return '' + str + "" + colon; + if (str) return '' + str + ""; + if (kw) return '' + kw + ""; + if (num) return '' + num + ""; + return m; + } + ); + } + function highlightBash(code) { + var lines = code.textContent.split("\n"); + code.innerHTML = lines + .map(function (line) { + if (/^\s*#/.test(line)) return '' + esc(line) + ""; + return esc(line).replace(/(^|\s)(-{1,2}[\w-]+)/g, '$1$2'); + }) + .join("\n"); + } + + /* ---------- blockquote 提示样式约定:> **提示** / > **注意** ---------- */ + document.querySelectorAll("article.md blockquote").forEach(function (bq) { + var t = (bq.textContent || "").trim(); + if (/^(注意|警告|⚠)/.test(t)) bq.classList.add("warn"); + else if (/^(提示|说明|💡|Tip)/i.test(t)) bq.classList.add("tip"); + }); + + /* ---------- 搜索 ---------- */ + var input = document.getElementById("search-input"); + var panel = document.getElementById("search-panel"); + var entries = null; + var selIndex = -1; + + function ensureIndex(cb) { + if (entries) return cb(); + fetch("/docs/search-data.json") + .then(function (r) { return r.json(); }) + .then(function (data) { entries = data; cb(); }) + .catch(function () { entries = []; cb(); }); + } + + function snippet(text, q) { + var i = text.toLowerCase().indexOf(q); + if (i < 0) return text.slice(0, 60) + "…"; + var start = Math.max(0, i - 24); + return (start > 0 ? "…" : "") + text.slice(start, i + q.length + 40) + "…"; + } + + function doSearch() { + var q = input.value.trim().toLowerCase(); + selIndex = -1; + if (!q) { panel.hidden = true; return; } + ensureIndex(function () { + var hits = []; + entries.forEach(function (e) { + var titleHit = e.title.toLowerCase().indexOf(q) >= 0; + var idx = e.text.toLowerCase().indexOf(q); + if (titleHit || idx >= 0) { + hits.push({ + slug: e.slug, + title: e.title, + group: e.group, + score: (titleHit ? 10 : 0) + (idx === 0 ? 3 : 0), + snippet: titleHit ? snippet(e.text, q) : snippet(e.text, q), + }); + } + }); + hits.sort(function (a, b) { return b.score - a.score; }); + hits = hits.slice(0, 8); + if (!hits.length) { + panel.innerHTML = '
没有找到相关内容,换个关键词试试
'; + } else { + panel.innerHTML = hits + .map(function (h) { + return ( + '' + + '' + h.title + '' + h.group + "" + + '' + h.snippet + "" + ); + }) + .join(""); + } + panel.hidden = false; + }); + } + + var debounce; + if (input) { + input.addEventListener("input", function () { + clearTimeout(debounce); + debounce = setTimeout(doSearch, 160); + }); + input.addEventListener("focus", function () { + if (input.value.trim()) doSearch(); + }); + input.addEventListener("keydown", function (e) { + var items = panel.querySelectorAll(".search-item"); + if (e.key === "ArrowDown" && items.length) { + e.preventDefault(); + selIndex = Math.min(selIndex + 1, items.length - 1); + } else if (e.key === "ArrowUp" && items.length) { + e.preventDefault(); + selIndex = Math.max(selIndex - 1, 0); + } else if (e.key === "Enter") { + if (selIndex >= 0 && items[selIndex]) { location.href = items[selIndex].href; return; } + var first = items[0]; + if (first) location.href = first.href; + return; + } else if (e.key === "Escape") { + panel.hidden = true; + return; + } else { + return; + } + items.forEach(function (el, i) { el.classList.toggle("sel", i === selIndex); }); + }); + document.addEventListener("click", function (e) { + if (!e.target.closest(".search")) panel.hidden = true; + }); + } + + /* ---------- 目录滚动高亮 ---------- */ + var tocLinks = Array.prototype.slice.call(document.querySelectorAll(".toc-nav a")); + if (tocLinks.length && "IntersectionObserver" in window) { + var byId = {}; + tocLinks.forEach(function (a) { byId[a.getAttribute("href").slice(1)] = a; }); + var io = new IntersectionObserver( + function (entries) { + entries.forEach(function (en) { + if (en.isIntersecting) { + tocLinks.forEach(function (a) { a.classList.remove("active"); }); + var a = byId[en.target.id]; + if (a) a.classList.add("active"); + } + }); + }, + { rootMargin: "-72px 0px -70% 0px", threshold: 0 } + ); + document.querySelectorAll("article.md h2[id], article.md h3[id]").forEach(function (h) { io.observe(h); }); + } + + /* ---------- 反馈组件 ---------- */ + var fb = document.getElementById("feedback"); + if (fb) { + var pageKey = "opsxdb-docs-fb:" + location.pathname; + var voted = null; + try { voted = localStorage.getItem(pageKey); } catch (e) {} + var btns = fb.querySelectorAll(".fb-btn"); + var thanks = document.getElementById("fb-thanks"); + function mark(v) { + btns.forEach(function (b) { + if (b.dataset.v === v) b.classList.add("done"); + }); + thanks.hidden = false; + try { localStorage.setItem(pageKey, v); } catch (e) {} + } + if (voted) mark(voted); + btns.forEach(function (b) { + b.addEventListener("click", function () { mark(b.dataset.v); }); + }); + } + + /* ---------- 打印 ---------- */ + var printBtn = document.getElementById("print-btn"); + if (printBtn) printBtn.addEventListener("click", function () { window.print(); }); + + /* ---------- 移动端侧栏 ---------- */ + var menuBtn = document.getElementById("menu-btn"); + var sidebar = document.getElementById("sidebar"); + if (menuBtn && sidebar) { + menuBtn.addEventListener("click", function () { sidebar.classList.toggle("open"); }); + document.addEventListener("click", function (e) { + if (sidebar.classList.contains("open") && !e.target.closest(".sidebar") && !e.target.closest(".menu-btn")) { + sidebar.classList.remove("open"); + } + }); + } +})(); diff --git a/homepage/dist/docs/connect/index.html b/homepage/dist/docs/connect/index.html new file mode 100644 index 0000000..7dbc8dd --- /dev/null +++ b/homepage/dist/docs/connect/index.html @@ -0,0 +1,198 @@ + + + + + +新建连接 · OpsxDB 文档 + + + + + + +
+
+ + + + OpsxDB 文档 + + v0.1 + + +
+
+ +
+ + +
+ +

新建连接

+
更新于 2026-09-20
+
+

本章说明各数据库类型的连接表单、URL 格式与高级选项(SSL / SSH 隧道)。

+

通用流程

+
    +
  1. 连接选择器点「新建」或选某个数据库类型;
  2. +
  3. 填写表单(不同驱动表单不同,见下表);
  4. +
  5. 测试 → 通过后 保存并连接。
  6. +
+

支持直接粘贴 URL 自动填表:

+
mysql://root:pass@127.0.0.1:3306/shop
+postgres://opsx:pass@127.0.0.1:5432/app
+
+

各驱动表单

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
驱动表单特有字段
MySQL / PostgreSQL / SQL Serverstandardhost · port · user · password · database · ssl · ssh
Oracleoraclehost · port · user · password · service(如 ORCL)
SQLitefiledatabase 填本地文件路径(如 ~/data/demo.sqlite)
Redisredishost · port · password · database 序号 · 模式(单机 / 哨兵 / 集群)· 键分隔符
+

表单只收集服务端实际消费的字段;历史遗留的死参数不会出现在表单里。

+

MySQL 族与 PostgreSQL 族

+

协议兼容的国产库无需单独驱动,直接复用家族驱动:

+
    +
  • MySQL 族:MariaDB(3307)、TiDB(4000)、OceanBase(2881)、PolarDB / TDSQL(3306)—— 表单里选对应类型即可;
  • +
  • PostgreSQL 族:GaussDB / openGauss、人大金仓 Kingbase(54321)—— 走 postgres 表单,注意默认库与用户名差异。
  • +
+

SSL / TLS

+

连接表单中开启 ssl 即可;按连接独立配置,互不影响。内网自签证书场景按需放宽校验策略。

+

SSH 隧道

+

数据库在跳板机后面时,开启 ssh 字段组,填写跳板机地址与凭据:OpsxDB 会先建 SSH 隧道,再把数据库连接走隧道转发,无需把库端口暴露到公网。

+

Redis 哨兵与集群

+
    +
  • 哨兵:模式选 Sentinel,填写 Sentinel 节点列表(host:port,多行)和主节点名 masterName;
  • +
  • 集群:模式选 Cluster,填写至少一个种子节点。对象树只显示 DB 0(Cluster 无 SELECT);
  • +
  • 单机模式只填 host/port,与原先一致。
  • +
+

字段细节与键浏览见 Redis 工作台。

+
+

提示:连接保存后,后续查询仅携带 sessionId,账密不会随每次请求上送;密码在本机混淆存储。

+
+ +
+ + + + +
+ + +
+ + + + diff --git a/homepage/dist/docs/drivers/index.html b/homepage/dist/docs/drivers/index.html new file mode 100644 index 0000000..7b8f8a1 --- /dev/null +++ b/homepage/dist/docs/drivers/index.html @@ -0,0 +1,341 @@ + + + + + +驱动支持 · OpsxDB 文档 + + + + + + +
+
+ + + + OpsxDB 文档 + + v0.1 + + +
+
+ +
+ + +
+ +

驱动支持

+
更新于 2026-09-23
+
+

OpsxDB 当前支持 18 种数据库,覆盖关系型、NoSQL、时序/搜索与国产库,全部经真实实例端到端验收(ready + verified)。常用引擎以原生 Go 驱动编译内置,开箱即用;JVM 系数据库通过 Agent 桥按需接入。

+

完整支持矩阵

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
数据库类型接入方式默认端口状态
MySQL关系型原生内置3306✅ 已验收
MariaDB关系型原生内置3307✅ 已验收
TiDB关系型原生内置4000✅ 已验收
PostgreSQL关系型原生内置5432✅ 已验收
SQL Server关系型原生内置1433✅ 已验收
Oracle关系型原生内置(go-ora,不引入 JVM)1521✅ 已验收
SQLite关系型原生内置(本地文件)—✅ 已验收
MongoDBNoSQLAgent 桥(官方驱动)27017✅ 已验收
RedisNoSQL原生内置6379✅ 已验收
Elasticsearch时序/搜索原生内置(SQL API)9200✅ 已验收
ZooKeeper时序/搜索Agent 桥2181✅ 已验收
InfluxDB时序/搜索原生内置(Flux)8086✅ 已验收
达梦 DM国产库Agent 桥(JDBC)5236✅ 已验收
OceanBase国产库原生内置(MySQL 协议族)2881✅ 已验收
GaussDB / openGauss国产库原生内置(PG 协议族)5432✅ 已验收
PolarDB国产库原生内置(MySQL 协议族)3306✅ 已验收
TDSQL国产库原生内置(MySQL 协议族)3306✅ 已验收
Kingbase国产库原生内置(PG 协议族)54321✅ 已验收
+

协议族复用

+

MySQL 族(MySQL / MariaDB / TiDB / OceanBase / PolarDB / TDSQL)共用同一原生驱动,PostgreSQL 族(PostgreSQL / GaussDB / openGauss / Kingbase)同理 —— 同族引擎的连接体验与能力完全一致,仅默认端口不同。

+

Agent 桥驱动(按需下载)

+

MongoDB、ZooKeeper、达梦通过 JVM Agent 桥接入:

+
    +
  • 首次使用时在驱动管理器按需下载对应组件,版本固定并做 sha256 校验(Gitee 主源 + GitHub 备源);
  • +
  • 商业数据库(如达梦官方 JDBC)不代下,需自备 jar 放入驱动目录;
  • +
  • Agent 进程随会话池化管理,崩溃自动摘除重建,应用退出级联清理。
  • +
+

各引擎能力边界

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
引擎浏览执行写入说明
关系型全家库/表/视图/存储过程/索引/外键/触发器SQL✅(含结果集编辑回写)MySQL 族附执行计划
Redis键树(SCAN 游标)/ TTL命令编辑器✅单机 / Sentinel / Cluster 三模式;危险命令族拦截
MongoDB库/集合db.coll.find() DSL✅(增删改单文档)官方驱动经 Agent 桥
ZooKeeper路径树GET / SET✅(写动词二次确认)经 Agent 桥
Elasticsearch索引浏览SQL API只读官方 JDBC 付费,故走原生 SQL API
InfluxDBorg/bucket 浏览Flux 脚本只读用户=org、密码=token
+
+

说明(Oracle):go-ora 纯 Go 驱动,无需安装 Java;Apple Silicon 容器环境起 Oracle XE 会遇到 ORA-00442 属环境限制,x86 或真实实例不受影响。

+
+ +
+ + + + +
+ + +
+ + + + diff --git a/homepage/dist/docs/faq/index.html b/homepage/dist/docs/faq/index.html new file mode 100644 index 0000000..d46705d --- /dev/null +++ b/homepage/dist/docs/faq/index.html @@ -0,0 +1,158 @@ + + + + + +常见问题 · OpsxDB 文档 + + + + + + +
+
+ + + + OpsxDB 文档 + + v0.1 + + +
+
+ +
+ + +
+ +

常见问题

+
更新于 2026-09-20
+
+

产品形态

+

Q:能在浏览器里操作数据库吗?
+不能。OpsxDB 客户端唯一形态是桌面 App(Tauri 2);浏览器只承载官网与文档(由本地后端 :8788 内置提供)。开发时的 :5174 只是桌面 devUrl 的资产服务,不是网页客户端。

+

Q:官网和文档部署在哪?
+就内置在你运行的那个二进制里:http://127.0.0.1:8788/ 是官网,/docs 是文档;无需额外部署。

+

Q:怎么打安装包?
+./run.sh package 产出 Tauri 安装包(DMG)并内嵌 sidecar 后端二进制。

+

数据与安全

+

Q:我的连接密码存在哪?
+本机,混淆存储;查询只带会话 ID,密码不会随请求重复上送,也不会同步到云端。

+

Q:会上传我的 SQL 或查询结果吗?
+不会。没有遥测、没有账号、没有云依赖。AI 助手为可选功能:只有你主动配置了模型服务并主动提问时,才会把当次请求(含库表结构上下文,不含连接凭据)发给你指定的服务地址。

+

Q:能在公司内网用吗?
+能。单二进制 + 内置静态页,无外部依赖;默认只监听回环地址,对外需显式配置。

+

驱动相关

+

Q:Oracle 能用吗?
+驱动代码就绪(go-ora 纯 Go 实现,无需 JVM),但本机 docker 验收在 Apple Silicon 上受镜像限制未通过(ORA-00442),需 x86 环境或真库完成验收,详见《驱动支持》。

+

Q:达梦 / MongoDB 什么时候支持?
+已列入路线:长尾库(达梦、MongoDB、ZooKeeper、ES、InfluxDB)规划 agent 按需接入,驱动分发走独立仓库并校验 sha256。

+

Q:MySQL 族 / PG 族的国产库怎么连?
+协议兼容直接复用家族驱动:TiDB / OceanBase / PolarDB / TDSQL 选对应类型(MySQL 协议);GaussDB / Kingbase 走 PostgreSQL 表单。注意各自默认端口与用户名差异。

+

其他

+

Q:和 OpsxAPI 是什么关系?
+同一团队的姊妹项目:OpsxAPI 是接口工作台,OpsxDB 是数据库工作台,共用一套 monorepo 脚手架(web + Gin + 可选 Tauri),产品面各自独立。

+

Q:快捷键有哪些?
+核心就一个:⌘/Ctrl + Enter 执行当前语句或选区;双击结果单元格复制。完整列表见《SQL 工作台》。

+ +
+ + + + +
+ + +
+ + + + diff --git a/homepage/dist/docs/index.html b/homepage/dist/docs/index.html new file mode 100644 index 0000000..8cf5c00 --- /dev/null +++ b/homepage/dist/docs/index.html @@ -0,0 +1,222 @@ + + + + + +产品介绍 · OpsxDB 文档 + + + + + + +
+
+ + + + OpsxDB 文档 + + v0.1 + + +
+
+ +
+ + +
+ +

产品介绍

+
更新于 2026-09-23
+
+

OpsxDB 是一款本地优先的桌面数据库工作台,面向运维与开发:连库、写 SQL、看结果,全在本机完成。

+

主交付形态是可安装的桌面应用(Tauri 2),本地 Go 后端随应用自动启动;同一套界面也可用单个二进制在 Web / 内网部署。数据全部保存在本机,不经过任何第三方服务器。

+

功能总览

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
能力说明
18 种数据库关系型 / NoSQL / 时序·搜索 / 国产库,全部端到端验收;常用引擎原生内置
连接选择器搜索 / 分类 / 最近 / 图标网格;粘贴连接 URL 一键填入表单;连接颜色标记区分环境
SQL 工作台CodeMirror 编辑器、⌘/Ctrl+Enter 执行语句或选区、多 Tab、可拖分栏、格式化、执行历史
对象树懒加载库 / 表 / 列 / 索引 / 触发器;点表名直接看前 100 行;右键管理对象
结果处理单元格编辑回写 / 右键复制(值·行·JSON·INSERT)/ CSV·JSON·INSERT 导出 / 过滤构建器 / 分页
Redis 工作台单机 / Sentinel / Cluster;键树浏览(SCAN 游标)、TTL、Hash/JSON 编辑、危险命令拦截
安全通道每连接独立配置 SSL/TLS 与 SSH 隧道;后端本机监听 + 访问令牌
AI 助手生成 / 解释 / 优化 / 修复 / 方言转换 / 样例;OpenAI 兼容协议 + SSE 流式输出
危险操作防护DROP / TRUNCATE / 无 WHERE 的 UPDATE·DELETE 执行前确认
桌面唯一形态桌面 GUI(Tauri 2),本地后端随应用自动拉起
+

支持的数据库

+ + + + + + + + + + + + + + + + + + + + + + + + + +
家族覆盖
关系型MySQL · MariaDB · TiDB · PostgreSQL · SQL Server · Oracle · SQLite
NoSQLRedis · MongoDB
时序 / 搜索Elasticsearch · ZooKeeper · InfluxDB
国产库达梦 DM · OceanBase · GaussDB / openGauss · PolarDB · TDSQL · Kingbase
+
+

逐引擎的接入方式、默认端口与能力边界见《驱动支持》;全部 18 引擎均已实测验收。

+
+

为什么选 OpsxDB

+
    +
  • 数据主权:连接配置与查询历史只存在本机;后端默认仅监听 127.0.0.1。
  • +
  • 开箱即用:桌面版双击即用,本地后端随应用自动拉起;官网与文档也由它内置提供。
  • +
  • 为快设计:点表即看数据、⌘Enter 即执行、结果三键取走(复制 / CSV / INSERT)。
  • +
  • 轻量克制:一个 Go 二进制 + 一份前端,内网可部署,无遥测无账号。
  • +
+
+

提示:想马上动手?直接看下一章《快速开始》,30 秒连上第一个库。

+
+ +
+ + + + +
+ + +
+ + + + diff --git a/homepage/dist/docs/interface/index.html b/homepage/dist/docs/interface/index.html new file mode 100644 index 0000000..1302f1e --- /dev/null +++ b/homepage/dist/docs/interface/index.html @@ -0,0 +1,189 @@ + + + + + +界面导览 · OpsxDB 文档 + + + + + + +
+
+ + + + OpsxDB 文档 + + v0.1 + + +
+
+ +
+ + +
+ +

界面导览

+
更新于 2026-09-20
+
+

OpsxDB 的界面为「高频操作」设计:从打开应用到看到数据,路径越短越好。

+

连接选择器

+

启动后的第一个界面:

+
    +
  • 搜索:按名称快速过滤已保存的连接;
  • +
  • 分类:关系型 / NoSQL / 国产库 / 时序·搜索 分组浏览;
  • +
  • 最近:最近使用的连接排在最前;
  • +
  • 图标网格:按数据库类型直选,未就绪的类型会标注「未就绪」(仅可保存配置);
  • +
  • URL 填入:粘贴 mysql://user:pass@host:3306/db 点「填入」,字段自动拆解。
  • +
+

工作台布局

+

连接成功后进入工作台,三栏结构:

+ + + + + + + + + + + + + + + + + + + + + +
区域内容
左侧连接列表 + 对象树(库 → 表 → 列,懒加载)
中部SQL 编辑器(多 Tab)+ 结果面板,可拖动分栏
右侧AI 面板(生成 / 解释 / 优化 / 修复 / 方言 / 样例)
+

对象树

+
    +
  • 点表名:直接打开前 100 行数据;
  • +
  • 展开表:查看列结构;
  • +
  • 右键表:打开表 / 查看 DDL / 生成 SQL(SELECT·INSERT·UPDATE·DELETE)/ 重命名 / 克隆表结构·克隆表(含数据)/ 清空 / 截断 / 删除 —— 危险项红色并二次确认;
  • +
  • 右键库:新建查询 / 新建表(生成 CREATE TABLE 模板到编辑器)/ 复制 / 设为默认库 / 刷新 / 删除库;
  • +
  • Redis:按键分隔符编文件夹,点键打开类型化详情(TTL / JSON / 增删字段);
  • +
  • 库列表懒加载,大实例也不卡。
  • +
+

编辑器与结果

+
    +
  • CodeMirror 语法高亮,⌘/Ctrl+Enter 执行当前语句或选区(不是整页脚本);
  • +
  • 多 Tab 并行查询,互不阻塞;
  • +
  • 结果面板:复制 / CSV / INSERT 三种取数方式,双击单元格复制;
  • +
  • 超过截断阈值时结果有明确提示。
  • +
+

个性化

+
    +
  • 深色 / 浅色主题切换;
  • +
  • Tab 布局与主题选择持久化,下次打开保持原样;
  • +
  • 查询历史本地留存,可回跳重跑。
  • +
+ +
+ + + + +
+ + +
+ + + + diff --git a/homepage/dist/docs/intro/index.html b/homepage/dist/docs/intro/index.html new file mode 100644 index 0000000..8cf5c00 --- /dev/null +++ b/homepage/dist/docs/intro/index.html @@ -0,0 +1,222 @@ + + + + + +产品介绍 · OpsxDB 文档 + + + + + + +
+
+ + + + OpsxDB 文档 + + v0.1 + + +
+
+ +
+ + +
+ +

产品介绍

+
更新于 2026-09-23
+
+

OpsxDB 是一款本地优先的桌面数据库工作台,面向运维与开发:连库、写 SQL、看结果,全在本机完成。

+

主交付形态是可安装的桌面应用(Tauri 2),本地 Go 后端随应用自动启动;同一套界面也可用单个二进制在 Web / 内网部署。数据全部保存在本机,不经过任何第三方服务器。

+

功能总览

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
能力说明
18 种数据库关系型 / NoSQL / 时序·搜索 / 国产库,全部端到端验收;常用引擎原生内置
连接选择器搜索 / 分类 / 最近 / 图标网格;粘贴连接 URL 一键填入表单;连接颜色标记区分环境
SQL 工作台CodeMirror 编辑器、⌘/Ctrl+Enter 执行语句或选区、多 Tab、可拖分栏、格式化、执行历史
对象树懒加载库 / 表 / 列 / 索引 / 触发器;点表名直接看前 100 行;右键管理对象
结果处理单元格编辑回写 / 右键复制(值·行·JSON·INSERT)/ CSV·JSON·INSERT 导出 / 过滤构建器 / 分页
Redis 工作台单机 / Sentinel / Cluster;键树浏览(SCAN 游标)、TTL、Hash/JSON 编辑、危险命令拦截
安全通道每连接独立配置 SSL/TLS 与 SSH 隧道;后端本机监听 + 访问令牌
AI 助手生成 / 解释 / 优化 / 修复 / 方言转换 / 样例;OpenAI 兼容协议 + SSE 流式输出
危险操作防护DROP / TRUNCATE / 无 WHERE 的 UPDATE·DELETE 执行前确认
桌面唯一形态桌面 GUI(Tauri 2),本地后端随应用自动拉起
+

支持的数据库

+ + + + + + + + + + + + + + + + + + + + + + + + + +
家族覆盖
关系型MySQL · MariaDB · TiDB · PostgreSQL · SQL Server · Oracle · SQLite
NoSQLRedis · MongoDB
时序 / 搜索Elasticsearch · ZooKeeper · InfluxDB
国产库达梦 DM · OceanBase · GaussDB / openGauss · PolarDB · TDSQL · Kingbase
+
+

逐引擎的接入方式、默认端口与能力边界见《驱动支持》;全部 18 引擎均已实测验收。

+
+

为什么选 OpsxDB

+
    +
  • 数据主权:连接配置与查询历史只存在本机;后端默认仅监听 127.0.0.1。
  • +
  • 开箱即用:桌面版双击即用,本地后端随应用自动拉起;官网与文档也由它内置提供。
  • +
  • 为快设计:点表即看数据、⌘Enter 即执行、结果三键取走(复制 / CSV / INSERT)。
  • +
  • 轻量克制:一个 Go 二进制 + 一份前端,内网可部署,无遥测无账号。
  • +
+
+

提示:想马上动手?直接看下一章《快速开始》,30 秒连上第一个库。

+
+ +
+ + + + +
+ + +
+ + + + diff --git a/homepage/dist/docs/quickstart/index.html b/homepage/dist/docs/quickstart/index.html new file mode 100644 index 0000000..30b12e6 --- /dev/null +++ b/homepage/dist/docs/quickstart/index.html @@ -0,0 +1,190 @@ + + + + + +快速开始 · OpsxDB 文档 + + + + + + +
+
+ + + + OpsxDB 文档 + + v0.1 + + +
+
+ +
+ + +
+ +

快速开始

+
更新于 2026-09-20
+
+

本章从零到出结果:起服务 → 建连接 → 执行第一条 SQL。

+

1. 启动

+

桌面版(主交付形态)双击 OpsxDB 应用即可,本地后端随应用自动拉起。

+

从源码运行(开发):

+
git clone <repo> opsxdb && cd opsxdb
+npm install
+
+./run.sh gui    # 桌面形态(开发):Tauri 窗口 + 本地后端
+./run.sh web    # 仅启动官网与文档 → http://127.0.0.1:8788/
+./run.sh package  # 打桌面安装包(DMG,内嵌后端)
+
+
+

注意:客户端只在桌面 App 里运行。./run.sh gui 起的 :5174 是桌面 devUrl 的资产服务,不是浏览器客户端;浏览器只用于官网 / 与文档 /docs(后端 :8788 直接提供)。

+
+

2. 新建连接

+
    +
  1. +

    打开应用,进入连接选择器,选择数据库类型(如 MySQL);

    +
  2. +
  3. +

    或者直接粘贴连接 URL,点「填入」自动拆解字段:

    +
    mysql://root:pass@127.0.0.1:3306/shop
    +
    +
  4. +
  5. +

    点 测试 验证连通性,再点 保存并连接。

    +
  6. +
+

连接配置保存在本机,密码混淆存储;后续查询只携带会话 ID,不再上送账密。

+

3. 第一次查询

+
    +
  1. +

    左侧对象树展开库,点表名直接查看前 100 行(展开表可看列结构);

    +
  2. +
  3. +

    打开 SQL 编辑器,输入:

    +
    SELECT * FROM orders ORDER BY id DESC LIMIT 100;
    +
    +
  4. +
  5. +

    按 ⌘/Ctrl + Enter 执行当前语句(或选中的片段);

    +
  6. +
  7. +

    结果面板支持复制 / 导出 CSV / 生成 INSERT,双击单元格即复制。

    +
  8. +
+

4. 验证服务

+
curl -s http://127.0.0.1:8788/health
+# {"ok":true,"service":"opsxdb"}
+
+

5. 手边没有数据库?

+

本地还没有可连的库?用仓库自带的辅助脚本一键起一个(需要 Docker,一次只起一个):

+
./tests/dbctl.sh up a    # MySQL
+./tests/dbctl.sh up c    # PostgreSQL(用户 opsx)
+./tests/dbctl.sh up f    # Redis
+
+

各驱动的验收状态见《驱动支持》。

+ +
+ + + + +
+ + +
+ + + + diff --git a/homepage/dist/docs/redis/index.html b/homepage/dist/docs/redis/index.html new file mode 100644 index 0000000..02798b3 --- /dev/null +++ b/homepage/dist/docs/redis/index.html @@ -0,0 +1,269 @@ + + + + + +Redis 工作台 · OpsxDB 文档 + + + + + + +
+
+ + + + OpsxDB 文档 + + v0.1 + + +
+
+ +
+ + +
+ +

Redis 工作台

+
更新于 2026-09-20
+
+

Redis 连接使用专用表单(redis)。连上后,对象树是键空间浏览器,编辑器是 Redis 命令行 —— 和 SQL 共用同一套输入框,不另开 CLI 页。

+

为什么命令行不单独做一套

+

SQL 工作台已经有:多 Tab、⌘/Ctrl+Enter、查询历史、书签、危险确认、取消。Redis 命令同样是「输入 → 执行 → 结果表」。

+

拆成独立 CLI(终端 REPL)会让快捷键、历史、危险确认分叉,也和 Navicat 式多引擎工作台不一致。

+

因此:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SQLRedis
输入框同一 CodeMirror同一 CodeMirror(占位/补全换成命令)
切分分号语句按行(SET k "a;b" 不会被分号拆开)
执行⌘/Ctrl+Enter 当前语句或选区⌘/Ctrl+Enter 当前行或选区
结果结果表命令结果表;从对象树打开键则进入键详情
+

Another Redis Desktop Manager 的独立 CLI Tab、opsxsql 的单行命令 + 输出日志,列为后续 P1,不是现在的主路径。

+

键空间浏览

+

对象树对 Redis 显示 DB0–15(Cluster 仅 0)。展开库后:

+
    +
  • SCAN 过滤:输入 user:* 点「应用」;生产大库请带前缀,避免扫全库。最多展示 500 个键,超出提示截断。
  • +
  • 按分隔符编文件夹:连接表单的「键分隔符」默认 :,CEX:FOLLOW:FOLLOWERS:1 显示为 CEX / FOLLOW / FOLLOWERS / 1。文件夹显示数量;右键可「只看此前缀」「在此新建键」。
  • +
  • 类型色点:string 绿 / hash 蓝 / list 橙 / set 紫 / zset 青。
  • +
  • 点键:打开键详情(不是假 SELECT)。
  • +
+

键详情

+

对标 Another Redis Desktop Manager 的 Hash/List/Set 视图:

+
    +
  • 类型徽章、键名(回车重命名)、TTL(回车或「保存 TTL」,-1 永久)、刷新、导出还原命令、删除;
  • +
  • 结构表:Hash 为 ID / Field / Value,JSON 值自动美化;可新增字段、编辑、删除;
  • +
  • JSON 视图:整体格式化;
  • +
  • 表内关键字过滤。
  • +
+

String 可直接改值保存。

+

命令执行

+

编辑器直接写 Redis 命令:

+
PING
+SET demo:key "hello" EX 60
+GET demo:key
+HGETALL demo:hash
+SCAN 0 MATCH demo:* COUNT 100
+INFO memory
+
+
    +
  • 未点名的命令走通用 Do(EXISTS / ECHO / INFO / CLIENT LIST 等不必再加白名单);
  • +
  • FLUSHALL / FLUSHDB / KEYS / CONFIG 仍要二段确认;
  • +
  • KEYS * 在大库上会阻塞 —— 请用 SCAN MATCH。
  • +
+

切换逻辑库(SELECT)

+

SELECT 1 是 Redis 官方的切库命令,编辑器直接支持 —— 语义与 redis-cli 一致:切换后本 Tab 的后续命令都在目标库执行:

+
SELECT 1
+GET db1:only:key      # 在 db1 执行
+
+
    +
  • 没有也没有 USE(那是 SQL 语法)—— 输入 USE db1 会得到 Redis 原生报错
    +ERR unknown command 'USE',与 redis-cli 行为一致;
  • +
  • 切库只影响当前查询 Tab(多 Tab 可各连各的库),左侧对象树点开对应库可浏览键;
  • +
  • Cluster 模式只有 DB 0,SELECT 无效。
  • +
+

连接参数

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
字段说明
host / port单机默认 127.0.0.1:6379
password / userACL / requirepass
database逻辑库序号(0–15 常见;Cluster 忽略)
键分隔符对象树文件夹分隔,默认 :
sslTLS
redisModestandalone(默认)/ sentinel / cluster
redisNodesSentinel / Cluster 节点列表,host:port 多行或逗号分隔
masterNameSentinel 主节点名(必填)
sentinelPasswordSentinel 密码(可空)
+

Sentinel

+

模式选「哨兵」,填写至少一个 Sentinel 地址和 masterName(如 mymaster)。逻辑库序号仍可用。

+

Cluster

+

模式选「集群」,填写至少一个种子节点。Cluster 不支持 SELECT 多库,对象树只暴露 DB 0。槽位路由由客户端处理,键浏览走 SCAN。

+
+

环境:Sentinel / Cluster 表单与后端已接好;真实拓扑联调见 docs/BACKLOG.md 环境缺口。

+
+ +
+ + + + +
+ + +
+ + + + diff --git a/homepage/dist/docs/results/index.html b/homepage/dist/docs/results/index.html new file mode 100644 index 0000000..211e5e8 --- /dev/null +++ b/homepage/dist/docs/results/index.html @@ -0,0 +1,184 @@ + + + + + +结果与导出 · OpsxDB 文档 + + + + + + +
+
+ + + + OpsxDB 文档 + + v0.1 + + +
+
+ +
+ + +
+ +

结果与导出

+
更新于 2026-09-20
+
+

查询跑完只是开始,把结果带走才算完成 —— OpsxDB 给了三条最快路径。

+

三种取数方式

+ + + + + + + + + + + + + + + + + + + + + +
方式用途
复制直接进剪贴板,贴到群聊 / 文档 / 表格
CSV导出标准 CSV 文件,Excel / Numbers 直接打开
INSERT把结果行生成为 INSERT 语句,直接可在别的库回放
+

表数据工作台(关系库)

+

从对象树打开表后,结果区按 DBeaver / DBX 的数据编辑器组织,而不是只有一张裸网格:

+
    +
  • 工具栏:刷新、增行、删行、提交(有主键才写回);
  • +
  • 条件过滤:列 + 运算符(= ≠ > < 包含 空…)+ 值,可加多条 AND;应用后重查,SQL 回填编辑器;
  • +
  • 本页搜索:不打库,只过滤当前结果;
  • +
  • 列头:列名 + 类型色 + 主键标记,悬停看注释。
  • +
+

表结构

+

「结构」分页签:列 / 索引 / 外键 / 触发器 / DDL。MySQL 族、PostgreSQL 族、SQLite、SQL Server、Oracle 都拉元数据;DDL 可复制或插入编辑器。

+

单元格操作

+
    +
  • 双击单元格:进入编辑(有主键时写回);长文本可展开;
  • +
  • 列头点击排序(仅当前页)。
  • +
+

截断提示

+

为保护界面与内存,超大结果集会按阈值截断展示:

+
    +
  • 结果面板顶部显示「已截断」提示与实际行数;
  • +
  • 需要完整数据时,缩小查询范围(加 LIMIT / WHERE)或使用导出。
  • +
+
+

提示:默认「点表名看前 100 行」就是截断策略的一部分 —— 快速浏览用 100 行,精确取数写 WHERE。

+
+

与 AI 面板联动

+

写不出来的查询可以直接在 AI 面板用自然语言描述(「查最近 7 天下单但未支付的用户」),生成 SQL 后放回编辑器执行,见《AI 助手》。

+ +
+ + + + +
+ + +
+ + + + diff --git a/homepage/dist/docs/search-data.json b/homepage/dist/docs/search-data.json new file mode 100644 index 0000000..644a7fa --- /dev/null +++ b/homepage/dist/docs/search-data.json @@ -0,0 +1 @@ +[{"Slug":"intro","Title":"产品介绍","Group":"开始使用","Text":"OpsxDB 是一款 本地优先 的桌面数据库工作台,面向运维与开发:连库、写 SQL、看结果,全在本机完成。 主交付形态是可安装的桌面应用(Tauri 2),本地 Go 后端随应用自动启动;同一套界面也可用单个二进制在 Web / 内网部署。数据全部保存在本机,不经过任何第三方服务器。 功能总览 能力 说明 18 种数据库 关系型 / NoSQL / 时序·搜索 / 国产库,全部端到端验收;常用引擎原生内置 连接选择器 搜索 / 分类 / 最近 / 图标网格;粘贴连接 URL 一键填入表单;连接颜色标记区分环境 SQL 工作台 CodeMirror 编辑器、⌘/Ctrl+Enter 执行语句或选区、多 Tab、可拖分栏、格式化、执行历史 对象树 懒加载库 / 表 / 列 / 索引 / 触发器;点表名直接看前 100 行;右键管理对象 结果处理 单元格编辑回写 / 右键复制(值·行·JSON·INSERT)/ CSV·JSON·INSERT 导出 / 过滤构建器 / 分页 Redis 工作台 单机 / Sentinel / Cluster;键树浏览(SCAN 游标)、TTL、Hash/JSON 编辑、危险命令拦截 安全通道 每连接独立配置 SSL/TLS 与 SSH 隧道;后端本机监听 + 访问令牌 AI 助手 生成 / 解释 / 优化 / 修复 / 方言转换 / 样例;OpenAI 兼容协议 + SSE 流式输出 危险操作防护 DROP / TRUNCATE / 无 WHERE 的 UPDATE·DELETE 执行前确认 桌面唯一形态 桌面 GUI(Tauri 2),本地后端随应用自动拉起 支持的数据库 家族 覆盖 关系型 MySQL · MariaDB · TiDB · PostgreSQL · SQL Server · Oracle · SQLite NoSQL Redis · MongoDB 时序 / 搜索 Elasticsearch · ZooKeeper · InfluxDB 国产库 达梦 DM · OceanBase · GaussDB / openGauss · PolarDB · TDSQL · Kingbase 逐引擎的接入方式、默认端口与能力边界见《 》;全部 18 引擎均已实测验收。 为什么选 OpsxDB 数据主权 :连接配置与查询历史只存在本机;后端默认仅监听 127.0.0.1。 开箱即用 :桌面版双击即用,本地后端随应用自动拉起;官网与文档也由它内置提供。 为快设计 :点表即看数据、⌘Enter 即执行、结果三键取走(复制 / CSV / INSERT)。 轻量克制 :一个 Go 二进制 + 一份前端,内网可部署,无遥测无账号。 提示 :想马上动手?直接看下一章《快速开始》,30 秒连上第一个库。"},{"Slug":"quickstart","Title":"快速开始","Group":"开始使用","Text":"本章从零到出结果:起服务 → 建连接 → 执行第一条 SQL。 1. 启动 桌面版(主交付形态)双击 OpsxDB 应用即可,本地后端随应用自动拉起。 从源码运行(开发): 注意 :客户端只在桌面 App 里运行。 起的 是桌面 devUrl 的资产服务,不是浏览器客户端;浏览器只用于官网 与文档 (后端 直接提供)。 2. 新建连接 1. 打开应用,进入 连接选择器 ,选择数据库类型(如 MySQL); 2. 或者直接粘贴连接 URL,点「填入」自动拆解字段: 3. 点 测试 验证连通性,再点 保存并连接 。 连接配置保存在本机,密码混淆存储;后续查询只携带会话 ID,不再上送账密。 3. 第一次查询 1. 左侧对象树展开库, 点表名 直接查看前 100 行(展开表可看列结构); 2. 打开 SQL 编辑器,输入: 3. 按 ⌘/Ctrl + Enter 执行当前语句(或选中的片段); 4. 结果面板支持 复制 / 导出 CSV / 生成 INSERT ,双击单元格即复制。 4. 验证服务 5. 手边没有数据库? 本地还没有可连的库?用仓库自带的辅助脚本一键起一个(需要 Docker,一次只起一个): 各驱动的验收状态见《驱动支持》。"},{"Slug":"interface","Title":"界面导览","Group":"开始使用","Text":"OpsxDB 的界面为「高频操作」设计:从打开应用到看到数据,路径越短越好。 连接选择器 启动后的第一个界面: 搜索 :按名称快速过滤已保存的连接; 分类 :关系型 / NoSQL / 国产库 / 时序·搜索 分组浏览; 最近 :最近使用的连接排在最前; 图标网格 :按数据库类型直选,未就绪的类型会标注「未就绪」(仅可保存配置); URL 填入 :粘贴 点「填入」,字段自动拆解。 工作台布局 连接成功后进入工作台,三栏结构: 区域 内容 左侧 连接列表 + 对象树(库 → 表 → 列,懒加载) 中部 SQL 编辑器(多 Tab)+ 结果面板,可拖动分栏 右侧 AI 面板(生成 / 解释 / 优化 / 修复 / 方言 / 样例) 对象树 点 表名 :直接打开前 100 行数据; 展开 表 :查看列结构; 右键表 :打开表 / 查看 DDL / 生成 SQL(SELECT·INSERT·UPDATE·DELETE)/ 重命名 / 克隆表结构·克隆表(含数据)/ 清空 / 截断 / 删除 —— 危险项红色并二次确认; 右键库 :新建查询 / 新建表(生成 CREATE TABLE 模板到编辑器)/ 复制 / 设为默认库 / 刷新 / 删除库; Redis:按键分隔符编文件夹,点键打开类型化详情(TTL / JSON / 增删字段); 库列表懒加载,大实例也不卡。 编辑器与结果 CodeMirror 语法高亮,⌘/Ctrl+Enter 执行 当前语句或选区 (不是整页脚本); 多 Tab 并行查询,互不阻塞; 结果面板:复制 / CSV / INSERT 三种取数方式,双击单元格复制; 超过截断阈值时结果有明确提示。 个性化 深色 / 浅色主题切换; Tab 布局与主题选择持久化,下次打开保持原样; 查询历史本地留存,可回跳重跑。"},{"Slug":"connect","Title":"新建连接","Group":"连接与驱动","Text":"本章说明各数据库类型的连接表单、URL 格式与高级选项(SSL / SSH 隧道)。 通用流程 1. 连接选择器点「新建」或选某个数据库类型; 2. 填写表单(不同驱动表单不同,见下表); 3. 测试 → 通过后 保存并连接 。 支持直接粘贴 URL 自动填表: 各驱动表单 驱动 表单 特有字段 MySQL / PostgreSQL / SQL Server standard host · port · user · password · database · ssl · ssh Oracle oracle host · port · user · password · service (如 ORCL) SQLite file database 填本地文件路径(如 ) Redis redis host · port · password · database 序号 · 模式 (单机 / 哨兵 / 集群)· 键分隔符 表单只收集服务端实际消费的字段;历史遗留的死参数不会出现在表单里。 MySQL 族与 PostgreSQL 族 协议兼容的国产库无需单独驱动,直接复用家族驱动: MySQL 族 :MariaDB(3307)、TiDB(4000)、OceanBase(2881)、PolarDB / TDSQL(3306)—— 表单里选对应类型即可; PostgreSQL 族 :GaussDB / openGauss、人大金仓 Kingbase(54321)—— 走 postgres 表单,注意默认库与用户名差异。 SSL / TLS 连接表单中开启 ssl 即可;按连接独立配置,互不影响。内网自签证书场景按需放宽校验策略。 SSH 隧道 数据库在跳板机后面时,开启 ssh 字段组,填写跳板机地址与凭据:OpsxDB 会先建 SSH 隧道,再把数据库连接走隧道转发,无需把库端口暴露到公网。 Redis 哨兵与集群 哨兵 :模式选 Sentinel,填写 Sentinel 节点列表( ,多行)和主节点名 ; 集群 :模式选 Cluster,填写至少一个种子节点。对象树只显示 DB 0(Cluster 无 ); 单机模式只填 host/port,与原先一致。 字段细节与键浏览见 。 提示 :连接保存后,后续查询仅携带 ,账密不会随每次请求上送;密码在本机混淆存储。"},{"Slug":"drivers","Title":"驱动支持","Group":"连接与驱动","Text":"OpsxDB 当前支持 18 种数据库,覆盖关系型、NoSQL、时序/搜索与国产库,全部经真实实例端到端验收(ready + verified)。常用引擎以原生 Go 驱动编译内置,开箱即用;JVM 系数据库通过 Agent 桥按需接入。 完整支持矩阵 数据库 类型 接入方式 默认端口 状态 MySQL 关系型 原生内置 3306 ✅ 已验收 MariaDB 关系型 原生内置 3307 ✅ 已验收 TiDB 关系型 原生内置 4000 ✅ 已验收 PostgreSQL 关系型 原生内置 5432 ✅ 已验收 SQL Server 关系型 原生内置 1433 ✅ 已验收 Oracle 关系型 原生内置(go ora,不引入 JVM) 1521 ✅ 已验收 SQLite 关系型 原生内置(本地文件) — ✅ 已验收 MongoDB NoSQL Agent 桥(官方驱动) 27017 ✅ 已验收 Redis NoSQL 原生内置 6379 ✅ 已验收 Elasticsearch 时序/搜索 原生内置(SQL API) 9200 ✅ 已验收 ZooKeeper 时序/搜索 Agent 桥 2181 ✅ 已验收 InfluxDB 时序/搜索 原生内置(Flux) 8086 ✅ 已验收 达梦 DM 国产库 Agent 桥(JDBC) 5236 ✅ 已验收 OceanBase 国产库 原生内置(MySQL 协议族) 2881 ✅ 已验收 GaussDB / openGauss 国产库 原生内置(PG 协议族) 5432 ✅ 已验收 PolarDB 国产库 原生内置(MySQL 协议族) 3306 ✅ 已验收 TDSQL 国产库 原生内置(MySQL 协议族) 3306 ✅ 已验收 Kingbase 国产库 原生内置(PG 协议族) 54321 ✅ 已验收 协议族复用 MySQL 族(MySQL / MariaDB / TiDB / OceanBase / PolarDB / TDSQL)共用同一原生驱动,PostgreSQL 族(PostgreSQL / GaussDB / openGauss / Kingbase)同理 —— 同族引擎的连接体验与能力完全一致,仅默认端口不同。 Agent 桥驱动(按需下载) MongoDB、ZooKeeper、达梦通过 JVM Agent 桥接入: 首次使用时在 驱动管理器 按需下载对应组件,版本固定并做 sha256 校验(Gitee 主源 + GitHub 备源); 商业数据库(如达梦官方 JDBC)不代下,需自备 jar 放入驱动目录; Agent 进程随会话池化管理,崩溃自动摘除重建,应用退出级联清理。 各引擎能力边界 引擎 浏览 执行 写入 说明 关系型全家 库/表/视图/存储过程/索引/外键/触发器 SQL ✅(含结果集编辑回写) MySQL 族附执行计划 Redis 键树(SCAN 游标)/ TTL 命令编辑器 ✅ 单机 / Sentinel / Cluster 三模式;危险命令族拦截 MongoDB 库/集合 DSL ✅(增删改单文档) 官方驱动经 Agent 桥 ZooKeeper 路径树 GET / SET ✅(写动词二次确认) 经 Agent 桥 Elasticsearch 索引浏览 SQL API 只读 官方 JDBC 付费,故走原生 SQL API InfluxDB org/bucket 浏览 Flux 脚本 只读 用户=org、密码=token 说明(Oracle) :go ora 纯 Go 驱动,无需安装 Java;Apple Silicon 容器环境起 Oracle XE 会遇到 ORA 00442 属环境限制,x86 或真实实例不受影响。"},{"Slug":"workbench","Title":"SQL 工作台","Group":"SQL 工作台","Text":"SQL 工作台是日常使用率最高的界面,所有交互围绕「快」设计。 执行模型 ⌘/Ctrl + Enter :执行光标所在的 当前语句 ;有选区时执行 选区 ; 不是「整页脚本」模式 —— 多条语句互不干扰,想跑哪句把光标放哪; Redis 连接共用同一编辑器,按 行 执行命令(见 ),不另开 CLI; 执行在会话上运行,连接断开后自动提示。 多 Tab 与分栏 每个查询一个 Tab,并行执行互不阻塞; 编辑器 / 结果区可拖动分栏,长查询时编辑器不被结果挤占; Tab 与布局持久化,重开应用保持原样。 对象树联动 左侧对象树懒加载库 / 表 / 列; 点表名 = 打开表工作台 (前 100 行 + 条件过滤 + 结构分页),并回填 SELECT; 展开表看列名与类型,写 SQL 时可对照。 查询历史 本地留存最近 200 条(不上传、不同步); 相同语句自动去重置顶 —— 历史即「最近用过的不同语句」,高频查询永远在第一条; 点击条目回填编辑器;悬停出现 ▶ 按钮,回填并直接重跑; 顶部过滤框支持按语句内容或连接名搜索; 条目显示时间、连接名、行数与耗时;失败的语句红色标出。 危险 SQL 防护 执行以下语句前会弹确认框: 类型 规则 删除对象 DROP / TRUNCATE 全表更新 无 WHERE 的 UPDATE / DELETE 注意 :确认框只拦「明确危险」的模式,不替代事务与备份习惯;生产库操作请配合审批流程。 快捷键 快捷键 动作 ⌘/Ctrl + Enter 执行当前语句 / 选区 双击结果单元格 复制单元格内容 Esc 关闭弹层 / 取消确认"},{"Slug":"results","Title":"结果与导出","Group":"SQL 工作台","Text":"查询跑完只是开始,把结果带走才算完成 —— OpsxDB 给了三条最快路径。 三种取数方式 方式 用途 复制 直接进剪贴板,贴到群聊 / 文档 / 表格 CSV 导出标准 CSV 文件,Excel / Numbers 直接打开 INSERT 把结果行生成为 INSERT 语句,直接可在别的库回放 表数据工作台(关系库) 从对象树打开表后,结果区按 DBeaver / DBX 的数据编辑器组织,而不是只有一张裸网格: 工具栏 :刷新、增行、删行、提交(有主键才写回); 条件过滤 :列 + 运算符(= ≠ \u003c 包含 空…)+ 值,可加多条 AND;应用后重查,SQL 回填编辑器; 本页搜索 :不打库,只过滤当前结果; 列头 :列名 + 类型色 + 主键标记,悬停看注释。 表结构 「结构」分页签:列 / 索引 / 外键 / 触发器 / DDL。MySQL 族、PostgreSQL 族、SQLite、SQL Server、Oracle 都拉元数据;DDL 可复制或插入编辑器。 单元格操作 双击单元格 :进入编辑(有主键时写回);长文本可展开; 列头点击排序(仅当前页)。 截断提示 为保护界面与内存,超大结果集会按阈值截断展示: 结果面板顶部显示「已截断」提示与实际行数; 需要完整数据时,缩小查询范围(加 LIMIT / WHERE)或使用导出。 提示 :默认「点表名看前 100 行」就是截断策略的一部分 —— 快速浏览用 100 行,精确取数写 WHERE。 与 AI 面板联动 写不出来的查询可以直接在 AI 面板用自然语言描述(「查最近 7 天下单但未支付的用户」),生成 SQL 后放回编辑器执行,见《AI 助手》。"},{"Slug":"redis","Title":"Redis 工作台","Group":"SQL 工作台","Text":"Redis 连接使用专用表单(redis)。连上后,对象树是键空间浏览器,编辑器是 Redis 命令行 —— 和 SQL 共用同一套输入框 ,不另开 CLI 页。 为什么命令行不单独做一套 SQL 工作台已经有:多 Tab、⌘/Ctrl+Enter、查询历史、书签、危险确认、取消。Redis 命令同样是「输入 → 执行 → 结果表」。 拆成独立 CLI(终端 REPL)会让快捷键、历史、危险确认分叉,也和 Navicat 式多引擎工作台不一致。 因此: SQL Redis 输入框 同一 CodeMirror 同一 CodeMirror(占位/补全换成命令) 切分 分号语句 按行 ( 不会被分号拆开) 执行 ⌘/Ctrl+Enter 当前语句或选区 ⌘/Ctrl+Enter 当前行或选区 结果 结果表 命令结果表;从对象树打开键则进入键详情 Another Redis Desktop Manager 的独立 CLI Tab、opsxsql 的单行命令 + 输出日志,列为后续 P1,不是现在的主路径。 键空间浏览 对象树对 Redis 显示 DB0–15(Cluster 仅 0)。展开库后: SCAN 过滤 :输入 点「应用」;生产大库请带前缀,避免扫全库。最多展示 500 个键,超出提示截断。 按分隔符编文件夹 :连接表单的「键分隔符」默认 , 显示为 。文件夹显示数量;右键可「只看此前缀」「在此新建键」。 类型色点 :string 绿 / hash 蓝 / list 橙 / set 紫 / zset 青。 点键 :打开键详情(不是假 SELECT)。 键详情 对标 Another Redis Desktop Manager 的 Hash/List/Set 视图: 类型徽章、键名(回车重命名)、TTL(回车或「保存 TTL」, 永久)、刷新、导出还原命令、删除; 结构 表:Hash 为 ID / Field / Value,JSON 值自动美化;可新增字段、编辑、删除; JSON 视图:整体格式化; 表内关键字过滤。 String 可直接改值保存。 命令执行 编辑器直接写 Redis 命令: 未点名的命令走通用 ( / / / 等不必再加白名单); / / / 仍要二段确认; 在大库上会阻塞 —— 请用 。 切换逻辑库(SELECT) 是 Redis 官方的切库命令,编辑器直接支持 —— 语义与 redis cli 一致: 切换后本 Tab 的后续命令都在目标库执行 : 没有也没有 (那是 SQL 语法)—— 输入 会得到 Redis 原生报错 ,与 redis cli 行为一致; 切库只影响当前查询 Tab(多 Tab 可各连各的库),左侧对象树点开对应库可浏览键; Cluster 模式只有 DB 0, 无效。 连接参数 字段 说明 host / port 单机默认 127.0.0.1:6379 password / user ACL / requirepass database 逻辑库序号(0–15 常见;Cluster 忽略) 键分隔符 对象树文件夹分隔,默认 ssl TLS redisMode (默认)/ / redisNodes Sentinel / Cluster 节点列表, 多行或逗号分隔 masterName Sentinel 主节点名(必填) sentinelPassword Sentinel 密码(可空) Sentinel 模式选「哨兵」,填写至少一个 Sentinel 地址和 (如 )。逻辑库序号仍可用。 Cluster 模式选「集群」,填写至少一个种子节点。Cluster 不支持 多库,对象树只暴露 DB 0。槽位路由由客户端处理,键浏览走 。 环境 :Sentinel / Cluster 表单与后端已接好;真实拓扑联调见 环境缺口。"},{"Slug":"security","Title":"安全设计","Group":"安全与 AI","Text":"连生产库的工具,安全必须是默认项。OpsxDB 的安全设计围绕一句话: 数据不出你的机器。 本地优先 连接配置、查询历史、主题偏好全部保存在本机; 无账号体系、无遥测、无云端同步; 后端默认只监听 ,对外服务需要显式配置( 或 )。 凭据保护 层面 机制 存储 连接密码在本机混淆存储,不落明文 传输 连接建立后,后续查询只携带 ,账密不再每次上送 会话 会话在服务端维护,可主动关闭(连接断开即失效) 加密通道 SSL / TLS :每个连接可独立开启;数据库支持 TLS 即可启用(MySQL、PostgreSQL、SQL Server、Redis、MongoDB 均支持)。 SSH 隧道 :数据库在跳板机后时,配置 SSH 字段组,OpsxDB 先建隧道再转发数据库连接 —— 库端口不必暴露公网。 危险操作防护 DROP / TRUNCATE 执行前确认; 无 WHERE 的 UPDATE / DELETE 执行前确认; 结果集按阈值截断,避免误操作拖垮界面。 内网部署形态 单二进制 + 内置静态页(官网 / 文档 / 工作台),无外部依赖: 任意内网主机可部署; 无外联请求,可在纯内网环境运行; 升级即替换一个二进制。"},{"Slug":"ai","Title":"AI 助手","Group":"安全与 AI","Text":"AI 面板的目标:让「写不出的 SQL」和「看不懂的 SQL」不再阻塞你。 六种动作 动作 用途 生成 自然语言 → SQL(「查最近 7 天下单但未支付的用户」) 解释 把一段复杂 SQL 翻译成中文说明 优化 分析慢查询,给出索引 / 改写建议 修复 报错信息 + SQL → 修正版本 方言 MySQL ↔ PostgreSQL 等跨方言转换 样例 按表结构生成示例查询 使用方式 1. 连接库后打开右侧 AI 面板; 2. 选择动作,输入需求或粘贴 SQL(可附上对象树上下文); 3. 生成结果一键放回编辑器,⌘/Ctrl + Enter 执行。 提示 :生成的 SQL 依旧走危险语句确认流程 —— AI 产出与手写 SQL 同等对待,不放宽防护。 接入真实模型 AI 面板支持任何 OpenAI 兼容协议 的服务(OpenAI / DeepSeek / 通义 / 本地 vLLM 等),回复以 SSE 流式 逐字输出,等待模型时不再面对空白。 配置入口(二选一): 1. AI 面板右上角「 配置 」:填 Base URL、API Key、模型名,保存后可一键测试; 2. 配置文件 (权限 0600),或环境变量 。 说明 :未配置 API Key 时回落本地 stub(离线占位,内容为模板演示);AI Key 保存后服务端只回显掩码( )。 数据流向承诺 默认只发送你明确提交的内容(附当前库表结构上下文,不含连接凭据); 可完全关闭 AI 功能(顶栏隐藏面板即可,无后台请求); 使用云端模型时在界面上明确标识,生成 SQL 依旧走危险语句确认流程。"},{"Slug":"faq","Title":"常见问题","Group":"参考","Text":"产品形态 Q:能在浏览器里操作数据库吗? 不能。OpsxDB 客户端唯一形态是桌面 App(Tauri 2);浏览器只承载官网与文档(由本地后端 内置提供)。开发时的 只是桌面 devUrl 的资产服务,不是网页客户端。 Q:官网和文档部署在哪? 就内置在你运行的那个二进制里: 是官网, 是文档;无需额外部署。 Q:怎么打安装包? 产出 Tauri 安装包(DMG)并内嵌 sidecar 后端二进制。 数据与安全 Q:我的连接密码存在哪? 本机,混淆存储;查询只带会话 ID,密码不会随请求重复上送,也不会同步到云端。 Q:会上传我的 SQL 或查询结果吗? 不会。没有遥测、没有账号、没有云依赖。AI 助手为可选功能:只有你主动配置了模型服务并主动提问时,才会把当次请求(含库表结构上下文,不含连接凭据)发给你指定的服务地址。 Q:能在公司内网用吗? 能。单二进制 + 内置静态页,无外部依赖;默认只监听回环地址,对外需显式配置。 驱动相关 Q:Oracle 能用吗? 驱动代码就绪(go ora 纯 Go 实现,无需 JVM),但本机 docker 验收在 Apple Silicon 上受镜像限制未通过(ORA 00442),需 x86 环境或真库完成验收,详见《驱动支持》。 Q:达梦 / MongoDB 什么时候支持? 已列入路线:长尾库(达梦、MongoDB、ZooKeeper、ES、InfluxDB)规划 agent 按需接入,驱动分发走独立仓库并校验 sha256。 Q:MySQL 族 / PG 族的国产库怎么连? 协议兼容直接复用家族驱动:TiDB / OceanBase / PolarDB / TDSQL 选对应类型(MySQL 协议);GaussDB / Kingbase 走 PostgreSQL 表单。注意各自默认端口与用户名差异。 其他 Q:和 OpsxAPI 是什么关系? 同一团队的姊妹项目:OpsxAPI 是接口工作台,OpsxDB 是数据库工作台,共用一套 monorepo 脚手架(web + Gin + 可选 Tauri),产品面各自独立。 Q:快捷键有哪些? 核心就一个:⌘/Ctrl + Enter 执行当前语句或选区;双击结果单元格复制。完整列表见《SQL 工作台》。"},{"Slug":"shortcuts","Title":"快捷键","Group":"参考","Text":"快捷键是 OpsxDB 的第一等操作方式 —— 高频动作全部可以不碰鼠标完成。 Windows / Linux 上 对应 。 全局与工作台 快捷键 动作 执行当前语句或选区(自动按语句切分) 快速跳转:模糊搜索库 / 表,Enter 直达数据 新建查询 Tab 关闭当前查询(有未保存改动会确认) 切到第 N 个查询 循环切换查询 上一条 / 下一条语句(编辑器内) 聚焦对象树过滤框 刷新对象树 显示 / 隐藏 AI 面板 快捷键帮助 结果网格 快捷键 / 操作 动作 上下移动选中行 翻页移动 跳到首行 / 末行 双击单元格 / 进入单元格编辑 清空选中格(进入编辑) (编辑中) 撤销本格改动,恢复进入编辑前的值 取消编辑 / 关闭弹层与菜单 复制选中单元格值(无列选中时复制整行 TSV) 右键单元格 编辑 / 复制单元格值 / 复制行(TSV · JSON · INSERT)/ 查看全文 多格复制粘贴 与 Excel 互通:复制区域后直接粘贴进网格批量暂存 双击分栏分隔条 结果区最大化 / 还原 对象树 操作 动作 双击表名 打开表工作台(看前 100 行) 右键库 新建查询 / 浏览对象 / 复制 / 设为默认库 / 刷新 / 删除库 右键表 / 视图 查看数据 / 查看 DDL / 复制 / 清空截断 / 删除表 键盘导航(展开 / 收起 / 进入) SQL 编辑器右键 编辑器内右键可完成:执行选中语句、执行当前语句、查看数据、查看 DDL、剪切 / 复制 / 粘贴 / 全选 —— 系统默认菜单被替换,不再跳出「Look Up / 检查元素」。"}] \ No newline at end of file diff --git a/homepage/dist/docs/security/index.html b/homepage/dist/docs/security/index.html new file mode 100644 index 0000000..69785d5 --- /dev/null +++ b/homepage/dist/docs/security/index.html @@ -0,0 +1,179 @@ + + + + + +安全设计 · OpsxDB 文档 + + + + + + +
+
+ + + + OpsxDB 文档 + + v0.1 + + +
+
+ +
+ + +
+ +

安全设计

+
更新于 2026-09-20
+
+

连生产库的工具,安全必须是默认项。OpsxDB 的安全设计围绕一句话:数据不出你的机器。

+

本地优先

+
    +
  • 连接配置、查询历史、主题偏好全部保存在本机;
  • +
  • 无账号体系、无遥测、无云端同步;
  • +
  • 后端默认只监听 127.0.0.1,对外服务需要显式配置(OPSXDB_BIND_PUBLIC=1 或 OPSXDB_ADDR)。
  • +
+

凭据保护

+ + + + + + + + + + + + + + + + + + + + + +
层面机制
存储连接密码在本机混淆存储,不落明文
传输连接建立后,后续查询只携带 sessionId,账密不再每次上送
会话会话在服务端维护,可主动关闭(连接断开即失效)
+

加密通道

+

SSL / TLS:每个连接可独立开启;数据库支持 TLS 即可启用(MySQL、PostgreSQL、SQL Server、Redis、MongoDB 均支持)。

+

SSH 隧道:数据库在跳板机后时,配置 SSH 字段组,OpsxDB 先建隧道再转发数据库连接 —— 库端口不必暴露公网。

+

危险操作防护

+
    +
  • DROP / TRUNCATE 执行前确认;
  • +
  • 无 WHERE 的 UPDATE / DELETE 执行前确认;
  • +
  • 结果集按阈值截断,避免误操作拖垮界面。
  • +
+

内网部署形态

+

单二进制 + 内置静态页(官网 / 文档 / 工作台),无外部依赖:

+
    +
  • 任意内网主机可部署;
  • +
  • 无外联请求,可在纯内网环境运行;
  • +
  • 升级即替换一个二进制。
  • +
+ +
+ + + + +
+ + +
+ + + + diff --git a/homepage/dist/docs/shortcuts/index.html b/homepage/dist/docs/shortcuts/index.html new file mode 100644 index 0000000..552c65b --- /dev/null +++ b/homepage/dist/docs/shortcuts/index.html @@ -0,0 +1,273 @@ + + + + + +快捷键 · OpsxDB 文档 + + + + + + +
+
+ + + + OpsxDB 文档 + + v0.1 + + +
+
+ +
+ + +
+ +

快捷键

+
更新于 2026-09-23
+
+

快捷键是 OpsxDB 的第一等操作方式 —— 高频动作全部可以不碰鼠标完成。

+
+

Windows / Linux 上 ⌘ 对应 Ctrl。

+
+

全局与工作台

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
快捷键动作
⌘ Enter执行当前语句或选区(自动按语句切分)
⌘ P快速跳转:模糊搜索库 / 表,Enter 直达数据
⌘ T新建查询 Tab
⌘ W关闭当前查询(有未保存改动会确认)
⌘ 1–9切到第 N 个查询
Ctrl Tab循环切换查询
Alt ↑ / ↓上一条 / 下一条语句(编辑器内)
⌘ ⇧ F聚焦对象树过滤框
F5刷新对象树
⌘ B显示 / 隐藏 AI 面板
⌘ /快捷键帮助
+

结果网格

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
快捷键 / 操作动作
↑ ↓上下移动选中行
PgUp PgDn翻页移动
Home End跳到首行 / 末行
双击单元格 / Enter进入单元格编辑
Delete Backspace清空选中格(进入编辑)
⌘ Z(编辑中)撤销本格改动,恢复进入编辑前的值
Esc取消编辑 / 关闭弹层与菜单
Ctrl/⌘ + C复制选中单元格值(无列选中时复制整行 TSV)
右键单元格编辑 / 复制单元格值 / 复制行(TSV · JSON · INSERT)/ 查看全文
多格复制粘贴与 Excel 互通:复制区域后直接粘贴进网格批量暂存
双击分栏分隔条结果区最大化 / 还原
+

对象树

+ + + + + + + + + + + + + + + + + + + + + + + + + +
操作动作
双击表名打开表工作台(看前 100 行)
右键库新建查询 / 浏览对象 / 复制 / 设为默认库 / 刷新 / 删除库
右键表 / 视图查看数据 / 查看 DDL / 复制 / 清空截断 / 删除表
↑ ↓ → ← Enter键盘导航(展开 / 收起 / 进入)
+

SQL 编辑器右键

+

编辑器内右键可完成:执行选中语句、执行当前语句、查看数据、查看 DDL、剪切 / 复制 / 粘贴 / 全选 —— 系统默认菜单被替换,不再跳出「Look Up / 检查元素」。

+ +
+ + + + +
+ + +
+ + + + diff --git a/homepage/dist/docs/workbench/index.html b/homepage/dist/docs/workbench/index.html new file mode 100644 index 0000000..dc19af1 --- /dev/null +++ b/homepage/dist/docs/workbench/index.html @@ -0,0 +1,208 @@ + + + + + +SQL 工作台 · OpsxDB 文档 + + + + + + +
+
+ + + + OpsxDB 文档 + + v0.1 + + +
+
+ +
+ + +
+ +

SQL 工作台

+
更新于 2026-09-20
+
+

SQL 工作台是日常使用率最高的界面,所有交互围绕「快」设计。

+

执行模型

+
    +
  • ⌘/Ctrl + Enter:执行光标所在的当前语句;有选区时执行选区;
  • +
  • 不是「整页脚本」模式 —— 多条语句互不干扰,想跑哪句把光标放哪;
  • +
  • Redis 连接共用同一编辑器,按行执行命令(见 Redis 工作台),不另开 CLI;
  • +
  • 执行在会话上运行,连接断开后自动提示。
  • +
+

多 Tab 与分栏

+
    +
  • 每个查询一个 Tab,并行执行互不阻塞;
  • +
  • 编辑器 / 结果区可拖动分栏,长查询时编辑器不被结果挤占;
  • +
  • Tab 与布局持久化,重开应用保持原样。
  • +
+

对象树联动

+
    +
  • 左侧对象树懒加载库 / 表 / 列;
  • +
  • 点表名 = 打开表工作台(前 100 行 + 条件过滤 + 结构分页),并回填 SELECT;
  • +
  • 展开表看列名与类型,写 SQL 时可对照。
  • +
+

查询历史

+
    +
  • 本地留存最近 200 条(不上传、不同步);
  • +
  • 相同语句自动去重置顶 —— 历史即「最近用过的不同语句」,高频查询永远在第一条;
  • +
  • 点击条目回填编辑器;悬停出现 ▶ 按钮,回填并直接重跑;
  • +
  • 顶部过滤框支持按语句内容或连接名搜索;
  • +
  • 条目显示时间、连接名、行数与耗时;失败的语句红色标出。
  • +
+

危险 SQL 防护

+

执行以下语句前会弹确认框:

+ + + + + + + + + + + + + + + + + +
类型规则
删除对象DROP / TRUNCATE
全表更新无 WHERE 的 UPDATE / DELETE
+
+

注意:确认框只拦「明确危险」的模式,不替代事务与备份习惯;生产库操作请配合审批流程。

+
+

快捷键

+ + + + + + + + + + + + + + + + + + + + + +
快捷键动作
⌘/Ctrl + Enter执行当前语句 / 选区
双击结果单元格复制单元格内容
Esc关闭弹层 / 取消确认
+ +
+ + + + +
+ + +
+ + + + diff --git a/homepage/dist/index.html b/homepage/dist/index.html new file mode 100644 index 0000000..1619095 --- /dev/null +++ b/homepage/dist/index.html @@ -0,0 +1,300 @@ + + + + + +OpsxDB — 本地优先的桌面数据库工作台 + + + + + + + + + + + +
+
+
+
v0.1 · 桌面 GUI · 数据 100% 本机
+

一个窗口,
管好全公司的数据库

+

+ 连库、写 SQL、看结果,全在本机完成。
+ MySQL / PostgreSQL / SQL Server / Oracle / SQLite / Redis 内置驱动,TiDB · OceanBase · GaussDB · 人大金仓同协议直连, + SSH 隧道与 SSL 加密直达内网库,AI 帮你把 SQL 写得又快又稳。 +

+ +
+ 本地优先SSH 隧道SSL 加密国产库兼容AI / MCP +
+
+ + + +
+ + +
+
+
7内置驱动
+
18可连数据库
+
0数据外发
+
1个二进制内置官网与文档
+
+
+
+ + +
+
+

为什么运维和开发选 OpsxDB

+

不把生产库连到别人的云上 —— 这是我们做这款工具的出发点。

+
+
+
+

本地优先,数据主权

+

连接配置、查询历史全部保存在本机,服务只监听 127.0.0.1,不经过任何第三方服务器。

+
+
+
+

六类库一个窗口

+

MySQL 族 / PostgreSQL 族 / SQL Server / Oracle / SQLite / Redis 统一工作台,切换零负担。

+
+
+
+

安全通道直达内网

+

每个连接可独立配置 SSL/TLS 与 SSH 隧道,跳板机后面的库也能安全直连。

+
+
+
+

AI 写 SQL,也能查库

+

Ask 生成/解释/优化;Agent 用与 MCP 同源的只读工具真查库。Cursor 可 npx @rlwj-lab/opsxdb-mcp 接入。

+
+
+
+
+ + +
+
+

开箱即用的专业能力

+

为「每天都要碰库的人」设计的工作台密度。

+
+

连接选择器

搜索 / 分类 / 最近 / 图标网格;粘贴 mysql://user:pass@host:3306/db 一键填入表单。

+

SQL 工作台

CodeMirror 编辑器,⌘/Ctrl+Enter 执行当前语句或选区,多 Tab 并行,可拖分栏。

+

结果随手取

结果集一键复制 / 导出 CSV / 生成 INSERT;双击单元格即复制,截断行数有提示。

+

对象树与表数据

懒加载库 / 表 / 列;点表名直接看前 100 行,展开表即看列结构。

+

Redis 工作台

编辑器直接执行 PING / GET / SET / KEYS,键空间浏览、TTL 管理。

+

AI / MCP

Ask 写 SQL;Agent 真查白名单库。可用 npx @rlwj-lab/opsxdb-mcp 接到 Cursor(默认只读)。

+
+
+
+ + +
+
+

数据库支持

+

常用库 native Go 驱动编译内置;长尾库规划 agent 按需接入。

+
+

MySQL 族

MySQL · MariaDB · TiDB · OceanBase · PolarDB · TDSQL:3306

+

PostgreSQL 族

PostgreSQL · GaussDB / openGauss · 人大金仓:5432

+

SQL Server

原生协议直连,SSL 可选:1433

+

Oracle

纯 Go 驱动 go-ora,不引入 JVM:1521

+

SQLite

本地文件库,填路径即连file

+

Redis

连接即可执行命令与键管理:6379

+
+
+ 规划中 · agent 按需接入:达梦 DM8 · MongoDB · ZooKeeper · Elasticsearch · InfluxDB +
+

驱动验收状态(本机 docker 实测)见 文档 · 驱动支持。

+
+
+ + +
+
+

安全是默认项,不是选项

+

连生产库的工具,必须先过安全这一关。

+
+

密码不出本机

连接密码本机混淆存储;查询只带 sessionId,账密不再每次上送。

+

SSL / TLS 每库可配

按连接独立开启 TLS,证书校验策略随库配置。

+

SSH 隧道

跳板机场景一条隧道直达内网库,无需暴露公网端口。

+

仅监听回环

后端默认绑定 127.0.0.1,对外服务需显式开启。

+

危险 SQL 确认

DROP / TRUNCATE / 无 WHERE 的 UPDATE·DELETE 执行前二次确认。

+

查询历史本地留存

历史只存在本机,随时回跳重跑,不上传不同步。

+
+
+
+ + +
+
+

三种形态,同一套体验

+

客户端唯一形态是桌面 GUI;官网与文档内置在同一个 Go 二进制里。

+
+ +
+
官网 + 文档
+
内置
+
随二进制提供,无需部署
+
    +
  • ✓ 官网 / 与文档 /docs 内置于后端
  • +
  • ✓ 文档支持全文搜索 / 打印 / 导出 PDF
  • +
  • ✓ 浏览器只看站点与文档,不承载客户端
  • +
  • ✓ 随版本发布自动更新
  • +
+ 浏览文档 +
+
+
内网部署
+
企业内网版
+
无外联
+
数据不出企业网
+
    +
  • ✓ 单二进制 + 静态页,内网任意主机部署
  • +
  • ✓ 默认仅回环监听,对外需显式配置
  • +
  • ✓ SSH 隧道 / TLS 直达内网数据库
  • +
  • ✓ 无遥测、无账号、无云依赖
  • +
+ 安全设计 +
+
+
+
+ + +
+
+

常见问题

+
+
我的连接密码保存在哪?安全吗?

全部保存在本机(混淆存储),查询时只携带会话 ID,密码不会随每次请求上送,也不会同步到任何云端。

+
能在浏览器里操作数据库吗?

不能。客户端唯一形态是桌面应用(Tauri 2);浏览器只承载官网与文档,由后端 :8788 内置提供。开发时的 :5174 只是桌面 devUrl 的资产服务。

+
和 DBeaver / Navicat 有什么差别?

OpsxDB 面向运维与开发的日常高频操作(连库、点表、写 SQL、取结果),界面密度和快捷键为「快」设计;本地优先、后端随桌面应用拉起、内置中文文档。重度管理功能(ER 图、数据比对等)在路线图中。

+
Oracle 支持好了吗?

驱动代码已就绪(纯 Go 的 go-ora,无需 JVM),但本机 docker 验收在 Apple Silicon 上受镜像限制未通过,需 x86 环境或真库完成验收,详见文档《驱动支持》。

+
AI 功能需要联网吗?

配置云端模型(如 DeepSeek)时,提问与结构上下文会发往该服务;可改用本地兼容端点。MCP / Agent 查库始终在本机执行,默认只读。

+
支持达梦 / MongoDB 吗?

已列入路线:常用库 native 内置,长尾库(达梦、MongoDB、ZooKeeper、ES、InfluxDB)规划 agent 按需接入,驱动分发走独立仓库并校验 sha256。

+
+
+
+ + +
+
+

把数据库客户端收回自己手里

+

30 秒连上第一个库;官网与文档都由你手里的这个二进制提供。

+ +
+
+ + + + + + diff --git a/homepage/dist/site/assets/site.css b/homepage/dist/site/assets/site.css new file mode 100644 index 0000000..866fa09 --- /dev/null +++ b/homepage/dist/site/assets/site.css @@ -0,0 +1,268 @@ +/* OpsxDB 官网 —— 营销单页样式(祖母绿 → 青家族色) */ +:root { + --green: #059669; + --green-dark: #047857; + --green-soft: rgba(5, 150, 105, 0.08); + --cyan: #06b6d4; + --bg: #ffffff; + --bg-alt: #f5faf8; + --border: #e2ebe7; + --text: #101828; + --text-2: #52606d; + --text-3: #98a2b3; + --red: #dc2626; + --amber: #d97706; + --radius: 14px; + --shadow: 0 1px 3px rgba(6, 23, 18, .06), 0 12px 32px rgba(6, 23, 18, .08); + --mono: "JetBrains Mono", SFMono-Regular, Menlo, monospace; +} +* { box-sizing: border-box; scroll-behavior: smooth; } +body { + margin: 0; font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", "Segoe UI", sans-serif; + color: var(--text); background: var(--bg); font-size: 15px; line-height: 1.75; +} +a { color: var(--green-dark); text-decoration: none; } +h1,h2,h3 { letter-spacing: -0.015em; } +section[id] { scroll-margin-top: 76px; } +.wrap { max-width: 1120px; margin: 0 auto; padding: 0 24px; } +.wrap.narrow { max-width: 820px; } +/* ---------- SVG 图标 ---------- */ +.i { width: 15px; height: 15px; stroke: currentColor; fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; vertical-align: -2px; } +.i-lg { width: 28px; height: 28px; vertical-align: middle; } +code { font-family: var(--mono); font-size: 13px; background: var(--green-soft); color: var(--green-dark); border-radius: 5px; padding: 1px 6px; } + +/* ---------- 按钮 ---------- */ +.btn { + display: inline-flex; align-items: center; justify-content: center; gap: 6px; + border-radius: 10px; padding: 9px 20px; font-size: 14.5px; font-weight: 600; cursor: pointer; + transition: all .18s; border: 1px solid transparent; white-space: nowrap; +} +.btn-lg { padding: 12px 26px; font-size: 15.5px; } +.btn-primary { background: var(--green); color: #fff !important; box-shadow: 0 6px 18px rgba(5,150,105,.30); } +.btn-primary:hover { background: var(--green-dark); transform: translateY(-1px); } +.btn-ghost { border-color: var(--border); color: var(--text) !important; background: #fff; } +.btn-ghost:hover { border-color: var(--green); color: var(--green-dark) !important; } +.btn-inverse { background: #fff; color: var(--green-dark) !important; } +.btn-inverse:hover { transform: translateY(-1px); } +.btn-outline { border-color: rgba(255,255,255,.5); color: #fff !important; } +.btn-outline:hover { border-color: #fff; background: rgba(255,255,255,.1); } + +/* ---------- 导航 ---------- */ +.nav { + position: sticky; top: 0; z-index: 50; background: rgba(255,255,255,.9); + backdrop-filter: blur(10px); border-bottom: 1px solid var(--border); +} +.nav-inner { max-width: 1120px; margin: 0 auto; padding: 0 24px; height: 60px; display: flex; align-items: center; gap: 28px; } +.brand { display: flex; align-items: center; gap: 9px; } +.brand-logo { display: inline-flex; } +.brand-logo svg { display: block; border-radius: 8px; } +.brand-name { font-size: 17px; font-weight: 800; color: var(--text) !important; } +.nav-links { display: flex; gap: 22px; } +.nav-links a { font-size: 14px; font-weight: 500; color: var(--text-2) !important; } +.nav-links a:hover { color: var(--green-dark) !important; } +.nav-cta { margin-left: auto; } + +/* ---------- Hero ---------- */ +.hero { + position: relative; overflow: hidden; + background: + radial-gradient(1200px 500px at 85% -10%, rgba(5,150,105,.13), transparent 60%), + radial-gradient(800px 400px at -10% 10%, rgba(6,182,212,.09), transparent 55%), + linear-gradient(180deg, #f5fbf8 0%, #fff 100%); + border-bottom: 1px solid var(--border); +} +.hero-inner { + max-width: 1120px; margin: 0 auto; padding: 72px 24px 56px; + display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); gap: 48px; align-items: center; +} +.hero-badge { + display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; font-weight: 600; color: var(--green-dark); + background: #fff; border: 1px solid rgba(5,150,105,.25); border-radius: 999px; padding: 4px 14px; + box-shadow: 0 2px 8px rgba(5,150,105,.1); margin-bottom: 18px; +} +.hero h1 { font-size: 44px; line-height: 1.22; font-weight: 800; margin: 0 0 16px; } +.hero h1 em { font-style: normal; color: var(--green); } +.hero-sub { color: var(--text-2); font-size: 16px; margin: 0 0 26px; } +.hero-actions { display: flex; gap: 14px; flex-wrap: wrap; } +.hero-actions.center { justify-content: center; } +.hero-pills { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 22px; } +.hero-pills span { + font-size: 12px; color: var(--text-2); background: #fff; border: 1px solid var(--border); + padding: 3px 12px; border-radius: 999px; +} + +/* ---------- 工作台 Mock(纯 CSS) ---------- */ +.mock { + border-radius: 14px; overflow: hidden; box-shadow: var(--shadow); border: 1px solid #1b2b26; + background: #0c1512; transform: perspective(1400px) rotateY(-4deg) rotateX(1.5deg); +} +.mock-titlebar { + display: flex; align-items: center; gap: 7px; height: 34px; padding: 0 12px; + background: #0f1a16; border-bottom: 1px solid #1b2b26; +} +.mock-titlebar i { width: 11px; height: 11px; border-radius: 50%; background: #37504a; } +.mock-titlebar i:nth-child(1) { background: #f87171; } .mock-titlebar i:nth-child(2) { background: #fbbf24; } .mock-titlebar i:nth-child(3) { background: #34d399; } +.mock-titlebar span { margin-left: 8px; color: #8aa39b; font-size: 11px; } +.mock-body { display: grid; grid-template-columns: 158px minmax(0,1fr); min-height: 330px; } +.mock-side { border-right: 1px solid #1b2b26; padding: 10px 8px; background: #0b1310; } +.mock-search { height: 22px; border-radius: 6px; background: #142019; margin-bottom: 10px; } +.mock-group { color: #8aa39b; font-size: 11px; padding: 8px 6px 3px; } +.mock-item { display: flex; align-items: center; gap: 6px; color: #a9c0b8; font-size: 11.5px; padding: 4px 6px; border-radius: 6px; } +.mock-item.active { background: rgba(5,150,105,.18); color: #6ee7b7; } +.mock-item.conn .dot { width: 7px; height: 7px; border-radius: 50%; background: #47564f; flex-shrink: 0; } +.mock-item.conn .dot.on { background: #34d399; } +.mi { width: 11px; height: 11px; stroke: currentColor; fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; flex-shrink: 0; opacity: .8; } +.mock-main { padding: 10px 12px; display: flex; flex-direction: column; gap: 9px; } +.mock-tabs { display: flex; gap: 4px; } +.mock-tabs .tab { color: #5f7a70; font-size: 10.5px; padding: 4px 10px; border-radius: 6px 6px 0 0; } +.mock-tabs .tab.on { color: #6ee7b7; background: rgba(5,150,105,.12); border-bottom: 2px solid var(--green); } +.mock-sql { border: 1px solid #1b2b26; border-radius: 9px; padding: 10px 12px; background: #0b1310; } +.mock-sql pre { + margin: 0; font-family: var(--mono); font-size: 11px; line-height: 1.7; color: #c3d4cd; white-space: pre-wrap; +} +.mock-sql .kw { color: #6ee7b7; } +.mock-sql .str { color: #fcd34d; } +.mock-sql .num { color: #7dd3fc; } +.mock-grid { + display: grid; grid-template-columns: 52px 62px 1fr 68px; gap: 0 10px; + border: 1px solid #1b2b26; border-radius: 9px; padding: 8px 10px; background: #0b1310; + font-family: var(--mono); font-size: 10.5px; line-height: 1.9; color: #b7c8c1; +} +.mock-grid .gh { color: #7fe3c3; border-bottom: 1px solid #1b2b26; margin-bottom: 3px; font-weight: 600; } +.mock-grid .ok { color: #34d399; } +.mock-grid .warn { color: #fbbf24; } +.mock-status { display: flex; justify-content: space-between; color: #5f7a70; font-size: 10px; font-family: var(--mono); padding: 0 2px; } +.mock-status .ok { color: #34d399; } + +/* ---------- 数据统计条 ---------- */ +.stats { border-top: 1px solid var(--border); background: rgba(255,255,255,.7); } +.stats-inner { + max-width: 1120px; margin: 0 auto; padding: 18px 24px; + display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; text-align: center; +} +.stat b { display: block; font-size: 26px; font-weight: 800; color: var(--green-dark); line-height: 1.2; } +.stat span { font-size: 12.5px; color: var(--text-2); } + +/* ---------- 通用 Section ---------- */ +.section { padding: 72px 0; } +.section.alt { background: var(--bg-alt); border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); } +.sec-title { font-size: 30px; font-weight: 800; text-align: center; margin: 0 0 8px; } +.sec-sub { text-align: center; color: var(--text-2); margin: 0 0 40px; } +.grid { display: grid; gap: 18px; } +.g3 { grid-template-columns: repeat(3, minmax(0,1fr)); } +.g4 { grid-template-columns: repeat(4, minmax(0,1fr)); } + +/* ---------- 卡片 ---------- */ +.card { + background: #fff; border: 1px solid var(--border); border-radius: var(--radius); + padding: 22px; box-shadow: 0 1px 2px rgba(6,23,18,.04); transition: all .18s; +} +.card:hover { transform: translateY(-3px); box-shadow: var(--shadow); border-color: rgba(5,150,105,.35); } +.card h3 { font-size: 16px; margin: 0 0 6px; } +.card p { color: var(--text-2); font-size: 13.5px; margin: 0; } +.card-icon { color: var(--green); margin-bottom: 10px; } +.card-icon .i-lg { width: 30px; height: 30px; } +.card.row { display: flex; gap: 14px; align-items: flex-start; } +.card.row .card-icon { margin: 2px 0 0; } + +/* ---------- 驱动矩阵 ---------- */ +.proto { + background: #fff; border: 1px solid var(--border); border-left: 3px solid var(--green); + border-radius: 12px; padding: 18px 20px; +} +.proto h3 { margin: 0 0 6px; font-size: 15.5px; display: flex; align-items: center; gap: 8px; } +.proto h3 .i { color: var(--green); width: 17px; height: 17px; } +.proto p { margin: 0; color: var(--text-2); font-size: 13.5px; } +.proto .port { margin-left: 10px; font-family: var(--mono); font-size: 11.5px; color: var(--green-dark); background: var(--green-soft); border-radius: 5px; padding: 1px 8px; white-space: nowrap; } + +/* ---------- 徽章 / 脚注 ---------- */ +.badges { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; margin-bottom: 18px; } +.badges span { + background: #fff; border: 1px solid var(--border); border-radius: 999px; + padding: 6px 16px; font-size: 13px; font-weight: 500; color: var(--text); +} +.badges span.more { border-style: dashed; color: var(--text-2); } +.footnote { text-align: center; color: var(--text-3); font-size: 12.5px; margin: 10px 0 0; } + +/* ---------- 形态卡(下载) ---------- */ +.pricing.three { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 22px; max-width: 1080px; margin: 0 auto; } +.price-card { + position: relative; background: #fff; border: 1px solid var(--border); border-radius: 16px; + padding: 30px 28px 26px; box-shadow: 0 1px 2px rgba(6,23,18,.04); display: flex; flex-direction: column; +} +.price-card.featured { border: 2px solid var(--green); box-shadow: 0 12px 36px rgba(5,150,105,.16); } +.price-card.enterprise { + background: linear-gradient(160deg, #0f1f1a 0%, #0c1512 70%); + border: 1px solid #22453a; box-shadow: 0 14px 40px rgba(12,21,18,.4); +} +.price-card.enterprise .plan { color: #8aa39b; } +.price-card.enterprise .price b { color: #fff; font-size: 34px; } +.price-card.enterprise .price span { color: #8aa39b; } +.price-card.enterprise .plan-sub { color: #8aa39b; } +.price-card.enterprise li { color: #a9c0b8; border-bottom-color: #1b2b26; } +.btn-dark { background: #fff; color: #0c1512 !important; } +.btn-dark:hover { transform: translateY(-1px); background: #e6f7f0; } +.plan-tag { + position: absolute; top: -13px; left: 50%; transform: translateX(-50%); + background: var(--green); color: #fff; font-size: 12px; font-weight: 700; + padding: 3px 14px; border-radius: 999px; white-space: nowrap; +} +.plan-tag.dark { background: #0c1512; border: 1px solid #22453a; } +.plan { font-size: 16px; font-weight: 700; color: var(--text-2); } +.price { margin: 8px 0 2px; } +.price b { font-size: 40px; font-weight: 800; letter-spacing: -.02em; color: var(--text); } +.price span { color: var(--text-3); font-size: 14px; margin-left: 4px; } +.plan-sub { color: var(--text-3); font-size: 13px; margin-bottom: 18px; } +.price-card ul { list-style: none; padding: 0; margin: 0 0 22px; flex: 1; } +.price-card li { font-size: 13.5px; color: var(--text-2); padding: 6px 0; border-bottom: 1px dashed var(--border); } +.price-card li:last-child { border-bottom: none; } +.price-card li code { font-size: 12px; } +.price-card .btn { width: 100%; } + +/* ---------- FAQ ---------- */ +.faq details { + background: #fff; border: 1px solid var(--border); border-radius: 12px; + padding: 16px 20px; margin-bottom: 12px; +} +.faq summary { font-weight: 600; cursor: pointer; font-size: 15px; list-style: none; display: flex; justify-content: space-between; } +.faq summary::after { content: "+"; color: var(--text-3); font-weight: 400; } +.faq details[open] summary::after { content: "-"; } +.faq details p { margin: 10px 0 0; color: var(--text-2); font-size: 14px; } + +/* ---------- CTA ---------- */ +.cta { + background: linear-gradient(135deg, #047857 0%, #059669 55%, #0d9488 100%); + color: #fff; text-align: center; padding: 72px 24px; +} +.cta h2 { font-size: 32px; font-weight: 800; margin: 0 0 10px; } +.cta p { color: rgba(255,255,255,.85); margin: 0 0 28px; } + +/* ---------- Footer ---------- */ +.footer { background: #0c1512; color: #8aa39b; padding: 52px 0 0; font-size: 13.5px; } +.footer-grid { display: grid; grid-template-columns: 2fr 1fr 1fr 1fr; gap: 32px; padding-bottom: 36px; } +.footer .brand-name { color: #fff !important; } +.footer .brand { display: flex; align-items: center; gap: 9px; } +.footer-desc { margin: 12px 0 0; font-size: 13px; line-height: 1.8; } +.footer h4 { color: #fff; font-size: 13.5px; margin: 4px 0 12px; } +.footer a { display: block; color: #8aa39b !important; padding: 4px 0; font-size: 13px; } +.footer a:hover { color: #fff !important; } +.footer-bar { border-top: 1px solid #1b2b26; text-align: center; padding: 18px; font-size: 12px; color: #5f7a70; } + +/* ---------- 响应式 ---------- */ +@media (max-width: 1020px) { + .hero-inner { grid-template-columns: 1fr; padding-top: 52px; } + .mock { transform: none; } + .g4 { grid-template-columns: repeat(2, minmax(0,1fr)); } + .g3 { grid-template-columns: repeat(2, minmax(0,1fr)); } + .pricing.three { grid-template-columns: minmax(0, 420px); } + .footer-grid { grid-template-columns: repeat(2, 1fr); } + .stats-inner { grid-template-columns: repeat(2, 1fr); } +} +@media (max-width: 680px) { + .nav-links { display: none; } + .hero h1 { font-size: 32px; } + .sec-title { font-size: 24px; } + .g3, .g4 { grid-template-columns: 1fr; } + .footer-grid { grid-template-columns: 1fr; } + .stats-inner { grid-template-columns: repeat(2, 1fr); } +}