feat(site): 并入 Gin 官网与文档服务,对齐桌面产品形态
CI / Lint & TypeCheck (push) Canceled after 0s
CI / Test (push) Canceled after 0s
CI / Tauri Foundation Acceptance (push) Canceled after 0s
CI / Build (macos-latest) (push) Canceled after 0s
CI / Build (ubuntu-latest) (push) Canceled after 0s
CI / Build (windows-latest) (push) Canceled after 0s
CI / Lint & TypeCheck (push) Canceled after 0s
CI / Test (push) Canceled after 0s
CI / Tauri Foundation Acceptance (push) Canceled after 0s
CI / Build (macos-latest) (push) Canceled after 0s
CI / Build (ubuntu-latest) (push) Canceled after 0s
CI / Build (windows-latest) (push) Canceled after 0s
- apps/server:Gin embed 官网 + /docs + /health + /download(无操作 API) - run.sh 重写 web/gui 场景;.gitignore 排除 server 二进制与挂载的安装包 - README/AGENTS/CLAUDE 同步「浏览器只看官网、操作走桌面」的产品形态说明 - 终端视口背景变量与全宽终端边缘 hairline 修正(serial/terminal/i18n 微调)
This commit is contained in:
1 parent
b18214e96a
commit
5eb11826db
36 files changed
+3676
-144
No files matched your search
@@ -0,0 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
|
||||
<rect x="64" y="64" width="896" height="896" rx="224" fill="#101820"/>
|
||||
<rect x="116" y="116" width="792" height="792" rx="180" fill="#17232d"/>
|
||||
<path d="M258 326 454 512 258 698" fill="none" stroke="#f2f7f8" stroke-width="92" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M500 698h244" fill="none" stroke="#55aef2" stroke-width="92" stroke-linecap="round"/>
|
||||
<circle cx="750" cy="308" r="52" fill="#42d392"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 502 B |
@@ -0,0 +1,35 @@
|
||||
// OpsXShell 产品站 — 无依赖静态脚本
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
// 移动端导航
|
||||
const toggle = document.querySelector('.nav-toggle')
|
||||
const links = document.querySelector('.nav-links')
|
||||
toggle?.addEventListener('click', () => links?.classList.toggle('open'))
|
||||
links?.querySelectorAll('a').forEach((a) =>
|
||||
a.addEventListener('click', () => links.classList.remove('open'))
|
||||
)
|
||||
|
||||
// 复制 SHA-256
|
||||
document.querySelectorAll('[data-copy]').forEach((button) => {
|
||||
button.addEventListener('click', async () => {
|
||||
const value = button.getAttribute('data-copy') || ''
|
||||
try {
|
||||
await navigator.clipboard.writeText(value)
|
||||
const original = button.textContent
|
||||
button.textContent = '已复制 ✓'
|
||||
setTimeout(() => { button.textContent = original }, 1600)
|
||||
} catch {
|
||||
// 剪贴板不可用(如 file:// 非安全上下文)时退回选中文本提示
|
||||
button.textContent = '请手动复制'
|
||||
setTimeout(() => { button.textContent = original }, 1600)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// FAQ 单开(details 互斥)
|
||||
const faqs = document.querySelectorAll('.faq-item')
|
||||
faqs.forEach((item) =>
|
||||
item.addEventListener('toggle', () => {
|
||||
if (item.open) faqs.forEach((other) => { if (other !== item) other.open = false })
|
||||
})
|
||||
)
|
||||
})
|
||||
@@ -0,0 +1,811 @@
|
||||
:root {
|
||||
--bg: #0b1118;
|
||||
--bg-soft: #0e1720;
|
||||
--panel: #14212c;
|
||||
--panel-2: #17232d;
|
||||
--border: rgba(120, 160, 190, 0.16);
|
||||
--text: #e8f0f4;
|
||||
--text-2: #aabccb;
|
||||
--text-3: #7590a3;
|
||||
--accent: #55aef2;
|
||||
--accent-soft: rgba(85, 174, 242, 0.14);
|
||||
--green: #3fd68f;
|
||||
--green-soft: rgba(63, 214, 143, 0.12);
|
||||
--amber: #f5c04e;
|
||||
--purple: #a78bfa;
|
||||
--red: #f87171;
|
||||
--radius: 14px;
|
||||
--mono: 'SF Mono', ui-monospace, 'Cascadia Code', Menlo, Consolas, monospace;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
body {
|
||||
background:
|
||||
radial-gradient(1100px 500px at 75% -8%, rgba(85, 174, 242, 0.1), transparent 60%),
|
||||
radial-gradient(800px 420px at 12% 4%, rgba(63, 214, 143, 0.06), transparent 55%), var(--bg);
|
||||
color: var(--text);
|
||||
font-family:
|
||||
-apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;
|
||||
line-height: 1.65;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--accent);
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1080px;
|
||||
margin: 0 auto;
|
||||
padding: 0 24px;
|
||||
}
|
||||
|
||||
/* ── Nav ─────────────────────────────────────────── */
|
||||
.nav {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 50;
|
||||
background: rgba(11, 17, 24, 0.86);
|
||||
backdrop-filter: blur(12px);
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
.nav-inner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
height: 60px;
|
||||
}
|
||||
.brand {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
font-weight: 700;
|
||||
font-size: 17px;
|
||||
color: var(--text);
|
||||
}
|
||||
.brand:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
.brand img {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 7px;
|
||||
}
|
||||
.brand .tm {
|
||||
font-size: 10px;
|
||||
color: var(--text-3);
|
||||
font-weight: 500;
|
||||
margin-left: 2px;
|
||||
}
|
||||
.nav-links {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
margin-left: auto;
|
||||
align-items: center;
|
||||
}
|
||||
.nav-links a {
|
||||
color: var(--text-2);
|
||||
font-size: 14px;
|
||||
padding: 7px 12px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
.nav-links a:hover {
|
||||
color: var(--text);
|
||||
background: var(--panel);
|
||||
text-decoration: none;
|
||||
}
|
||||
.nav-cta {
|
||||
background: var(--accent);
|
||||
color: #06121c !important;
|
||||
font-weight: 600;
|
||||
padding: 7px 16px !important;
|
||||
border-radius: 9px;
|
||||
}
|
||||
.nav-cta:hover {
|
||||
background: #7cc0f5;
|
||||
}
|
||||
.nav-toggle {
|
||||
display: none;
|
||||
margin-left: auto;
|
||||
background: none;
|
||||
border: 1px solid var(--border);
|
||||
color: var(--text-2);
|
||||
border-radius: 8px;
|
||||
padding: 6px 11px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* ── Hero ────────────────────────────────────────── */
|
||||
.hero {
|
||||
padding: 84px 0 64px;
|
||||
}
|
||||
.hero-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1.05fr 1fr;
|
||||
gap: 52px;
|
||||
align-items: center;
|
||||
}
|
||||
.hero h1 {
|
||||
font-size: 44px;
|
||||
line-height: 1.22;
|
||||
letter-spacing: -0.5px;
|
||||
margin: 18px 0 14px;
|
||||
}
|
||||
.hero h1 .hl {
|
||||
color: var(--accent);
|
||||
}
|
||||
.hero .tagline {
|
||||
color: var(--text-2);
|
||||
font-size: 17px;
|
||||
margin-bottom: 26px;
|
||||
}
|
||||
.hero-badges {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.badge {
|
||||
font-size: 12px;
|
||||
color: var(--text-2);
|
||||
border: 1px solid var(--border);
|
||||
background: var(--panel);
|
||||
padding: 4px 11px;
|
||||
border-radius: 999px;
|
||||
}
|
||||
.badge b {
|
||||
color: var(--green);
|
||||
font-weight: 600;
|
||||
}
|
||||
.hero-ctas {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
}
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
border-radius: 10px;
|
||||
padding: 11px 22px;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
border: 1px solid transparent;
|
||||
transition: all 0.15s ease;
|
||||
}
|
||||
.btn-primary {
|
||||
background: var(--accent);
|
||||
color: #06121c;
|
||||
}
|
||||
.btn-primary:hover {
|
||||
background: #7cc0f5;
|
||||
text-decoration: none;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
.btn-ghost {
|
||||
background: transparent;
|
||||
color: var(--text);
|
||||
border-color: var(--border);
|
||||
}
|
||||
.btn-ghost:hover {
|
||||
border-color: var(--accent);
|
||||
text-decoration: none;
|
||||
}
|
||||
.hero-note {
|
||||
font-size: 12.5px;
|
||||
color: var(--text-3);
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
/* Terminal mock (pure CSS, no fake screenshot) */
|
||||
.term {
|
||||
background: #0d1620;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius);
|
||||
overflow: hidden;
|
||||
box-shadow: 0 24px 70px rgba(0, 0, 0, 0.45);
|
||||
}
|
||||
.term-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 10px 14px;
|
||||
background: #101b26;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
.term-dot {
|
||||
width: 11px;
|
||||
height: 11px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.term-dot.r {
|
||||
background: #ff5f57;
|
||||
}
|
||||
.term-dot.y {
|
||||
background: #febc2e;
|
||||
}
|
||||
.term-dot.g {
|
||||
background: #28c840;
|
||||
}
|
||||
.term-title {
|
||||
font-size: 12px;
|
||||
color: var(--text-3);
|
||||
margin-left: 6px;
|
||||
font-family: var(--mono);
|
||||
}
|
||||
.term-body {
|
||||
padding: 16px 18px 18px;
|
||||
font-family: var(--mono);
|
||||
font-size: 12.8px;
|
||||
line-height: 1.8;
|
||||
}
|
||||
.term-body .p {
|
||||
color: var(--green);
|
||||
}
|
||||
.term-body .c {
|
||||
color: var(--text);
|
||||
}
|
||||
.term-body .dim {
|
||||
color: #93aab9;
|
||||
}
|
||||
.term-body .out {
|
||||
color: #c3d2dd;
|
||||
}
|
||||
.term-body .err {
|
||||
color: var(--red);
|
||||
}
|
||||
.term-body .mark {
|
||||
color: var(--amber);
|
||||
}
|
||||
.cursor {
|
||||
display: inline-block;
|
||||
width: 8px;
|
||||
height: 15px;
|
||||
background: var(--green);
|
||||
vertical-align: -2px;
|
||||
animation: blink 1.1s steps(1) infinite;
|
||||
}
|
||||
@keyframes blink {
|
||||
50% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ── Sections ────────────────────────────────────── */
|
||||
section {
|
||||
padding: 74px 0;
|
||||
}
|
||||
.section-alt {
|
||||
background: var(--bg-soft);
|
||||
border-top: 1px solid var(--border);
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
.section-head {
|
||||
max-width: 660px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
.kicker {
|
||||
color: var(--accent);
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 2.5px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.section-head h2 {
|
||||
font-size: 30px;
|
||||
margin: 10px 0 12px;
|
||||
letter-spacing: -0.3px;
|
||||
}
|
||||
.section-head p {
|
||||
color: var(--text-2);
|
||||
font-size: 15.5px;
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
gap: 18px;
|
||||
}
|
||||
.grid-3 {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
.grid-2 {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
.card {
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius);
|
||||
padding: 22px 22px 20px;
|
||||
transition:
|
||||
border-color 0.15s ease,
|
||||
transform 0.15s ease;
|
||||
}
|
||||
.card:hover {
|
||||
border-color: rgba(85, 174, 242, 0.45);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
.card .icon {
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
border-radius: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 14px;
|
||||
font-size: 19px;
|
||||
}
|
||||
.card h3 {
|
||||
font-size: 16.5px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.card p {
|
||||
color: var(--text-2);
|
||||
font-size: 13.8px;
|
||||
}
|
||||
.card .tag {
|
||||
display: inline-block;
|
||||
font-size: 11px;
|
||||
padding: 2px 8px;
|
||||
border-radius: 999px;
|
||||
margin-left: 8px;
|
||||
vertical-align: 2px;
|
||||
}
|
||||
.tag-free {
|
||||
background: var(--green-soft);
|
||||
color: var(--green);
|
||||
}
|
||||
.tag-pro {
|
||||
background: var(--accent-soft);
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
/* AI workflow */
|
||||
.flow {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 14px;
|
||||
margin: 34px 0 26px;
|
||||
}
|
||||
.flow-step {
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 12px;
|
||||
padding: 18px;
|
||||
position: relative;
|
||||
}
|
||||
.flow-step .no {
|
||||
font-family: var(--mono);
|
||||
font-size: 12px;
|
||||
color: var(--accent);
|
||||
background: var(--accent-soft);
|
||||
border-radius: 7px;
|
||||
padding: 2px 8px;
|
||||
display: inline-block;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.flow-step h4 {
|
||||
font-size: 14.5px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.flow-step p {
|
||||
font-size: 12.8px;
|
||||
color: var(--text-2);
|
||||
}
|
||||
.confirm-card {
|
||||
background: #0d1620;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 12px;
|
||||
font-family: var(--mono);
|
||||
font-size: 13px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.confirm-head {
|
||||
padding: 10px 16px;
|
||||
border-bottom: 1px solid var(--border);
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
color: var(--text-3);
|
||||
}
|
||||
.risk-pill {
|
||||
padding: 1px 9px;
|
||||
border-radius: 999px;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.risk-mid {
|
||||
background: rgba(245, 192, 78, 0.14);
|
||||
color: var(--amber);
|
||||
}
|
||||
.risk-high {
|
||||
background: rgba(248, 113, 113, 0.15);
|
||||
color: var(--red);
|
||||
}
|
||||
.risk-safe {
|
||||
background: var(--green-soft);
|
||||
color: var(--green);
|
||||
}
|
||||
.confirm-cmd {
|
||||
padding: 14px 16px;
|
||||
color: var(--text);
|
||||
word-break: break-all;
|
||||
}
|
||||
.confirm-actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
padding: 0 16px 16px;
|
||||
}
|
||||
.confirm-actions span {
|
||||
font-size: 12px;
|
||||
padding: 5px 12px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--border);
|
||||
color: var(--text-2);
|
||||
}
|
||||
.confirm-actions .danger {
|
||||
border-color: rgba(248, 113, 113, 0.4);
|
||||
color: var(--red);
|
||||
}
|
||||
.confirm-actions .primary {
|
||||
background: var(--accent);
|
||||
color: #06121c;
|
||||
border-color: var(--accent);
|
||||
font-weight: 600;
|
||||
}
|
||||
.confirm-actions .green {
|
||||
border-color: rgba(63, 214, 143, 0.4);
|
||||
color: var(--green);
|
||||
}
|
||||
|
||||
.check-list {
|
||||
list-style: none;
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
margin-top: 26px;
|
||||
}
|
||||
.check-list li {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
font-size: 14px;
|
||||
color: var(--text-2);
|
||||
}
|
||||
.check-list li::before {
|
||||
content: '✓';
|
||||
color: var(--green);
|
||||
font-weight: 700;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.check-list li b {
|
||||
color: var(--text);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Pricing */
|
||||
.pricing {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 18px;
|
||||
}
|
||||
.plan {
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 16px;
|
||||
padding: 26px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.plan.featured {
|
||||
border-color: rgba(85, 174, 242, 0.55);
|
||||
background: linear-gradient(180deg, rgba(85, 174, 242, 0.08), var(--panel) 45%);
|
||||
position: relative;
|
||||
}
|
||||
.plan .ribbon {
|
||||
position: absolute;
|
||||
top: -12px;
|
||||
left: 24px;
|
||||
background: var(--accent);
|
||||
color: #06121c;
|
||||
font-size: 11.5px;
|
||||
font-weight: 700;
|
||||
padding: 3px 12px;
|
||||
border-radius: 999px;
|
||||
}
|
||||
.plan h3 {
|
||||
font-size: 17px;
|
||||
}
|
||||
.plan .price {
|
||||
font-size: 34px;
|
||||
font-weight: 700;
|
||||
margin: 12px 0 2px;
|
||||
}
|
||||
.plan .price small {
|
||||
font-size: 14px;
|
||||
color: var(--text-3);
|
||||
font-weight: 400;
|
||||
}
|
||||
.plan .price-note {
|
||||
font-size: 12.5px;
|
||||
color: var(--text-3);
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
.plan ul {
|
||||
list-style: none;
|
||||
display: grid;
|
||||
gap: 9px;
|
||||
margin: 4px 0 24px;
|
||||
flex: 1;
|
||||
}
|
||||
.plan ul li {
|
||||
font-size: 13.8px;
|
||||
color: var(--text-2);
|
||||
display: flex;
|
||||
gap: 9px;
|
||||
}
|
||||
.plan ul li::before {
|
||||
content: '✓';
|
||||
color: var(--green);
|
||||
font-weight: 700;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.plan ul li.locked::before {
|
||||
content: '+';
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
/* Security */
|
||||
.sec-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 14px;
|
||||
}
|
||||
.sec-item {
|
||||
display: flex;
|
||||
gap: 14px;
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 12px;
|
||||
padding: 18px;
|
||||
}
|
||||
.sec-item .ic {
|
||||
font-size: 20px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.sec-item h4 {
|
||||
font-size: 14.5px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.sec-item p {
|
||||
font-size: 13px;
|
||||
color: var(--text-2);
|
||||
}
|
||||
|
||||
/* Tech + download */
|
||||
.tech-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
.tech-list span {
|
||||
font-family: var(--mono);
|
||||
font-size: 13px;
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--border);
|
||||
padding: 7px 14px;
|
||||
border-radius: 9px;
|
||||
color: var(--text-2);
|
||||
}
|
||||
|
||||
.dl-box {
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 16px;
|
||||
padding: 30px;
|
||||
display: grid;
|
||||
grid-template-columns: 1.4fr 1fr;
|
||||
gap: 30px;
|
||||
align-items: center;
|
||||
}
|
||||
.dl-box h3 {
|
||||
font-size: 19px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.dl-box .meta {
|
||||
color: var(--text-3);
|
||||
font-size: 13px;
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
.sha {
|
||||
font-family: var(--mono);
|
||||
font-size: 11.5px;
|
||||
color: var(--text-3);
|
||||
background: #0d1620;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 9px;
|
||||
padding: 10px 12px;
|
||||
word-break: break-all;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: flex-start;
|
||||
margin-top: 14px;
|
||||
}
|
||||
.sha button {
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--accent);
|
||||
cursor: pointer;
|
||||
font-size: 11.5px;
|
||||
flex-shrink: 0;
|
||||
font-family: inherit;
|
||||
}
|
||||
.dl-note {
|
||||
font-size: 12.5px;
|
||||
color: var(--text-3);
|
||||
margin-top: 14px;
|
||||
}
|
||||
.dl-app {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 18px;
|
||||
justify-content: center;
|
||||
}
|
||||
.dl-app img {
|
||||
width: 92px;
|
||||
height: 92px;
|
||||
}
|
||||
.dl-app .os {
|
||||
text-align: left;
|
||||
}
|
||||
.dl-app .os b {
|
||||
display: block;
|
||||
font-size: 15px;
|
||||
}
|
||||
.dl-app .os span {
|
||||
color: var(--text-3);
|
||||
font-size: 12.5px;
|
||||
}
|
||||
|
||||
/* FAQ */
|
||||
.faq-item {
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 12px;
|
||||
background: var(--panel);
|
||||
margin-bottom: 10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.faq-item summary {
|
||||
cursor: pointer;
|
||||
padding: 16px 20px;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
list-style: none;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.faq-item summary::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
.faq-item summary::after {
|
||||
content: '+';
|
||||
color: var(--text-3);
|
||||
font-size: 18px;
|
||||
}
|
||||
.faq-item[open] summary::after {
|
||||
content: '−';
|
||||
}
|
||||
.faq-item .answer {
|
||||
padding: 0 20px 18px;
|
||||
color: var(--text-2);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
footer {
|
||||
border-top: 1px solid var(--border);
|
||||
padding: 40px 0 48px;
|
||||
color: var(--text-3);
|
||||
font-size: 13px;
|
||||
}
|
||||
.footer-inner {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 24px;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.footer-brand {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
color: var(--text);
|
||||
font-weight: 600;
|
||||
}
|
||||
.footer-brand img {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
footer nav {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 16px;
|
||||
}
|
||||
footer a {
|
||||
color: var(--text-3);
|
||||
}
|
||||
footer a:hover {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
/* ── Responsive ──────────────────────────────────── */
|
||||
@media (max-width: 960px) {
|
||||
.hero-grid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 36px;
|
||||
}
|
||||
.hero h1 {
|
||||
font-size: 34px;
|
||||
}
|
||||
.grid-3 {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
.flow {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
.pricing {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.dl-box {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
@media (max-width: 640px) {
|
||||
.nav-links {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: var(--bg-soft);
|
||||
border-bottom: 1px solid var(--border);
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
padding: 10px 18px 16px;
|
||||
gap: 2px;
|
||||
}
|
||||
.nav-links.open {
|
||||
display: flex;
|
||||
}
|
||||
.nav-toggle {
|
||||
display: block;
|
||||
}
|
||||
.grid-3,
|
||||
.grid-2,
|
||||
.sec-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.flow {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
section {
|
||||
padding: 56px 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
// Package site 提供产品官网(嵌入 HTML/CSS/JS)。
|
||||
package site
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
//go:embed template.html assets
|
||||
var files embed.FS
|
||||
|
||||
type Handler struct {
|
||||
html string
|
||||
}
|
||||
|
||||
func New() *Handler {
|
||||
raw, err := files.ReadFile("template.html")
|
||||
if err != nil {
|
||||
panic("site: template.html 缺失: " + err.Error())
|
||||
}
|
||||
return &Handler{html: string(raw)}
|
||||
}
|
||||
|
||||
func (h *Handler) Register(r *gin.Engine) {
|
||||
r.GET("/", h.Page)
|
||||
r.GET("/home", h.Page)
|
||||
r.GET("/index.html", h.Page)
|
||||
r.GET("/site/assets/*file", h.Asset)
|
||||
}
|
||||
|
||||
func (h *Handler) Page(c *gin.Context) {
|
||||
c.Header("Content-Type", "text/html; charset=utf-8")
|
||||
c.Header("Cache-Control", "no-cache")
|
||||
_, _ = c.Writer.WriteString(h.html)
|
||||
}
|
||||
|
||||
func (h *Handler) Asset(c *gin.Context) {
|
||||
name := strings.TrimPrefix(c.Param("file"), "/")
|
||||
if strings.Contains(name, "..") {
|
||||
c.Status(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
data, err := files.ReadFile("assets/" + name)
|
||||
if err != nil {
|
||||
c.Status(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
switch {
|
||||
case strings.HasSuffix(name, ".css"):
|
||||
c.Header("Content-Type", "text/css; charset=utf-8")
|
||||
case strings.HasSuffix(name, ".js"):
|
||||
c.Header("Content-Type", "application/javascript; charset=utf-8")
|
||||
case strings.HasSuffix(name, ".svg"):
|
||||
c.Header("Content-Type", "image/svg+xml")
|
||||
default:
|
||||
c.Header("Content-Type", "application/octet-stream")
|
||||
}
|
||||
c.Header("Cache-Control", "public, max-age=3600")
|
||||
c.Data(http.StatusOK, "", data)
|
||||
}
|
||||
@@ -0,0 +1,391 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>OpsXShell — 轻量原生运维终端</title>
|
||||
<meta name="description" content="OpsXShell 是基于 Tauri 2 与 Rust 的轻量原生运维终端:SSH 多标签分屏、SFTP 双栏、端口转发、RDP/VNC 远程桌面、串口与终端 AI 助手。便捷、人性化、不做堡垒机。" />
|
||||
<link rel="icon" type="image/svg+xml" href="/site/assets/icon.svg" />
|
||||
<link rel="stylesheet" href="/site/assets/style.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- ── Nav ─────────────────────────────────────── -->
|
||||
<header class="nav">
|
||||
<div class="container nav-inner">
|
||||
<a class="brand" href="#top">
|
||||
<img src="/site/assets/icon.svg" alt="OpsXShell 图标" />
|
||||
OpsXShell<span class="tm">v2.1.1</span>
|
||||
</a>
|
||||
<button class="nav-toggle" aria-label="打开菜单">☰</button>
|
||||
<nav class="nav-links">
|
||||
<a href="#features">功能</a>
|
||||
<a href="#ai">终端 AI</a>
|
||||
<a href="#pricing">价格</a>
|
||||
<a href="#security">安全</a>
|
||||
<a href="#download">下载</a>
|
||||
<a href="/docs">文档</a>
|
||||
<a href="#faq">FAQ</a>
|
||||
<a class="nav-cta" href="#download">免费下载</a>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- ── Hero ────────────────────────────────────── -->
|
||||
<div id="top"></div>
|
||||
<section class="hero">
|
||||
<div class="container hero-grid">
|
||||
<div>
|
||||
<span class="kicker">Tauri 2 · Rust · 原生桌面</span>
|
||||
<h1>连上就能干活的<br /><span class="hl">轻量运维终端</span></h1>
|
||||
<p class="tagline">
|
||||
终端、传文件、转发、远程桌面——短路径直达。没有插件市场,没有审批流,
|
||||
打开就用。
|
||||
</p>
|
||||
<div class="hero-badges">
|
||||
<span class="badge"><b>●</b> SSH / SFTP</span>
|
||||
<span class="badge"><b>●</b> 端口转发 / SOCKS5</span>
|
||||
<span class="badge"><b>●</b> RDP / VNC</span>
|
||||
<span class="badge"><b>●</b> 串口</span>
|
||||
<span class="badge"><b>●</b> 7 语种界面</span>
|
||||
</div>
|
||||
<div class="hero-ctas">
|
||||
<a class="btn btn-primary" href="/download/OpsXShell_2.1.1_aarch64.dmg">
|
||||
⬇ 下载 macOS 版(Apple Silicon)
|
||||
</a>
|
||||
<a class="btn btn-ghost" href="#features">看看能做什么</a>
|
||||
</div>
|
||||
<p class="hero-note">v2.1.1 · 13 MB · 免费层即可使用 SSH 终端、SFTP 与本地终端</p>
|
||||
</div>
|
||||
|
||||
<div class="term" aria-hidden="true">
|
||||
<div class="term-bar">
|
||||
<span class="term-dot r"></span><span class="term-dot y"></span><span class="term-dot g"></span>
|
||||
<span class="term-title">opsxshell — root@web-prod ~ │ 分屏 1/2</span>
|
||||
</div>
|
||||
<div class="term-body">
|
||||
<div><span class="p">➜</span> <span class="c">ssh dev@10.0.0.8</span></div>
|
||||
<div class="out">Host key verified via ~/.ssh/known_hosts ✓</div>
|
||||
<div><span class="p">➜</span> <span class="c">df -h /var && systemctl status nginx --no-pager</span></div>
|
||||
<div class="out">/dev/sda1 98G 41G 53G 44% /var</div>
|
||||
<div class="out">● nginx.service - active (running)</div>
|
||||
<div><span class="mark">▶ 转发</span> <span class="dim">socks5://127.0.0.1:1080 经 web-prod 出口已就绪</span></div>
|
||||
<div><span class="mark">▶ SFTP</span> <span class="dim">deploy.zip 上传完成 · 断点续传 · 原子替换</span></div>
|
||||
<div><span class="mark">▶ AI</span> <span class="c">总结刚才的部署输出</span><span class="cursor"></span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ── Features ────────────────────────────────── -->
|
||||
<section id="features" class="section-alt">
|
||||
<div class="container">
|
||||
<div class="section-head">
|
||||
<span class="kicker">核心能力</span>
|
||||
<h2>一个窗口,覆盖日常远程运维</h2>
|
||||
<p>SSH、SFTP、转发、远程桌面、串口和本地终端共用一个多标签工作区;常用流程保持简短,高级配置默认收起。</p>
|
||||
</div>
|
||||
<div class="grid grid-3">
|
||||
<div class="card">
|
||||
<div class="icon" style="background:rgba(85,174,242,.14)">⌨️</div>
|
||||
<h3>SSH 终端与会话管理</h3>
|
||||
<p>密码 / 私钥 / SSH Agent 自动尝试,主机指纹走 <code>~/.ssh/known_hosts</code> 校验。会话分组、多标签、最多 4 分屏、命令片段、<code>ssh://</code> 链接唤起快速连接。</p>
|
||||
<span class="tag tag-free">免费</span>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="icon" style="background:rgba(167,139,250,.14)">📁</div>
|
||||
<h3>SFTP 双栏文件管理</h3>
|
||||
<p>本地 / 远程双栏拖拽互传、断点续传、上传完成前原子替换、重命名与权限修改;远程文本直接编辑(约 2MB 上限)。</p>
|
||||
<span class="tag tag-free">免费</span>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="icon" style="background:rgba(63,214,143,.13)">🔗</div>
|
||||
<h3>端口转发</h3>
|
||||
<p>本地 / 远程 / 动态 SOCKS5 转发,规则与运行实例分离;状态栏「转发」抽屉统一管理,断线自动保留未停止的 Listener。</p>
|
||||
<span class="tag tag-pro">专业版</span>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="icon" style="background:rgba(245,192,78,.13)">🖥️</div>
|
||||
<h3>远程桌面 RDP / VNC</h3>
|
||||
<p>原生 IronRDP 与 VNC 会话,帧与输入经 Tauri 事件直达 Canvas;运行态只在内存,断开即清理。</p>
|
||||
<span class="tag tag-pro">专业版</span>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="icon" style="background:rgba(85,174,242,.14)">📤</div>
|
||||
<h3>批量执行与广播输入</h3>
|
||||
<p>多主机批量命令结果只在当前窗口汇总;同窗多分屏广播同步输入,敲一遍、处处生效(桌面会话除外)。</p>
|
||||
<span class="tag tag-pro">专业版</span>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="icon" style="background:rgba(63,214,143,.13)">🔩</div>
|
||||
<h3>本地终端与串口</h3>
|
||||
<p>系统 zsh / bash / sh 本地终端开箱即用;串口终端适配路由器、交换机与开发板调试。HTTP CONNECT / SOCKS5 连接代理。</p>
|
||||
<span class="tag tag-free">本地终端免费</span><span class="tag tag-pro">串口专业版</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ── AI ──────────────────────────────────────── -->
|
||||
<section id="ai">
|
||||
<div class="container">
|
||||
<div class="section-head">
|
||||
<span class="kicker">终端 AI 助手 · 专业版</span>
|
||||
<h2>先看上下文,再提建议,执行权始终在你手里</h2>
|
||||
<p>AI 只复用当前活跃的 SSH 连接,不建立独立凭据边界;最多 8 步执行循环,五级风险评级,危险命令硬拒绝并在 Rust 侧二次校验。</p>
|
||||
</div>
|
||||
|
||||
<div class="flow">
|
||||
<div class="flow-step">
|
||||
<span class="no">01</span>
|
||||
<h4>读取终端上下文</h4>
|
||||
<p>以选中文本或当前视口为起点,Agent 优先提出只读命令收集证据,不凭空猜测环境。</p>
|
||||
</div>
|
||||
<div class="flow-step">
|
||||
<span class="no">02</span>
|
||||
<h4>风险分级确认</h4>
|
||||
<p>严格 / 宽松两档模式;五级风险(安全 → 禁止执行),critical 永远直接拒绝。</p>
|
||||
</div>
|
||||
<div class="flow-step">
|
||||
<span class="no">03</span>
|
||||
<h4>你决定怎么执行</h4>
|
||||
<p>拒绝、只插入不执行、本次执行、本次+始终允许——四种选择都由你点击。</p>
|
||||
</div>
|
||||
<div class="flow-step">
|
||||
<span class="no">04</span>
|
||||
<h4>结果与小结</h4>
|
||||
<p>命令真实输出进入下一轮上下文;一键「总结输出」从长日志里提炼要点。</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="confirm-card" aria-hidden="true">
|
||||
<div class="confirm-head">
|
||||
<span>Agent 第 2/8 轮</span>
|
||||
<span class="risk-pill risk-high">高风险</span>
|
||||
<span style="margin-left:auto">宽松模式</span>
|
||||
</div>
|
||||
<div class="confirm-cmd">$ systemctl restart nginx</div>
|
||||
<div class="confirm-actions">
|
||||
<span class="danger">✕ 拒绝</span>
|
||||
<span class="green">⎘ 插入不执行</span>
|
||||
<span class="primary">▶ 本次执行</span>
|
||||
<span>∞ 本次+始终</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ul class="check-list">
|
||||
<li><b>不保存命令与对话历史</b>——AI 上下文只存在于当前窗口会话内存中。</li>
|
||||
<li><b>供应商自选</b>——OpenAI / Anthropic 兼容接口、new-api、本地 Ollama 均可,API Key 经 AES-256-GCM 加密落盘。</li>
|
||||
<li><b>可选「全部确认」</b>——开启后除只读白名单命令外,每一条都需你手动放行。</li>
|
||||
<li><b>随时停止</b>——生成或执行中一键取消,远端命令同步中止。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ── Pricing ─────────────────────────────────── -->
|
||||
<section id="pricing" class="section-alt">
|
||||
<div class="container">
|
||||
<div class="section-head">
|
||||
<span class="kicker">价格</span>
|
||||
<h2>免费够用,专业版解锁重活</h2>
|
||||
<p>许可证绑定设备而非订阅账号;离线许可证(LICOFF-)支持完全离线激活。</p>
|
||||
</div>
|
||||
<div class="pricing">
|
||||
<div class="plan">
|
||||
<h3>免费</h3>
|
||||
<div class="price">¥0</div>
|
||||
<div class="price-note">日常 SSH 运维完全够用</div>
|
||||
<ul>
|
||||
<li>SSH 终端(密码 / 私钥 / Agent)</li>
|
||||
<li>SFTP 双栏文件管理</li>
|
||||
<li>本地终端(zsh / bash / sh)</li>
|
||||
<li>会话管理与 <code>~/.ssh/config</code> 导入</li>
|
||||
<li>7 语种界面</li>
|
||||
</ul>
|
||||
<a class="btn btn-ghost" href="/download/OpsXShell_2.1.1_aarch64.dmg">免费下载</a>
|
||||
</div>
|
||||
<div class="plan featured">
|
||||
<span class="ribbon">推荐</span>
|
||||
<h3>专业版 · 包年</h3>
|
||||
<div class="price">¥99 <small>/ 年</small></div>
|
||||
<div class="price-note">2 台设备</div>
|
||||
<ul>
|
||||
<li class="locked">端口转发(本地 / 远程 / SOCKS5)</li>
|
||||
<li class="locked">终端 AI 助手</li>
|
||||
<li class="locked">批量执行 / 广播同步</li>
|
||||
<li class="locked">远程桌面 RDP / VNC</li>
|
||||
<li class="locked">串口终端与连接代理</li>
|
||||
<li class="locked">主机清单批量导入导出</li>
|
||||
</ul>
|
||||
<a class="btn btn-primary" href="#faq">应用内升级</a>
|
||||
</div>
|
||||
<div class="plan">
|
||||
<h3>专业版 · 永久</h3>
|
||||
<div class="price">¥199</div>
|
||||
<div class="price-note">5 台设备 · 终身授权</div>
|
||||
<ul>
|
||||
<li>包含包年全部功能</li>
|
||||
<li>一次买断,无续费</li>
|
||||
<li>离线许可证支持</li>
|
||||
<li>后续版本持续可用</li>
|
||||
</ul>
|
||||
<a class="btn btn-ghost" href="#faq">应用内升级</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ── Security ────────────────────────────────── -->
|
||||
<section id="security">
|
||||
<div class="container">
|
||||
<div class="section-head">
|
||||
<span class="kicker">安全边界</span>
|
||||
<h2>凭据加密落盘,运行态只在内存</h2>
|
||||
<p>产品聚焦「日常远程干活」:审计、录像、审批等堡垒机能力刻意不做——宁可少而顺,不做重型平台。</p>
|
||||
</div>
|
||||
<div class="sec-grid">
|
||||
<div class="sec-item">
|
||||
<span class="ic">🔐</span>
|
||||
<div>
|
||||
<h4>AES-256-GCM 本地加密</h4>
|
||||
<p>会话密码、私钥口令、模型 API Key 全部加密后落盘;主密钥固定在 <code>~/.opsxshell/master.key</code>,目录 0700、文件 0600。</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sec-item">
|
||||
<span class="ic">🧾</span>
|
||||
<div>
|
||||
<h4>known_hosts 主机指纹</h4>
|
||||
<p>首次连接指纹确认,后续变更即告警;不静默接受陌生主机。</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sec-item">
|
||||
<span class="ic">🕶️</span>
|
||||
<div>
|
||||
<h4>不留命令历史</h4>
|
||||
<p>不保存终端命令历史;批量命令结果与 AI 对话只保留在当前窗口。</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sec-item">
|
||||
<span class="ic">⚡</span>
|
||||
<div>
|
||||
<h4>运行态不落盘</h4>
|
||||
<p>转发 Listener、RDP / VNC worker 的运行态只存在原生侧内存;界面的「停止」关闭的是真实原生资源。</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ── Tech ────────────────────────────────────── -->
|
||||
<section class="section-alt">
|
||||
<div class="container">
|
||||
<div class="section-head">
|
||||
<span class="kicker">技术栈</span>
|
||||
<h2>原生性能,跨平台内核</h2>
|
||||
</div>
|
||||
<div class="tech-list">
|
||||
<span>Tauri 2</span><span>Rust 2021</span><span>ssh2 / libssh2</span><span>IronRDP</span>
|
||||
<span>vnc-rs</span><span>portable-pty</span><span>serialport</span><span>React 18</span>
|
||||
<span>TypeScript 5</span><span>Zustand</span><span>XTerm.js</span><span>i18next · 7 语种</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ── Download ────────────────────────────────── -->
|
||||
<section id="download">
|
||||
<div class="container">
|
||||
<div class="section-head">
|
||||
<span class="kicker">下载</span>
|
||||
<h2>拿走即用</h2>
|
||||
</div>
|
||||
<div class="dl-box">
|
||||
<div>
|
||||
<h3>OpsXShell v2.1.1 · macOS(Apple Silicon)</h3>
|
||||
<p class="meta">.dmg 安装包 · 13 MB · macOS 13+ · 2026-09-02 构建</p>
|
||||
<a class="btn btn-primary" href="/download/OpsXShell_2.1.1_aarch64.dmg">⬇ 下载 OpsXShell_2.1.1_aarch64.dmg</a>
|
||||
<div class="sha">
|
||||
<span>
|
||||
SHA-256<br />
|
||||
423828c8d19cd77d1aceda80ccbb82d0e5155d27d559df5a8ff0985dca0f033
|
||||
</span>
|
||||
<button data-copy="423828c8d19cd77d1aceda80ccbb82d0e5155d27d559df5a8ff0985dca0f033">复制</button>
|
||||
</div>
|
||||
<p class="dl-note">
|
||||
当前版本未做开发者签名与公证:首次打开请右键点击 .app →「打开」,或在系统设置中允许。
|
||||
Windows 与 Linux 版本将在对应平台实机验收后发布。
|
||||
</p>
|
||||
</div>
|
||||
<div class="dl-app">
|
||||
<img src="/site/assets/icon.svg" alt="OpsXShell 应用图标" />
|
||||
<div class="os">
|
||||
<b>macOS 13+</b>
|
||||
<span>Apple Silicon(M1/M2/M3/M4)</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ── FAQ ─────────────────────────────────────── -->
|
||||
<section id="faq" class="section-alt">
|
||||
<div class="container">
|
||||
<div class="section-head">
|
||||
<span class="kicker">FAQ</span>
|
||||
<h2>常见问题</h2>
|
||||
</div>
|
||||
|
||||
<details class="faq-item">
|
||||
<summary>OpsXShell 会保存我的 SSH 密码吗?</summary>
|
||||
<div class="answer">会话密码、私钥口令经 AES-256-GCM 加密后保存在本机应用数据目录,主密钥单独存放于 <code>~/.opsxshell/master.key</code>(目录 0700 / 文件 0600)。不上传任何凭据;也支持完全不保存密码的 SSH Agent 认证。</div>
|
||||
</details>
|
||||
<details class="faq-item">
|
||||
<summary>AI 会自动执行命令吗?</summary>
|
||||
<div class="answer">默认按「严格 / 宽松」两档确认:宽松模式下仅高风险命令需要确认,严格模式中风险起确认。危险命令(如 <code>rm -rf /</code>)无论什么模式都直接拒绝,且 Rust 侧二次校验。你还可以开启「所有命令都需确认」,或在确认卡上选择「只插入不执行」。</div>
|
||||
</details>
|
||||
<details class="faq-item">
|
||||
<summary>支持 <code>~/.ssh/config</code> 和跳板机吗?</summary>
|
||||
<div class="answer">支持导入 <code>~/.ssh/config</code> 常用字段;SSH 代理 / 跳板(HTTP CONNECT、SOCKS5)属于专业版能力。</div>
|
||||
</details>
|
||||
<details class="faq-item">
|
||||
<summary>免费版和专业版差在哪?</summary>
|
||||
<div class="answer">免费版包含 SSH 终端、SFTP、本地终端与会话管理。专业版解锁端口转发、连接代理、终端 AI、批量执行 / 广播、RDP / VNC 远程桌面、串口与主机清单批量导入导出。包年 ¥99(2 台设备)或永久 ¥199(5 台设备),均在应用内升级。</div>
|
||||
</details>
|
||||
<details class="faq-item">
|
||||
<summary>支持 Windows / Linux 吗?</summary>
|
||||
<div class="answer">内核(Tauri 2 + Rust)面向 macOS / Windows / Linux 跨平台设计;安装包按「目标系统实机构建并验收」的原则发布。当前提供 macOS Apple Silicon 包,Windows 与 Linux 版在对应平台完成实机验收后上线。</div>
|
||||
</details>
|
||||
<details class="faq-item">
|
||||
<summary>数据保存在哪里?</summary>
|
||||
<div class="answer">会话与设置保存在系统应用数据目录的 <code>opsxshell-data.json</code>;终端标签布局持久化,但连接、转发、远程桌面等运行态只在内存,应用重启后按需重连。</div>
|
||||
</details>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ── Footer ──────────────────────────────────── -->
|
||||
<footer>
|
||||
<div class="container footer-inner">
|
||||
<div>
|
||||
<div class="footer-brand">
|
||||
<img src="/site/assets/icon.svg" alt="" />
|
||||
OpsXShell
|
||||
</div>
|
||||
<p style="margin-top:8px">轻量运维终端 · 便捷、人性化、操作简单实用</p>
|
||||
</div>
|
||||
<nav>
|
||||
<a href="#features">功能</a>
|
||||
<a href="#ai">终端 AI</a>
|
||||
<a href="#pricing">价格</a>
|
||||
<a href="#security">安全</a>
|
||||
<a href="#download">下载</a>
|
||||
<a href="/docs">文档</a>
|
||||
<a href="#faq">FAQ</a>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="container" style="margin-top:22px">
|
||||
<p>© 2026 OpsXShell · 不做审计、审批与堡垒机——宁可少而顺。</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="/site/assets/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in new issue
Block a user