feat: standard plugin client module — standalone DSHWatch settings section (settings.section) + ./client export + dsh.client
This commit is contained in:
+106
@@ -0,0 +1,106 @@
|
||||
/* eslint-disable */
|
||||
// DSHWatch 客户端插件:在 DSH 设置里注册一个一级「DSHWatch 设置」入口。
|
||||
// 浏览器端模块(window.__ModuleLoader__ 格式),由 DSH 客户端加载。
|
||||
window.__ModuleLoader__.load({
|
||||
id: "dsh-watch-client",
|
||||
factory: (require) => {
|
||||
var module = { exports: {} };
|
||||
var exports = module.exports;
|
||||
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
||||
for (const p of ["react", "react/jsx-runtime"]) { const r = require(p); if (p.indexOf("jsx") >= 0) { module["reactJsx"] = r; } else { module["react"] = r; } }
|
||||
const React = module["react"];
|
||||
const { jsx, jsxs } = module["reactJsx"];
|
||||
|
||||
const NS = "dsh-watch";
|
||||
const FIELDS = [
|
||||
["mode", "模式", "relay | direct"],
|
||||
["serverUrl", "服务器地址", "ws://host:port"],
|
||||
["userId", "用户ID", "userId"],
|
||||
["token", "Token", "token"],
|
||||
["apiKey", "DeepSeek API Key", "sk-..."],
|
||||
["host", "监听地址", "0.0.0.0"],
|
||||
["port", "端口", "18321"],
|
||||
["reconnectMs", "重连毫秒", "5000"],
|
||||
["timeoutMs", "超时毫秒", "30000"]
|
||||
];
|
||||
|
||||
function messageOf(error) {
|
||||
return error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
||||
// 配置表单:读取/保存 dsh-watch 命名空间设置
|
||||
function Section({ api }) {
|
||||
const [values, setValues] = React.useState({});
|
||||
const [error, setError] = React.useState(null);
|
||||
const [saved, setSaved] = React.useState(false);
|
||||
React.useEffect(() => {
|
||||
let alive = true;
|
||||
api.settings.get({ ns: NS }).then((res) => {
|
||||
if (!alive) return;
|
||||
if (res && res.result && res.result.ok) {
|
||||
setValues(res.result.value || {});
|
||||
} else {
|
||||
setError(res && res.result ? res.result.error.message : "读取失败");
|
||||
}
|
||||
}).catch((e) => { if (alive) setError(messageOf(e)); });
|
||||
return () => { alive = false; };
|
||||
}, [api]);
|
||||
|
||||
const set = (k, v) => { setValues((prev) => ({ ...prev, [k]: v })); setSaved(false); };
|
||||
|
||||
const save = async () => {
|
||||
setSaved(false);
|
||||
try {
|
||||
const res = await api.settings.update({ ns: NS, patch: values });
|
||||
if (res && res.result && res.result.ok) { setSaved(true); setError(null); }
|
||||
else setError(res && res.result ? res.result.error.message : "保存失败");
|
||||
} catch (e) { setError(messageOf(e)); }
|
||||
};
|
||||
|
||||
const row = ([key, label, ph]) => jsxs("label", { style: { display: "flex", flexDirection: "column", gap: 4, marginBottom: 12 }, children: [
|
||||
jsx("span", { children: label, style: { fontSize: 12, color: "var(--dsw-alias-label-secondary)" } }),
|
||||
jsx("input", {
|
||||
value: values[key] === void 0 ? "" : String(values[key]),
|
||||
placeholder: ph,
|
||||
onChange: (e) => set(key, e.target.value),
|
||||
style: { padding: 8, borderRadius: 6, border: "1px solid var(--dsw-alias-border-l2)", background: "var(--dsw-alias-bg-module-platform)", color: "var(--dsw-alias-label-primary)" }
|
||||
})
|
||||
] });
|
||||
|
||||
return jsxs("div", { children: [
|
||||
jsx("h2", { children: "DSHWatch 设置", style: { fontSize: 16, margin: "0 0 8px" } }),
|
||||
jsx("p", { children: "手机/手表远程控制 DeepSeek Harness 的配置。", style: { fontSize: 12, color: "var(--dsw-alias-label-tertiary)" } }),
|
||||
jsxs("div", { children: [
|
||||
...FIELDS.map((f) => row(f))
|
||||
] }),
|
||||
error ? jsx("p", { children: String(error), style: { color: "var(--dsw-danger)", fontSize: 12 } }) : null,
|
||||
jsxs("div", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [
|
||||
jsxs("button", { type: "button", onClick: save, style: { padding: "8px 14px", borderRadius: 8, border: "none", background: "var(--dsw-alias-interactive-bg-default)", color: "var(--dsw-alias-label-primary)", cursor: "pointer" }, children: ["保存"] }),
|
||||
saved ? jsx("span", { children: "已保存 ✓", style: { fontSize: 12, color: "var(--dsw-alias-label-secondary)" } }) : null
|
||||
] })
|
||||
] });
|
||||
}
|
||||
|
||||
// 注入:连接 API 等
|
||||
const inject = ["slots", "locale", "connection", "remote", "settingsScope"];
|
||||
|
||||
function apply(ctx) {
|
||||
ctx.inject(["slots", "locale", "connection", "remote", "settingsScope"], (scope) => {
|
||||
const api = scope.get("connection").api;
|
||||
const injected = () => ({ api });
|
||||
scope.slots.register({
|
||||
name: "settings.section",
|
||||
id: "dsh-watch",
|
||||
order: 30,
|
||||
label: () => "DSHWatch 设置",
|
||||
locale: "dsh-watch.settings",
|
||||
inject: injected
|
||||
}, Section);
|
||||
});
|
||||
}
|
||||
|
||||
exports.apply = apply;
|
||||
exports.inject = inject;
|
||||
return module.exports;
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user