@wenbin_wb/dsh-bridge 2.6.1 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +127 -0
- package/README.en.md +40 -20
- package/README.md +40 -20
- package/client/client.js +568 -65
- package/client/index.js +485 -39
- package/docs/feishu-usage.md +1 -0
- package/docs/qq-usage.md +1 -0
- package/docs/telegram-usage.md +1 -0
- package/docs/wechat-usage.md +1 -0
- package/lib/auth/login-template.js +4 -0
- package/lib/bridge-rpc-constants.js +5 -0
- package/lib/bridge-rpc.js +38 -1
- package/lib/cloudflared-manager.mjs +15 -1
- package/lib/index.js +270 -2
- package/lib/platform/conversation-bridge.js +92 -46
- package/lib/qq/gateway.js +5 -2
- package/lib/telegram/gateway.js +25 -17
- package/lib/wechat/gateway.js +27 -13
- package/package.json +3 -2
package/client/client.js
CHANGED
|
@@ -45,6 +45,11 @@ var BRIDGE_ENDPOINTS = {
|
|
|
45
45
|
saveCustomTunnelConfig: "saveCustomTunnelConfig",
|
|
46
46
|
checkVersion: "checkVersion",
|
|
47
47
|
upgradePlugin: "upgradePlugin",
|
|
48
|
+
restartDsh: "restartDsh",
|
|
49
|
+
exportBackup: "exportBackup",
|
|
50
|
+
importBackup: "importBackup",
|
|
51
|
+
diagnoseNetwork: "diagnoseNetwork",
|
|
52
|
+
getSystemMetrics: "getSystemMetrics",
|
|
48
53
|
// 访问安全认证(密码保护 / 扫码免密 Token)
|
|
49
54
|
authGetStatus: "authGetStatus",
|
|
50
55
|
authUpdateConfig: "authUpdateConfig",
|
|
@@ -187,34 +192,14 @@ var Icons = {
|
|
|
187
192
|
"svg",
|
|
188
193
|
{ viewBox: "0 0 24 24", width: 12, height: 12, fill: "none", stroke: "currentColor", strokeWidth: 2.5, strokeLinecap: "round", strokeLinejoin: "round", ...props },
|
|
189
194
|
React.createElement("polyline", { points: "20 6 9 17 4 12" })
|
|
195
|
+
),
|
|
196
|
+
ops: (props) => React.createElement(
|
|
197
|
+
"svg",
|
|
198
|
+
{ viewBox: "0 0 24 24", width: 16, height: 16, fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", ...props },
|
|
199
|
+
React.createElement("circle", { cx: 12, cy: 12, r: 3 }),
|
|
200
|
+
React.createElement("path", { d: "M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z" })
|
|
190
201
|
)
|
|
191
202
|
};
|
|
192
|
-
function useCopy() {
|
|
193
|
-
const [copied, setCopied] = React.useState(false);
|
|
194
|
-
const copy = React.useCallback((text) => {
|
|
195
|
-
const done = () => {
|
|
196
|
-
setCopied(true);
|
|
197
|
-
setTimeout(() => setCopied(false), 2e3);
|
|
198
|
-
};
|
|
199
|
-
if (navigator.clipboard?.writeText) {
|
|
200
|
-
navigator.clipboard.writeText(text).then(done).catch(() => fallbackCopy());
|
|
201
|
-
} else {
|
|
202
|
-
fallbackCopy();
|
|
203
|
-
}
|
|
204
|
-
function fallbackCopy() {
|
|
205
|
-
const textarea = document.createElement("textarea");
|
|
206
|
-
textarea.value = text;
|
|
207
|
-
textarea.style.position = "fixed";
|
|
208
|
-
textarea.style.opacity = "0";
|
|
209
|
-
document.body.appendChild(textarea);
|
|
210
|
-
textarea.select();
|
|
211
|
-
const success = document.execCommand("copy");
|
|
212
|
-
document.body.removeChild(textarea);
|
|
213
|
-
if (success) done();
|
|
214
|
-
}
|
|
215
|
-
}, []);
|
|
216
|
-
return [copied, copy];
|
|
217
|
-
}
|
|
218
203
|
function StatusTag({ running, status }) {
|
|
219
204
|
let bg = "var(--dsw-alias-bg-layer-2,#f3f4f6)";
|
|
220
205
|
let color = "var(--dsw-alias-label-secondary,#6b7280)";
|
|
@@ -338,7 +323,12 @@ function QrBlock({ url, qr, onReset, auth, onNavigateSecurity }) {
|
|
|
338
323
|
"div",
|
|
339
324
|
{ style: { marginTop: 10 } },
|
|
340
325
|
React.createElement("img", { src: qr, alt: "QR", style: s.qr }),
|
|
341
|
-
React.createElement("div", { style: { ...s.muted, marginTop: 4 } }, "\u8BF7\u5728\u79C1\u5BC6\u73AF\u5883\u4E0B\u4F7F\u7528")
|
|
326
|
+
React.createElement("div", { style: { ...s.muted, marginTop: 4 } }, "\u8BF7\u5728\u79C1\u5BC6\u73AF\u5883\u4E0B\u4F7F\u7528"),
|
|
327
|
+
React.createElement(
|
|
328
|
+
"div",
|
|
329
|
+
{ style: { ...s.muted, marginTop: 4, fontSize: 11, color: "var(--dsw-alias-brand-primary, #4f6ef7)" } },
|
|
330
|
+
"\u{1F4F1} \u63D0\u793A\uFF1A\u624B\u673A\u6D4F\u89C8\u5668\u626B\u7801\u6253\u5F00\u540E\uFF0C\u5728\u83DC\u5355\u70B9\u51FB\u300C\u6DFB\u52A0\u5230\u4E3B\u5C4F\u5E55\u300D\u5373\u53EF\u4F5C\u4E3A\u72EC\u7ACB\u5168\u5C4F App \u8FD0\u884C\u3002"
|
|
331
|
+
)
|
|
342
332
|
),
|
|
343
333
|
onReset && React.createElement(
|
|
344
334
|
"div",
|
|
@@ -1683,30 +1673,416 @@ function PlatformCard({ platformId, platformName, platformDesc, rpcCall, onStatu
|
|
|
1683
1673
|
)
|
|
1684
1674
|
);
|
|
1685
1675
|
}
|
|
1686
|
-
function
|
|
1687
|
-
|
|
1676
|
+
function SystemMetricsWidget({ metrics }) {
|
|
1677
|
+
if (!metrics) return null;
|
|
1678
|
+
const memUsedPercent = metrics.memory?.usedPercent ?? 0;
|
|
1679
|
+
const memUsedGb = (metrics.memory?.usedBytes / 1024 ** 3).toFixed(1);
|
|
1680
|
+
const memTotalGb = (metrics.memory?.totalBytes / 1024 ** 3).toFixed(1);
|
|
1681
|
+
const heapMb = Math.round((metrics.memory?.processHeapUsed || 0) / 1024 ** 2);
|
|
1682
|
+
const formatUptime = (sec = 0) => {
|
|
1683
|
+
const days = Math.floor(sec / 86400);
|
|
1684
|
+
const hrs = Math.floor(sec % 86400 / 3600);
|
|
1685
|
+
const mins = Math.floor(sec % 3600 / 60);
|
|
1686
|
+
if (days > 0) return `${days}\u5929 ${hrs}\u5C0F\u65F6 ${mins}\u5206`;
|
|
1687
|
+
if (hrs > 0) return `${hrs}\u5C0F\u65F6 ${mins}\u5206`;
|
|
1688
|
+
return `${mins}\u5206\u949F`;
|
|
1689
|
+
};
|
|
1690
|
+
const progressColor = memUsedPercent > 85 ? "#dc2626" : memUsedPercent > 70 ? "#d97706" : "#059669";
|
|
1691
|
+
return React.createElement(
|
|
1692
|
+
"div",
|
|
1693
|
+
{
|
|
1694
|
+
style: {
|
|
1695
|
+
...s.card,
|
|
1696
|
+
marginBottom: 16
|
|
1697
|
+
}
|
|
1698
|
+
},
|
|
1699
|
+
React.createElement(
|
|
1700
|
+
"div",
|
|
1701
|
+
{ style: { display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 12, flexWrap: "wrap", gap: 6 } },
|
|
1702
|
+
React.createElement(
|
|
1703
|
+
"div",
|
|
1704
|
+
{ style: { ...s.label, fontSize: 13, display: "flex", alignItems: "center", gap: 6 } },
|
|
1705
|
+
"\u{1F4CA} \u5BBF\u4E3B\u7CFB\u7EDF\u4E0E\u8FD0\u884C\u770B\u677F"
|
|
1706
|
+
),
|
|
1707
|
+
React.createElement(
|
|
1708
|
+
"div",
|
|
1709
|
+
{ style: { fontSize: 11, color: "var(--dsw-alias-label-secondary, #6b7280)" } },
|
|
1710
|
+
`Node ${metrics.os?.nodeVersion || ""} \xB7 ${metrics.os?.platform || ""} ${metrics.os?.arch || ""}`
|
|
1711
|
+
)
|
|
1712
|
+
),
|
|
1713
|
+
React.createElement(
|
|
1714
|
+
"div",
|
|
1715
|
+
{ style: { display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(130px, 1fr))", gap: 12, marginBottom: 12 } },
|
|
1716
|
+
React.createElement(
|
|
1717
|
+
"div",
|
|
1718
|
+
null,
|
|
1719
|
+
React.createElement("div", { style: { color: "var(--dsw-alias-label-tertiary, #9ca3af)", fontSize: 11, marginBottom: 2 } }, "CPU \u6838\u5FC3\u4E0E\u578B\u53F7"),
|
|
1720
|
+
React.createElement(
|
|
1721
|
+
"div",
|
|
1722
|
+
{ style: { fontWeight: 600, color: "var(--dsw-alias-label-primary, currentColor)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }, title: metrics.cpu?.model },
|
|
1723
|
+
`${metrics.cpu?.cores || 0} \u6838\u5FC3 (${(metrics.cpu?.model || "").split("@")[0].trim()})`
|
|
1724
|
+
)
|
|
1725
|
+
),
|
|
1726
|
+
React.createElement(
|
|
1727
|
+
"div",
|
|
1728
|
+
null,
|
|
1729
|
+
React.createElement("div", { style: { color: "var(--dsw-alias-label-tertiary, #9ca3af)", fontSize: 11, marginBottom: 2 } }, "DSH \u8FD0\u884C\u65F6\u95F4 (Uptime)"),
|
|
1730
|
+
React.createElement(
|
|
1731
|
+
"div",
|
|
1732
|
+
{ style: { fontWeight: 600, color: "var(--dsw-alias-state-success-primary, #059669)" } },
|
|
1733
|
+
formatUptime(metrics.uptime?.processSec)
|
|
1734
|
+
)
|
|
1735
|
+
),
|
|
1736
|
+
React.createElement(
|
|
1737
|
+
"div",
|
|
1738
|
+
null,
|
|
1739
|
+
React.createElement("div", { style: { color: "var(--dsw-alias-label-tertiary, #9ca3af)", fontSize: 11, marginBottom: 2 } }, "Node \u8FDB\u7A0B\u5806\u5185\u5B58"),
|
|
1740
|
+
React.createElement(
|
|
1741
|
+
"div",
|
|
1742
|
+
{ style: { fontWeight: 600, color: "var(--dsw-alias-label-primary, currentColor)" } },
|
|
1743
|
+
`${heapMb} MB`
|
|
1744
|
+
)
|
|
1745
|
+
)
|
|
1746
|
+
),
|
|
1747
|
+
React.createElement(
|
|
1748
|
+
"div",
|
|
1749
|
+
null,
|
|
1750
|
+
React.createElement(
|
|
1751
|
+
"div",
|
|
1752
|
+
{ style: { display: "flex", justifyContent: "space-between", fontSize: 11, color: "var(--dsw-alias-label-secondary, #6b7280)", marginBottom: 4 } },
|
|
1753
|
+
React.createElement("span", null, `\u7CFB\u7EDF\u5185\u5B58\u5360\u7528: ${memUsedGb} GB / ${memTotalGb} GB`),
|
|
1754
|
+
React.createElement("span", { style: { fontWeight: 600, color: progressColor } }, `${memUsedPercent}%`)
|
|
1755
|
+
),
|
|
1756
|
+
React.createElement(
|
|
1757
|
+
"div",
|
|
1758
|
+
{
|
|
1759
|
+
style: {
|
|
1760
|
+
width: "100%",
|
|
1761
|
+
height: 6,
|
|
1762
|
+
background: "var(--dsw-alias-border-l2, #e5e7eb)",
|
|
1763
|
+
borderRadius: 999,
|
|
1764
|
+
overflow: "hidden"
|
|
1765
|
+
}
|
|
1766
|
+
},
|
|
1767
|
+
React.createElement("div", {
|
|
1768
|
+
style: {
|
|
1769
|
+
width: `${memUsedPercent}%`,
|
|
1770
|
+
height: "100%",
|
|
1771
|
+
background: progressColor,
|
|
1772
|
+
borderRadius: 999,
|
|
1773
|
+
transition: "width .3s ease"
|
|
1774
|
+
}
|
|
1775
|
+
})
|
|
1776
|
+
)
|
|
1777
|
+
)
|
|
1778
|
+
);
|
|
1779
|
+
}
|
|
1780
|
+
function NetworkDiagnosticWidget({ rpcCall }) {
|
|
1781
|
+
const [running, setRunning] = React.useState(false);
|
|
1782
|
+
const [result, setResult] = React.useState(null);
|
|
1783
|
+
const runDiagnose = React.useCallback(async () => {
|
|
1784
|
+
setRunning(true);
|
|
1785
|
+
try {
|
|
1786
|
+
const r = await rpcCall(BRIDGE_ENDPOINTS.diagnoseNetwork, {});
|
|
1787
|
+
if (r?.ok) setResult(r.value);
|
|
1788
|
+
} catch (e) {
|
|
1789
|
+
setResult({ overall: "warning", results: [{ item: "err", name: "\u8BCA\u65AD\u8BF7\u6C42\u5F02\u5E38", status: "fail", detail: e.message }] });
|
|
1790
|
+
} finally {
|
|
1791
|
+
setRunning(false);
|
|
1792
|
+
}
|
|
1793
|
+
}, [rpcCall]);
|
|
1794
|
+
return React.createElement(
|
|
1795
|
+
"div",
|
|
1796
|
+
{ style: { ...s.card, marginBottom: 16 } },
|
|
1797
|
+
React.createElement(
|
|
1798
|
+
"div",
|
|
1799
|
+
{ style: { marginBottom: 10 } },
|
|
1800
|
+
React.createElement(
|
|
1801
|
+
"div",
|
|
1802
|
+
{ style: { ...s.label, fontSize: 13, display: "flex", alignItems: "center", gap: 6 } },
|
|
1803
|
+
"\u{1F50D} \u7F51\u7EDC\u8FDE\u901A\u6027\u4E00\u952E\u8BCA\u65AD"
|
|
1804
|
+
),
|
|
1805
|
+
React.createElement(
|
|
1806
|
+
"div",
|
|
1807
|
+
{ style: { ...s.muted, marginTop: 3 } },
|
|
1808
|
+
"\u4E00\u952E\u68C0\u6D4B\u672C\u5730\u53CD\u5411\u4EE3\u7406\u7AEF\u53E3\u3001\u5C40\u57DF\u7F51 IPv4\u3001Cloudflare Anycast \u5EF6\u8FDF\u4EE5\u53CA\u56FD\u5185 npmmirror \u955C\u50CF\u6E90\u8FDE\u901A\u6027\u3002"
|
|
1809
|
+
)
|
|
1810
|
+
),
|
|
1811
|
+
React.createElement(
|
|
1812
|
+
"div",
|
|
1813
|
+
{ style: { display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap", marginBottom: result ? 12 : 0 } },
|
|
1814
|
+
React.createElement(
|
|
1815
|
+
"button",
|
|
1816
|
+
{
|
|
1817
|
+
type: "button",
|
|
1818
|
+
style: { ...s.btnPri, height: 32, fontSize: 12, padding: "0 14px" },
|
|
1819
|
+
onClick: runDiagnose,
|
|
1820
|
+
disabled: running
|
|
1821
|
+
},
|
|
1822
|
+
running ? "\u6B63\u5728\u63A2\u6D4B\u8FDE\u901A\u6027\u2026" : result ? "\u{1F504} \u91CD\u65B0\u8BCA\u65AD\u7F51\u7EDC" : "\u{1F50D} \u5F00\u59CB\u4E00\u952E\u8BCA\u65AD"
|
|
1823
|
+
),
|
|
1824
|
+
result && React.createElement("span", {
|
|
1825
|
+
style: {
|
|
1826
|
+
fontSize: 12,
|
|
1827
|
+
color: result.overall === "healthy" ? "var(--dsw-alias-state-success-primary, #059669)" : "var(--dsw-alias-state-warn-primary, #d97706)",
|
|
1828
|
+
fontWeight: 600
|
|
1829
|
+
}
|
|
1830
|
+
}, result.overall === "healthy" ? "\u2713 \u6240\u6709\u7F51\u7EDC\u63A2\u6D4B\u9879\u6B63\u5E38" : "\u25B2 \u68C0\u6D4B\u5230\u90E8\u5206\u5EF6\u8FDF\u8F83\u9AD8\u6216\u5F02\u5E38")
|
|
1831
|
+
),
|
|
1832
|
+
running && !result && React.createElement(
|
|
1833
|
+
"div",
|
|
1834
|
+
{
|
|
1835
|
+
style: {
|
|
1836
|
+
marginTop: 10,
|
|
1837
|
+
padding: "10px 14px",
|
|
1838
|
+
borderRadius: 8,
|
|
1839
|
+
background: "var(--dsw-alias-bg-layer-2, #f9fafb)",
|
|
1840
|
+
display: "flex",
|
|
1841
|
+
alignItems: "center",
|
|
1842
|
+
gap: 8,
|
|
1843
|
+
color: "var(--dsw-alias-brand-primary, #4f6ef7)",
|
|
1844
|
+
fontSize: 12
|
|
1845
|
+
}
|
|
1846
|
+
},
|
|
1847
|
+
React.createElement("span", { style: { animation: "spin 1s linear infinite", display: "inline-flex" } }, React.createElement(Icons.refresh)),
|
|
1848
|
+
"\u6B63\u5728\u6267\u884C\u7F51\u7EDC\u7AEF\u53E3\u4E0E\u4E91\u7AEF\u8282\u70B9\u8FDE\u901A\u6027\u63A2\u6D4B\u2026"
|
|
1849
|
+
),
|
|
1850
|
+
result?.results && React.createElement(
|
|
1851
|
+
"div",
|
|
1852
|
+
{
|
|
1853
|
+
style: {
|
|
1854
|
+
display: "flex",
|
|
1855
|
+
flexDirection: "column",
|
|
1856
|
+
gap: 8,
|
|
1857
|
+
marginTop: 10,
|
|
1858
|
+
paddingTop: 10,
|
|
1859
|
+
borderTop: "1px solid var(--dsw-alias-border-l2, #e5e7eb)"
|
|
1860
|
+
}
|
|
1861
|
+
},
|
|
1862
|
+
result.results.map((item, idx) => {
|
|
1863
|
+
const isPass = item.status === "pass";
|
|
1864
|
+
const isWarn = item.status === "warn";
|
|
1865
|
+
return React.createElement(
|
|
1866
|
+
"div",
|
|
1867
|
+
{
|
|
1868
|
+
key: idx,
|
|
1869
|
+
style: {
|
|
1870
|
+
display: "flex",
|
|
1871
|
+
alignItems: "flex-start",
|
|
1872
|
+
justifyContent: "space-between",
|
|
1873
|
+
gap: 8,
|
|
1874
|
+
padding: "8px 10px",
|
|
1875
|
+
borderRadius: 6,
|
|
1876
|
+
background: "var(--dsw-alias-bg-layer-1, rgba(255,255,255,0.7))",
|
|
1877
|
+
border: `1px solid ${isPass ? "var(--dsw-alias-state-success-border, #a7f3d0)" : isWarn ? "var(--dsw-alias-state-warn-border, #fde68a)" : "var(--dsw-alias-state-error-border, #fecaca)"}`,
|
|
1878
|
+
boxSizing: "border-box"
|
|
1879
|
+
}
|
|
1880
|
+
},
|
|
1881
|
+
React.createElement(
|
|
1882
|
+
"div",
|
|
1883
|
+
{ style: { flex: 1, minWidth: 0 } },
|
|
1884
|
+
React.createElement(
|
|
1885
|
+
"div",
|
|
1886
|
+
{ style: { fontWeight: 600, color: "var(--dsw-alias-label-primary, currentColor)", marginBottom: 2 } },
|
|
1887
|
+
isPass ? "\u2713 " : isWarn ? "\u25B2 " : "\u2715 ",
|
|
1888
|
+
item.name
|
|
1889
|
+
),
|
|
1890
|
+
React.createElement("div", { style: { fontSize: 11, color: "var(--dsw-alias-label-secondary, #6b7280)" } }, item.detail)
|
|
1891
|
+
),
|
|
1892
|
+
item.latencyMs != null && React.createElement("span", {
|
|
1893
|
+
style: {
|
|
1894
|
+
fontSize: 11,
|
|
1895
|
+
fontWeight: 600,
|
|
1896
|
+
flexShrink: 0,
|
|
1897
|
+
color: item.latencyMs < 500 ? "var(--dsw-alias-state-success-primary, #059669)" : "var(--dsw-alias-state-warn-primary, #d97706)"
|
|
1898
|
+
}
|
|
1899
|
+
}, `${item.latencyMs}ms`)
|
|
1900
|
+
);
|
|
1901
|
+
})
|
|
1902
|
+
)
|
|
1903
|
+
);
|
|
1904
|
+
}
|
|
1905
|
+
function BackupRestoreWidget({ rpcCall, onUpdate }) {
|
|
1906
|
+
const [exporting, setExporting] = React.useState(false);
|
|
1907
|
+
const [importing, setImporting] = React.useState(false);
|
|
1908
|
+
const [msg, setMsg] = React.useState(null);
|
|
1909
|
+
const fileInputRef = React.useRef(null);
|
|
1910
|
+
const handleExport = async () => {
|
|
1911
|
+
setExporting(true);
|
|
1912
|
+
setMsg(null);
|
|
1913
|
+
try {
|
|
1914
|
+
const r = await rpcCall(BRIDGE_ENDPOINTS.exportBackup, {});
|
|
1915
|
+
if (r?.ok && r.value) {
|
|
1916
|
+
const jsonStr = JSON.stringify(r.value, null, 2);
|
|
1917
|
+
const blob = new Blob([jsonStr], { type: "application/json" });
|
|
1918
|
+
const url = URL.createObjectURL(blob);
|
|
1919
|
+
const a = document.createElement("a");
|
|
1920
|
+
const now = /* @__PURE__ */ new Date();
|
|
1921
|
+
const dateStr = `${now.getFullYear()}${String(now.getMonth() + 1).padStart(2, "0")}${String(now.getDate()).padStart(2, "0")}`;
|
|
1922
|
+
a.href = url;
|
|
1923
|
+
a.download = `dsh-bridge-backup-${dateStr}.json`;
|
|
1924
|
+
document.body.appendChild(a);
|
|
1925
|
+
a.click();
|
|
1926
|
+
document.body.removeChild(a);
|
|
1927
|
+
URL.revokeObjectURL(url);
|
|
1928
|
+
setMsg({ ok: true, text: "\u2713 \u5907\u4EFD\u6587\u4EF6\u5DF2\u6210\u529F\u5BFC\u51FA\u5E76\u4E0B\u8F7D\u5230\u672C\u5730\uFF01" });
|
|
1929
|
+
} else {
|
|
1930
|
+
setMsg({ ok: false, text: r?.error?.message || "\u5BFC\u51FA\u5907\u4EFD\u5931\u8D25" });
|
|
1931
|
+
}
|
|
1932
|
+
} catch (e) {
|
|
1933
|
+
setMsg({ ok: false, text: e.message || "\u5BFC\u51FA\u5F02\u5E38" });
|
|
1934
|
+
} finally {
|
|
1935
|
+
setExporting(false);
|
|
1936
|
+
}
|
|
1937
|
+
};
|
|
1938
|
+
const handleFileChange = async (e) => {
|
|
1939
|
+
const file = e.target?.files?.[0];
|
|
1940
|
+
if (!file) return;
|
|
1941
|
+
setImporting(true);
|
|
1942
|
+
setMsg(null);
|
|
1943
|
+
try {
|
|
1944
|
+
const text = await file.text();
|
|
1945
|
+
const backup = JSON.parse(text);
|
|
1946
|
+
const r = await rpcCall(BRIDGE_ENDPOINTS.importBackup, { backup });
|
|
1947
|
+
if (r?.ok) {
|
|
1948
|
+
setMsg({ ok: true, text: "\u2713 \u914D\u7F6E\u5DF2\u6210\u529F\u5BFC\u5165\u5E76\u5237\u65B0\u751F\u6548\uFF01" });
|
|
1949
|
+
onUpdate?.(r.value?.status);
|
|
1950
|
+
} else {
|
|
1951
|
+
setMsg({ ok: false, text: r?.error?.message || "\u5BFC\u5165\u914D\u7F6E\u5931\u8D25" });
|
|
1952
|
+
}
|
|
1953
|
+
} catch (err) {
|
|
1954
|
+
setMsg({ ok: false, text: `\u5BFC\u5165\u89E3\u6790\u5931\u8D25: ${err.message}` });
|
|
1955
|
+
} finally {
|
|
1956
|
+
setImporting(false);
|
|
1957
|
+
if (fileInputRef.current) fileInputRef.current.value = "";
|
|
1958
|
+
}
|
|
1959
|
+
};
|
|
1688
1960
|
return React.createElement(
|
|
1689
1961
|
"div",
|
|
1690
|
-
{ style: {
|
|
1691
|
-
React.createElement(
|
|
1962
|
+
{ style: { ...s.card, marginBottom: 16 } },
|
|
1963
|
+
React.createElement(
|
|
1964
|
+
"div",
|
|
1965
|
+
{ style: { marginBottom: 10 } },
|
|
1966
|
+
React.createElement(
|
|
1967
|
+
"div",
|
|
1968
|
+
{ style: { ...s.label, fontSize: 13, display: "flex", alignItems: "center", gap: 6 } },
|
|
1969
|
+
"\u{1F5C4}\uFE0F \u5168\u5C40\u914D\u7F6E\u5907\u4EFD\u4E0E\u6062\u590D"
|
|
1970
|
+
),
|
|
1971
|
+
React.createElement(
|
|
1972
|
+
"div",
|
|
1973
|
+
{ style: { ...s.muted, marginTop: 3 } },
|
|
1974
|
+
"\u652F\u6301\u4E00\u952E\u5BFC\u51FA\u6216\u5BFC\u5165\u6062\u590D\u672C\u63D2\u4EF6\u6240\u6709\u914D\u7F6E\uFF08\u5305\u542B\u5404 IM \u5E73\u53F0\u51ED\u8BC1\u3001\u6388\u6743\u767D\u540D\u5355\u3001\u516C\u7F51\u96A7\u9053\u4E0E\u5B89\u5168\u8BA4\u8BC1\u89C4\u5219\uFF09\u3002"
|
|
1975
|
+
)
|
|
1976
|
+
),
|
|
1977
|
+
React.createElement(
|
|
1978
|
+
"div",
|
|
1979
|
+
{ style: { display: "flex", gap: 10, alignItems: "center", flexWrap: "wrap" } },
|
|
1980
|
+
React.createElement("button", {
|
|
1981
|
+
type: "button",
|
|
1982
|
+
style: { ...s.btnPri, height: 32, fontSize: 12, padding: "0 14px" },
|
|
1983
|
+
onClick: handleExport,
|
|
1984
|
+
disabled: exporting || importing
|
|
1985
|
+
}, exporting ? "\u6B63\u5728\u5BFC\u51FA\u2026" : "\u{1F4E5} \u5BFC\u51FA\u914D\u7F6E\u5907\u4EFD (.json)"),
|
|
1986
|
+
React.createElement("button", {
|
|
1987
|
+
type: "button",
|
|
1988
|
+
style: { ...s.btnGhost, height: 32, fontSize: 12, padding: "0 14px" },
|
|
1989
|
+
onClick: () => fileInputRef.current?.click(),
|
|
1990
|
+
disabled: exporting || importing
|
|
1991
|
+
}, importing ? "\u6B63\u5728\u5BFC\u5165\u2026" : "\u{1F4E4} \u5BFC\u5165\u914D\u7F6E\u6062\u590D"),
|
|
1992
|
+
React.createElement("input", {
|
|
1993
|
+
type: "file",
|
|
1994
|
+
ref: fileInputRef,
|
|
1995
|
+
accept: ".json",
|
|
1996
|
+
style: { display: "none" },
|
|
1997
|
+
onChange: handleFileChange
|
|
1998
|
+
})
|
|
1999
|
+
),
|
|
2000
|
+
msg && React.createElement("div", {
|
|
1692
2001
|
style: {
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
color: "var(--dsw-alias-label-secondary,#6b7280)",
|
|
1696
|
-
flex: 1,
|
|
1697
|
-
minWidth: 0,
|
|
1698
|
-
wordBreak: "break-all",
|
|
1699
|
-
background: "var(--dsw-alias-bg-layer-1,#ffffff)",
|
|
1700
|
-
padding: "4px 8px",
|
|
2002
|
+
marginTop: 10,
|
|
2003
|
+
padding: "6px 12px",
|
|
1701
2004
|
borderRadius: 6,
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
2005
|
+
fontSize: 12,
|
|
2006
|
+
background: msg.ok ? "var(--dsw-alias-state-success-bg,#ecfdf5)" : "var(--dsw-alias-state-error-bg,#fef2f2)",
|
|
2007
|
+
color: msg.ok ? "var(--dsw-alias-state-success-primary,#059669)" : "var(--dsw-alias-state-error-primary,#dc2626)"
|
|
2008
|
+
}
|
|
2009
|
+
}, msg.text)
|
|
2010
|
+
);
|
|
2011
|
+
}
|
|
2012
|
+
function RestartDshCard({ rpcCall }) {
|
|
2013
|
+
const [restarting, setRestarting] = React.useState(false);
|
|
2014
|
+
const [status, setStatus] = React.useState(null);
|
|
2015
|
+
const handleRestart = async () => {
|
|
2016
|
+
setRestarting(true);
|
|
2017
|
+
setStatus({ phase: "restarting", text: "\u6B63\u5728\u5411 DSH \u670D\u52A1\u53D1\u9001\u91CD\u542F\u6307\u4EE4\u2026" });
|
|
2018
|
+
try {
|
|
2019
|
+
await rpcCall(BRIDGE_ENDPOINTS.restartDsh, {});
|
|
2020
|
+
} catch {
|
|
2021
|
+
}
|
|
2022
|
+
setStatus({ phase: "reconnecting", text: "DSH \u670D\u52A1\u6B63\u5728\u91CD\u542F\u4E2D\uFF0C\u6B63\u5728\u81EA\u52A8\u91CD\u65B0\u8FDE\u63A5\u2026" });
|
|
2023
|
+
await new Promise((r) => setTimeout(r, 2e3));
|
|
2024
|
+
let attempts = 0;
|
|
2025
|
+
const maxAttempts = 30;
|
|
2026
|
+
const pollHealth = setInterval(async () => {
|
|
2027
|
+
attempts++;
|
|
2028
|
+
try {
|
|
2029
|
+
const r = await rpcCall(BRIDGE_ENDPOINTS.checkVersion, {});
|
|
2030
|
+
if (r?.ok) {
|
|
2031
|
+
clearInterval(pollHealth);
|
|
2032
|
+
setStatus({ phase: "success", text: "\u{1F389} \u91CD\u542F\u6210\u529F\uFF01\u5DF2\u91CD\u65B0\u5EFA\u7ACB\u8FDE\u63A5\uFF0C\u6B63\u5728\u5237\u65B0\u9875\u9762\u2026" });
|
|
2033
|
+
setTimeout(() => {
|
|
2034
|
+
window.location.reload();
|
|
2035
|
+
}, 1e3);
|
|
2036
|
+
return;
|
|
2037
|
+
}
|
|
2038
|
+
} catch {
|
|
2039
|
+
}
|
|
2040
|
+
if (attempts >= maxAttempts) {
|
|
2041
|
+
clearInterval(pollHealth);
|
|
2042
|
+
setStatus({ phase: "timeout", text: "\u91CD\u8FDE\u7B49\u5F85\u8D85\u65F6\uFF0C\u8BF7\u624B\u52A8\u5237\u65B0\u9875\u9762\u3002" });
|
|
2043
|
+
setRestarting(false);
|
|
2044
|
+
}
|
|
2045
|
+
}, 1e3);
|
|
2046
|
+
};
|
|
2047
|
+
return React.createElement(
|
|
2048
|
+
"div",
|
|
2049
|
+
{ style: { ...s.card, marginBottom: 16 } },
|
|
2050
|
+
React.createElement(
|
|
2051
|
+
"div",
|
|
2052
|
+
{ style: { marginBottom: 10 } },
|
|
2053
|
+
React.createElement(
|
|
2054
|
+
"div",
|
|
2055
|
+
{ style: { ...s.label, fontSize: 13, display: "flex", alignItems: "center", gap: 6 } },
|
|
2056
|
+
"\u{1F504} DSH \u670D\u52A1\u5E73\u6ED1\u91CD\u542F"
|
|
2057
|
+
),
|
|
2058
|
+
React.createElement(
|
|
2059
|
+
"div",
|
|
2060
|
+
{ style: { ...s.muted, marginTop: 3 } },
|
|
2061
|
+
"\u4F18\u96C5\u9000\u51FA\u5E76\u91CD\u65B0\u62C9\u8D77\u5F53\u524D DSH \u8FDB\u7A0B\u4E0E\u6240\u6709\u63D2\u4EF6\u670D\u52A1\uFF0C\u524D\u7AEF\u5C06\u5728\u51E0\u79D2\u540E\u81EA\u52A8\u63A2\u6D4B\u91CD\u8FDE\u5E76\u5237\u65B0\u9875\u9762\u3002"
|
|
2062
|
+
)
|
|
2063
|
+
),
|
|
2064
|
+
!restarting && !status && React.createElement("button", {
|
|
2065
|
+
type: "button",
|
|
2066
|
+
style: { ...s.btnGhost, height: 32, fontSize: 12, padding: "0 14px" },
|
|
2067
|
+
onClick: handleRestart
|
|
2068
|
+
}, "\u{1F504} \u7ACB\u5373\u91CD\u542F DSH \u670D\u52A1"),
|
|
2069
|
+
(restarting || status) && React.createElement(
|
|
2070
|
+
"div",
|
|
2071
|
+
{
|
|
2072
|
+
style: {
|
|
2073
|
+
display: "flex",
|
|
2074
|
+
alignItems: "center",
|
|
2075
|
+
gap: 8,
|
|
2076
|
+
fontSize: 12,
|
|
2077
|
+
color: status?.phase === "success" ? "var(--dsw-alias-state-success-primary, #059669)" : status?.phase === "timeout" ? "var(--dsw-alias-state-error-primary, #dc2626)" : "var(--dsw-alias-state-info-primary, #2563eb)",
|
|
2078
|
+
fontWeight: 500
|
|
2079
|
+
}
|
|
2080
|
+
},
|
|
2081
|
+
status?.phase !== "success" && status?.phase !== "timeout" && React.createElement("span", {
|
|
2082
|
+
style: { animation: "spin 1s linear infinite", display: "inline-flex" }
|
|
2083
|
+
}, React.createElement(Icons.refresh)),
|
|
2084
|
+
status?.text || "\u6B63\u5728\u8C03\u5EA6\u2026"
|
|
2085
|
+
)
|
|
1710
2086
|
);
|
|
1711
2087
|
}
|
|
1712
2088
|
function VersionBanner({ rpcCall }) {
|
|
@@ -1715,6 +2091,9 @@ function VersionBanner({ rpcCall }) {
|
|
|
1715
2091
|
const [upgrading, setUpgrading] = React.useState(false);
|
|
1716
2092
|
const [upgradeResult, setUpgradeResult] = React.useState(null);
|
|
1717
2093
|
const [showManual, setShowManual] = React.useState(false);
|
|
2094
|
+
const [restarting, setRestarting] = React.useState(false);
|
|
2095
|
+
const [restartStatus, setRestartStatus] = React.useState(null);
|
|
2096
|
+
const [dismissRestart, setDismissRestart] = React.useState(false);
|
|
1718
2097
|
const check = React.useCallback(async () => {
|
|
1719
2098
|
setLoading(true);
|
|
1720
2099
|
try {
|
|
@@ -1733,11 +2112,12 @@ function VersionBanner({ rpcCall }) {
|
|
|
1733
2112
|
if (!info?.latest || upgrading) return;
|
|
1734
2113
|
setUpgrading(true);
|
|
1735
2114
|
setUpgradeResult(null);
|
|
2115
|
+
setDismissRestart(false);
|
|
2116
|
+
setRestartStatus(null);
|
|
1736
2117
|
try {
|
|
1737
2118
|
const r = await rpcCall(BRIDGE_ENDPOINTS.upgradePlugin, { version: info.latest });
|
|
1738
2119
|
if (r?.ok && r.value?.ok) {
|
|
1739
|
-
setUpgradeResult({ ok: true, message: `\u5DF2\u6210\u529F\u5347\u7EA7\u5230 v${info.latest}\uFF01
|
|
1740
|
-
setTimeout(() => check(), 3e3);
|
|
2120
|
+
setUpgradeResult({ ok: true, message: `\u5DF2\u6210\u529F\u5347\u7EA7\u5230 v${info.latest}\uFF01` });
|
|
1741
2121
|
} else {
|
|
1742
2122
|
setUpgradeResult({ ok: false, message: r?.value?.error || r?.error?.message || "\u5347\u7EA7\u5931\u8D25" });
|
|
1743
2123
|
setShowManual(true);
|
|
@@ -1748,10 +2128,42 @@ function VersionBanner({ rpcCall }) {
|
|
|
1748
2128
|
} finally {
|
|
1749
2129
|
setUpgrading(false);
|
|
1750
2130
|
}
|
|
1751
|
-
}, [info?.latest, upgrading, rpcCall
|
|
2131
|
+
}, [info?.latest, upgrading, rpcCall]);
|
|
2132
|
+
const handleRestart = React.useCallback(async () => {
|
|
2133
|
+
setRestarting(true);
|
|
2134
|
+
setRestartStatus({ phase: "restarting", text: "\u6B63\u5728\u8C03\u5EA6 DSH \u670D\u52A1\u91CD\u542F\u2026" });
|
|
2135
|
+
try {
|
|
2136
|
+
await rpcCall(BRIDGE_ENDPOINTS.restartDsh, {});
|
|
2137
|
+
} catch {
|
|
2138
|
+
}
|
|
2139
|
+
setRestartStatus({ phase: "reconnecting", text: "DSH \u670D\u52A1\u6B63\u5728\u91CD\u542F\u4E2D\uFF0C\u6B63\u5728\u81EA\u52A8\u91CD\u65B0\u8FDE\u63A5\u2026" });
|
|
2140
|
+
await new Promise((r) => setTimeout(r, 2e3));
|
|
2141
|
+
let attempts = 0;
|
|
2142
|
+
const maxAttempts = 30;
|
|
2143
|
+
const pollHealth = setInterval(async () => {
|
|
2144
|
+
attempts++;
|
|
2145
|
+
try {
|
|
2146
|
+
const r = await rpcCall(BRIDGE_ENDPOINTS.checkVersion, {});
|
|
2147
|
+
if (r?.ok) {
|
|
2148
|
+
clearInterval(pollHealth);
|
|
2149
|
+
setRestartStatus({ phase: "success", text: "\u{1F389} \u91CD\u542F\u6210\u529F\uFF01\u5DF2\u81EA\u52A8\u52A0\u8F7D\u6700\u65B0\u7248\u672C\u3002\u6B63\u5728\u5237\u65B0\u9875\u9762\u2026" });
|
|
2150
|
+
setTimeout(() => {
|
|
2151
|
+
window.location.reload();
|
|
2152
|
+
}, 1e3);
|
|
2153
|
+
return;
|
|
2154
|
+
}
|
|
2155
|
+
} catch {
|
|
2156
|
+
}
|
|
2157
|
+
if (attempts >= maxAttempts) {
|
|
2158
|
+
clearInterval(pollHealth);
|
|
2159
|
+
setRestartStatus({ phase: "timeout", text: "\u91CD\u8FDE\u7B49\u5F85\u8D85\u65F6\uFF0C\u8BF7\u624B\u52A8\u5237\u65B0\u9875\u9762\u3002" });
|
|
2160
|
+
setRestarting(false);
|
|
2161
|
+
}
|
|
2162
|
+
}, 1e3);
|
|
2163
|
+
}, [rpcCall]);
|
|
1752
2164
|
const links = React.createElement(
|
|
1753
2165
|
"div",
|
|
1754
|
-
{ style: { display: "flex", gap:
|
|
2166
|
+
{ style: { display: "flex", gap: 10, alignItems: "center", flexWrap: "wrap" } },
|
|
1755
2167
|
React.createElement("a", {
|
|
1756
2168
|
href: GITHUB_URL,
|
|
1757
2169
|
target: "_blank",
|
|
@@ -1826,7 +2238,7 @@ function VersionBanner({ rpcCall }) {
|
|
|
1826
2238
|
gap: 4
|
|
1827
2239
|
},
|
|
1828
2240
|
onClick: check,
|
|
1829
|
-
disabled: loading || upgrading,
|
|
2241
|
+
disabled: loading || upgrading || restarting,
|
|
1830
2242
|
title: "\u91CD\u65B0\u68C0\u67E5 npm \u7EBF\u4E0A\u7248\u672C"
|
|
1831
2243
|
},
|
|
1832
2244
|
React.createElement(Icons.refresh),
|
|
@@ -1874,17 +2286,17 @@ function VersionBanner({ rpcCall }) {
|
|
|
1874
2286
|
fontSize: 12,
|
|
1875
2287
|
padding: "0 14px",
|
|
1876
2288
|
background: upgradeResult?.ok ? "var(--dsw-alias-state-success-primary,#059669)" : "var(--dsw-alias-brand-primary,#4f6ef7)",
|
|
1877
|
-
opacity: upgrading ? 0.6 : 1
|
|
2289
|
+
opacity: upgrading || restarting ? 0.6 : 1
|
|
1878
2290
|
},
|
|
1879
2291
|
onClick: handleUpgrade,
|
|
1880
|
-
disabled: upgrading || upgradeResult?.ok
|
|
2292
|
+
disabled: upgrading || restarting || upgradeResult?.ok
|
|
1881
2293
|
},
|
|
1882
2294
|
upgrading ? React.createElement(
|
|
1883
2295
|
"span",
|
|
1884
2296
|
{ style: { display: "inline-flex", alignItems: "center", gap: 6 } },
|
|
1885
2297
|
React.createElement("span", { style: { animation: "spin 1s linear infinite", display: "inline-flex" } }, React.createElement(Icons.refresh)),
|
|
1886
2298
|
"\u6B63\u5728\u81EA\u52A8\u5347\u7EA7\u2026"
|
|
1887
|
-
) : upgradeResult?.ok ? "\u2713 \
|
|
2299
|
+
) : upgradeResult?.ok ? "\u2713 \u5347\u7EA7\u5B8C\u6210" : `\u4E00\u952E\u5347\u7EA7\u5230 v${info.latest}`
|
|
1888
2300
|
)
|
|
1889
2301
|
),
|
|
1890
2302
|
// 简短更新内容 / Release Notes 亮点展示
|
|
@@ -1893,9 +2305,9 @@ function VersionBanner({ rpcCall }) {
|
|
|
1893
2305
|
{
|
|
1894
2306
|
style: {
|
|
1895
2307
|
fontSize: 12,
|
|
1896
|
-
color: "var(--dsw-alias-label-
|
|
1897
|
-
background: "rgba(255, 255, 255, 0.
|
|
1898
|
-
border: "1px solid rgba(191, 219, 254, 0.
|
|
2308
|
+
color: "var(--dsw-alias-label-primary, #374151)",
|
|
2309
|
+
background: "var(--dsw-alias-bg-layer-2, rgba(255, 255, 255, 0.85))",
|
|
2310
|
+
border: "1px solid var(--dsw-alias-state-info-border, rgba(191, 219, 254, 0.8))",
|
|
1899
2311
|
borderRadius: 8,
|
|
1900
2312
|
padding: "8px 12px",
|
|
1901
2313
|
marginBottom: 10,
|
|
@@ -1903,14 +2315,78 @@ function VersionBanner({ rpcCall }) {
|
|
|
1903
2315
|
whiteSpace: "pre-line"
|
|
1904
2316
|
}
|
|
1905
2317
|
},
|
|
1906
|
-
React.createElement("div", { style: { fontWeight: 600, color: "var(--dsw-alias-state-info-primary
|
|
2318
|
+
React.createElement("div", { style: { fontWeight: 600, color: "var(--dsw-alias-state-info-primary, #2563eb)", marginBottom: 2 } }, "\u2728 \u66F4\u65B0\u4EAE\u70B9\uFF1A"),
|
|
1907
2319
|
info.releaseNotes
|
|
1908
2320
|
),
|
|
1909
|
-
|
|
2321
|
+
// 升级成功后:引导重启 DSH 操作卡片
|
|
2322
|
+
upgradeResult?.ok && !dismissRestart && React.createElement(
|
|
2323
|
+
"div",
|
|
2324
|
+
{
|
|
2325
|
+
style: {
|
|
2326
|
+
background: "var(--dsw-alias-bg-layer-2, rgba(255, 255, 255, 0.95))",
|
|
2327
|
+
border: "1px solid var(--dsw-alias-state-success-border, #a7f3d0)",
|
|
2328
|
+
borderRadius: 8,
|
|
2329
|
+
padding: "12px 14px",
|
|
2330
|
+
marginBottom: 10
|
|
2331
|
+
}
|
|
2332
|
+
},
|
|
2333
|
+
React.createElement(
|
|
2334
|
+
"div",
|
|
2335
|
+
{ style: { display: "flex", alignItems: "center", gap: 8, marginBottom: 8 } },
|
|
2336
|
+
React.createElement("span", { style: { fontSize: 16 } }, "\u2728"),
|
|
2337
|
+
React.createElement("span", {
|
|
2338
|
+
style: { fontSize: 13, fontWeight: 600, color: "var(--dsw-alias-state-success-primary, #059669)" }
|
|
2339
|
+
}, `\u5DF2\u6210\u529F\u5347\u7EA7\u5230 v${info.latest}\uFF01\u9700\u8981\u91CD\u542F DSH \u670D\u52A1\u4F7F\u65B0\u7248\u672C\u751F\u6548`)
|
|
2340
|
+
),
|
|
2341
|
+
!restarting && !restartStatus && React.createElement(
|
|
2342
|
+
"div",
|
|
2343
|
+
{
|
|
2344
|
+
style: { display: "flex", gap: 8, alignItems: "center", flexWrap: "wrap" }
|
|
2345
|
+
},
|
|
2346
|
+
React.createElement("button", {
|
|
2347
|
+
style: {
|
|
2348
|
+
...s.btnPri,
|
|
2349
|
+
height: 30,
|
|
2350
|
+
fontSize: 12,
|
|
2351
|
+
padding: "0 14px",
|
|
2352
|
+
background: "var(--dsw-alias-state-success-primary, #059669)"
|
|
2353
|
+
},
|
|
2354
|
+
onClick: handleRestart
|
|
2355
|
+
}, "\u{1F504} \u7ACB\u5373\u91CD\u542F DSH \u670D\u52A1"),
|
|
2356
|
+
React.createElement("button", {
|
|
2357
|
+
style: {
|
|
2358
|
+
...s.btnGhost,
|
|
2359
|
+
height: 30,
|
|
2360
|
+
fontSize: 12,
|
|
2361
|
+
padding: "0 12px"
|
|
2362
|
+
},
|
|
2363
|
+
onClick: () => setDismissRestart(true)
|
|
2364
|
+
}, "\u7A0D\u540E\u624B\u52A8\u91CD\u542F")
|
|
2365
|
+
),
|
|
2366
|
+
(restarting || restartStatus) && React.createElement(
|
|
2367
|
+
"div",
|
|
2368
|
+
{
|
|
2369
|
+
style: {
|
|
2370
|
+
display: "flex",
|
|
2371
|
+
alignItems: "center",
|
|
2372
|
+
gap: 8,
|
|
2373
|
+
fontSize: 12,
|
|
2374
|
+
color: restartStatus?.phase === "success" ? "var(--dsw-alias-state-success-primary, #059669)" : restartStatus?.phase === "timeout" ? "var(--dsw-alias-state-error-primary, #dc2626)" : "var(--dsw-alias-state-info-primary, #2563eb)",
|
|
2375
|
+
fontWeight: 500
|
|
2376
|
+
}
|
|
2377
|
+
},
|
|
2378
|
+
restartStatus?.phase !== "success" && restartStatus?.phase !== "timeout" && React.createElement("span", {
|
|
2379
|
+
style: { animation: "spin 1s linear infinite", display: "inline-flex" }
|
|
2380
|
+
}, React.createElement(Icons.refresh)),
|
|
2381
|
+
restartStatus?.text || "\u6B63\u5728\u5904\u7406\u2026"
|
|
2382
|
+
)
|
|
2383
|
+
),
|
|
2384
|
+
// 失败提示
|
|
2385
|
+
upgradeResult && !upgradeResult.ok && React.createElement("div", {
|
|
1910
2386
|
style: {
|
|
1911
|
-
background:
|
|
1912
|
-
border:
|
|
1913
|
-
color:
|
|
2387
|
+
background: "var(--dsw-alias-state-error-bg,#fef2f2)",
|
|
2388
|
+
border: "1px solid var(--dsw-alias-state-error-border,#fecaca)",
|
|
2389
|
+
color: "var(--dsw-alias-state-error-primary,#991b1b)",
|
|
1914
2390
|
padding: "8px 12px",
|
|
1915
2391
|
borderRadius: 6,
|
|
1916
2392
|
fontSize: 12,
|
|
@@ -1944,12 +2420,14 @@ var TABS = [
|
|
|
1944
2420
|
{ id: "lan", label: "\u5C40\u57DF\u7F51", icon: Icons.lan },
|
|
1945
2421
|
{ id: "tunnel", label: "\u516C\u7F51\u96A7\u9053", icon: Icons.tunnel },
|
|
1946
2422
|
{ id: "im", label: "IM \u673A\u5668\u4EBA", icon: Icons.bot },
|
|
1947
|
-
{ id: "security", label: "\u5B89\u5168\u8BA4\u8BC1", icon: Icons.security }
|
|
2423
|
+
{ id: "security", label: "\u5B89\u5168\u8BA4\u8BC1", icon: Icons.security },
|
|
2424
|
+
{ id: "ops", label: "\u8FD0\u7EF4\u76D1\u63A7", icon: Icons.ops }
|
|
1948
2425
|
];
|
|
1949
2426
|
function TabBar({ active, onChange, dots }) {
|
|
1950
2427
|
return React.createElement(
|
|
1951
2428
|
"div",
|
|
1952
2429
|
{
|
|
2430
|
+
className: "dsh-tabbar-container",
|
|
1953
2431
|
style: {
|
|
1954
2432
|
display: "flex",
|
|
1955
2433
|
gap: 4,
|
|
@@ -1958,7 +2436,9 @@ function TabBar({ active, onChange, dots }) {
|
|
|
1958
2436
|
overflowX: "auto",
|
|
1959
2437
|
WebkitOverflowScrolling: "touch",
|
|
1960
2438
|
maxWidth: "100%",
|
|
1961
|
-
flexWrap: "nowrap"
|
|
2439
|
+
flexWrap: "nowrap",
|
|
2440
|
+
scrollbarWidth: "none",
|
|
2441
|
+
msOverflowStyle: "none"
|
|
1962
2442
|
}
|
|
1963
2443
|
},
|
|
1964
2444
|
TABS.map(({ id, label, icon: TabIcon }) => {
|
|
@@ -2276,6 +2756,18 @@ function BridgePanel({ rpcCall }) {
|
|
|
2276
2756
|
rpcCall: authRpcCall,
|
|
2277
2757
|
onUpdate: () => load(true)
|
|
2278
2758
|
});
|
|
2759
|
+
} else if (activeTab === "ops") {
|
|
2760
|
+
tabContent = React.createElement(
|
|
2761
|
+
React.Fragment,
|
|
2762
|
+
null,
|
|
2763
|
+
React.createElement(SystemMetricsWidget, { metrics: status?.system }),
|
|
2764
|
+
React.createElement(NetworkDiagnosticWidget, { rpcCall: authRpcCall }),
|
|
2765
|
+
React.createElement(BackupRestoreWidget, {
|
|
2766
|
+
rpcCall: authRpcCall,
|
|
2767
|
+
onUpdate: () => load(true)
|
|
2768
|
+
}),
|
|
2769
|
+
React.createElement(RestartDshCard, { rpcCall: authRpcCall })
|
|
2770
|
+
);
|
|
2279
2771
|
} else if (activeTab === "im") {
|
|
2280
2772
|
const IM_PLATFORMS = [
|
|
2281
2773
|
{ id: "wechat", label: "\u5FAE\u4FE1", icon: Icons.wechat, brandColor: "#07C160", desc: "ClawBot \u626B\u7801\u76F4\u8FDE \xB7 \u65E0\u9700\u516C\u7F51" },
|
|
@@ -2646,6 +3138,17 @@ function injectMobileStyles() {
|
|
|
2646
3138
|
const style = document.createElement("style");
|
|
2647
3139
|
style.id = "dsh-bridge-mobile-styles";
|
|
2648
3140
|
style.textContent = `
|
|
3141
|
+
/* DSH Bridge \u9690\u85CF Tab \u680F\u539F\u751F\u6EDA\u52A8\u6761\u5E76\u4FDD\u6301\u5E73\u6ED1\u6ED1\u52A8 */
|
|
3142
|
+
.dsh-tabbar-container {
|
|
3143
|
+
scrollbar-width: none !important;
|
|
3144
|
+
-ms-overflow-style: none !important;
|
|
3145
|
+
}
|
|
3146
|
+
.dsh-tabbar-container::-webkit-scrollbar {
|
|
3147
|
+
display: none !important;
|
|
3148
|
+
width: 0 !important;
|
|
3149
|
+
height: 0 !important;
|
|
3150
|
+
}
|
|
3151
|
+
|
|
2649
3152
|
/* DSH Bridge \u79FB\u52A8\u7AEF\u81EA\u9002\u5E94\u4E0E\u89E6\u63A7\u4EA4\u4E92\u589E\u5F3A\u6837\u5F0F */
|
|
2650
3153
|
:root {
|
|
2651
3154
|
--dsh-mobile-header-h: 52px;
|