@mrrisega/dsh-remote 0.7.2-beta.1 → 0.7.2-beta.2
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/clients/dsh-remote/mobile-adapter.mjs +236 -22
- package/clients/dsh-remote/test/mobile-adapter-guards.test.mjs +31 -11
- package/clients/dsh-remote/test/mobile-adapter-load-watch.test.mjs +408 -0
- package/package.json +1 -1
- package/packages/dsh-remote-web/lib/client.js +152 -155
- package/packages/dsh-remote-web/lib/index.js +396 -14
- package/packages/dsh-remote-web/package.json +1 -1
- package/packages/dsh-remote-web/runtime/clients/dsh-remote/mobile-adapter.mjs +236 -22
- package/packages/dsh-remote-web/test/announcements-ui.test.mjs +6 -3
- package/packages/dsh-remote-web/test/desktop-compat.test.mjs +12 -6
- package/packages/dsh-remote-web/test/remote-access-ui.test.mjs +116 -3
- package/packages/dsh-remote-web/test/repair-backup.test.mjs +599 -0
|
@@ -246,7 +246,12 @@ window.__ModuleLoader__.load({
|
|
|
246
246
|
".dru-captcha .dru-input{flex:1;min-width:0}",
|
|
247
247
|
".dru-captcha-box{width:118px;height:44px;flex:none;border-radius:8px;border:1px solid var(--dru-border-ctl);cursor:pointer;background:var(--dru-surface);display:flex;align-items:center;justify-content:center;font-size:12px;color:var(--dru-fg-muted);overflow:hidden}",
|
|
248
248
|
".dru-captcha-box svg{display:block;width:100%;height:100%}",
|
|
249
|
-
".dru-user{display:flex;align-items:center;gap:10px;margin-bottom:12px}",
|
|
249
|
+
".dru-user{display:flex;align-items:center;gap:10px;margin-bottom:12px;flex-wrap:wrap}",
|
|
250
|
+
// 退出登录:跟着账号行走(业主 2026-10-17),右侧对齐、次要视觉(不抢主行动):
|
|
251
|
+
// 触控目标 ≥40px、与账号信息 8px 间距;危险色但不用实底(它不是主行动)。
|
|
252
|
+
".dru-user-logout{margin-left:auto;flex:none;min-height:40px;padding:8px 12px;border:1px solid var(--dru-border-ctl);border-radius:8px;background:transparent;color:var(--dru-danger);font:500 12.5px/1.2 inherit;font-family:inherit;cursor:pointer;white-space:nowrap}",
|
|
253
|
+
".dru-user-logout:hover:not(:disabled){background:var(--dru-danger-soft);border-color:var(--dru-danger-border)}",
|
|
254
|
+
".dru-user-logout:disabled{opacity:.55;cursor:default}",
|
|
250
255
|
".dru-avatar{width:40px;height:40px;border-radius:50%;background:var(--dru-accent-fill);color:var(--dru-on-accent);display:flex;align-items:center;justify-content:center;font-size:17px;font-weight:700;flex-shrink:0}",
|
|
251
256
|
".dru-user .mail{font-size:14px;font-weight:600;color:var(--dru-fg);word-break:break-all}",
|
|
252
257
|
".dru-user .plan{font-size:12px;color:var(--dru-fg-muted);margin-top:2px}",
|
|
@@ -1368,16 +1373,6 @@ window.__ModuleLoader__.load({
|
|
|
1368
1373
|
function annReportClick(id) {
|
|
1369
1374
|
try { post("/dsh-remote/announcements/click", { id: id }).catch(function () { /* 静默:服务端才是权威 */ }); } catch (e) { /* 忽略 */ }
|
|
1370
1375
|
}
|
|
1371
|
-
/** 本地把某条标记为已读(只为了让徽标/标签立刻更新;真正的已读在服务端)。 */
|
|
1372
|
-
function annMarkReadLocal(id) {
|
|
1373
|
-
var hit = false;
|
|
1374
|
-
annState.items = annState.items.map(function (x) {
|
|
1375
|
-
if (x.id !== id || !x.unread) return x;
|
|
1376
|
-
hit = true;
|
|
1377
|
-
return Object.assign({}, x, { unread: false });
|
|
1378
|
-
});
|
|
1379
|
-
if (hit) { annState.unread = Math.max(0, annState.unread - 1); annEmit(); }
|
|
1380
|
-
}
|
|
1381
1376
|
|
|
1382
1377
|
// ── 🤖 微信机器人「命令帮助」镜像 ─────────────────────────────────────────
|
|
1383
1378
|
// ⚠️ 真身是 clients/dsh-remote/wechat-channel.mjs 的 HELP_TEXT(用户在微信里看到的唯一说明书)。
|
|
@@ -2894,7 +2889,7 @@ window.__ModuleLoader__.load({
|
|
|
2894
2889
|
var restartPending = !!restartInfo.pending;
|
|
2895
2890
|
// 宿主形态(node 半下发):桌面端(Electron)Host 由桌面应用托管,重启这个动作
|
|
2896
2891
|
// 在那边**做不到也不该做**(强行退出会弹原生致命错误)。面板据此:
|
|
2897
|
-
// ① 不自动倒计时重启;②
|
|
2892
|
+
// ① 不自动倒计时重启;② 桌面端只提示「刷新页面即可」,不引导重启/重开应用(2026-10-17)。
|
|
2898
2893
|
// 旧版 host 的响应里没有该字段 → false,行为与改动前完全一致。
|
|
2899
2894
|
// 🔴 2026-10-11 修:node 半把该字段下在 **connect** 里(`connect.desktopHost`),
|
|
2900
2895
|
// 这里以前读顶层 `st.desktopHost` → **永远 false** → 桌面端被当成 Web 版:
|
|
@@ -3988,6 +3983,55 @@ window.__ModuleLoader__.load({
|
|
|
3988
3983
|
// 「更多」里只留下面那两个**折叠的营销入口**(升级 PRO / 带新用户换会员),用户仍要它们收在这里。
|
|
3989
3984
|
// 🔒 顺带更强的一条不变量:整个面板从此不渲染任何 Mbps / GB / 价格数字
|
|
3990
3985
|
// (「已限速 / 不限速」仍由服务端 quota.limit_enabled / quota.max_mbps 驱动,但只给定性措辞)。
|
|
3986
|
+
/**
|
|
3987
|
+
* 🔧 安装/配对自检提示(2026-10-17):node 半在 /dsh-remote/status 的 `setup` 里下发
|
|
3988
|
+
* `{ kind: ok|runtime_missing|pairing_missing|all_missing, text, detail, backup? }`。
|
|
3989
|
+
*
|
|
3990
|
+
* 由来:真机事故 —— 用户本机 `~/.dsh-remote` 被误删后,面板只显示模糊的"未运行",
|
|
3991
|
+
* 用户不知道是"运行环境没了"还是"没登录",最后手机端干等 47 秒才报错。
|
|
3992
|
+
* 所以这里**必须说清结论 + 给出下一步动作**,但绝不阻塞面板其它功能。
|
|
3993
|
+
*/
|
|
3994
|
+
function renderSetupAlert() {
|
|
3995
|
+
var setup = (st && (st.setup || (st.connect && st.connect.setup))) || null;
|
|
3996
|
+
if (!setup || !setup.kind || setup.kind === "ok") return null;
|
|
3997
|
+
var backup = setup.backup && setup.backup.available ? setup.backup : null;
|
|
3998
|
+
return h("div", { className: "dru-restart-alert", role: "status", style: { marginBottom: 12 } },
|
|
3999
|
+
h("span", { className: "dru-restart-alert-icon" }, "🔧"),
|
|
4000
|
+
h("div", { style: { flex: "1" } },
|
|
4001
|
+
h("div", { className: "dru-restart-alert-title" }, setup.text || "运行环境需要处理"),
|
|
4002
|
+
setup.detail ? h("div", { className: "dru-restart-alert-sub" }, setup.detail) : null,
|
|
4003
|
+
backup ? h("div", { className: "dru-restart-alert-sub" }, backup.text || "检测到历史配对备份,可一键恢复") : null,
|
|
4004
|
+
h("div", { className: "dru-actions", style: { marginTop: 10 } },
|
|
4005
|
+
backup
|
|
4006
|
+
? h("button", {
|
|
4007
|
+
type: "button",
|
|
4008
|
+
className: "dru-btn dru-btn-primary",
|
|
4009
|
+
disabled: busy !== "",
|
|
4010
|
+
onClick: function () {
|
|
4011
|
+
var action = backup.action || {};
|
|
4012
|
+
setBusy("setup");
|
|
4013
|
+
post(action.path || "/dsh-remote/config/restore", action.body || {})
|
|
4014
|
+
.then(function (body) {
|
|
4015
|
+
if (body && body.ok) setMessage({ kind: "ok", text: "已恢复历史配对,正在重新启动 bridge…" });
|
|
4016
|
+
else setMessage({ kind: "err", text: (body && body.error && body.error.message) || "恢复失败,请重试" });
|
|
4017
|
+
if (body && body.connect) setSt(body); else refresh();
|
|
4018
|
+
})
|
|
4019
|
+
.catch(function (e) { setMessage({ kind: "err", text: "恢复失败: " + e.message }); })
|
|
4020
|
+
.finally(function () { setBusy(""); });
|
|
4021
|
+
}
|
|
4022
|
+
}, busy === "setup" ? "恢复中…" : "恢复历史配对")
|
|
4023
|
+
: null,
|
|
4024
|
+
h("button", {
|
|
4025
|
+
type: "button",
|
|
4026
|
+
className: "dru-btn dru-btn-ghost",
|
|
4027
|
+
disabled: busy !== "",
|
|
4028
|
+
onClick: function () { refresh(); }
|
|
4029
|
+
}, "刷新状态")
|
|
4030
|
+
)
|
|
4031
|
+
)
|
|
4032
|
+
);
|
|
4033
|
+
}
|
|
4034
|
+
|
|
3991
4035
|
function renderAccount() {
|
|
3992
4036
|
var a = account;
|
|
3993
4037
|
var plan = a ? a.plan : "free";
|
|
@@ -4038,17 +4082,11 @@ window.__ModuleLoader__.load({
|
|
|
4038
4082
|
var invTipOn = !invOff && !inviteTipDismissed;
|
|
4039
4083
|
var invTipRule = invTipOn ? inviteRuleOf() : null;
|
|
4040
4084
|
// 【0.6.10】营销入口「在哪一层」的四个开关(约定:新用户第一次看得见,用户关掉后收进「更多」):
|
|
4041
|
-
//
|
|
4042
|
-
//
|
|
4043
|
-
//
|
|
4044
|
-
//
|
|
4045
|
-
//
|
|
4046
|
-
// · 付费用户的按钮是「续费 / 转正式 PRO」—— 那是账号维护、不是营销露出,收纳后仍留在正面:
|
|
4047
|
-
// 把付费用户的续费入口藏进「更多」是真实风险(续费靠它,:3096-3098 的到期日也靠它提醒)
|
|
4048
|
-
var showUpsellOnFace = !mktFolded || isMember;
|
|
4049
|
-
var showInviteOnFace = !invOff && !mktFolded;
|
|
4050
|
-
var showUpsellInMore = mktFolded && !isMember;
|
|
4051
|
-
var showInviteInMore = mktFolded && !invOff;
|
|
4085
|
+
// 2026-10-17 版式简化(业主:按钮太多、换行逻辑太多):
|
|
4086
|
+
// 正面**只留一行三个按钮** —— 主行动(升级/续费)+ 用户反馈 + 「更多」;
|
|
4087
|
+
// 「带新用户换会员 / 修改密码 / 加入交流群」全部收进「更多」。
|
|
4088
|
+
// 位置稳定 > 首次曝光:入口永远在同一个地方,用户不用记"上次在哪",也不再需要
|
|
4089
|
+
// mktFolded 那套"先摆正面、关过才收纳"的两层逻辑(气泡仍会提示一次,见 renderInviteTip)。
|
|
4052
4090
|
return h("div", null,
|
|
4053
4091
|
h("div", { className: "dru-user" },
|
|
4054
4092
|
h("div", { className: "dru-avatar" }, (st.config.phone || "D").charAt(0).toUpperCase()),
|
|
@@ -4060,7 +4098,16 @@ window.__ModuleLoader__.load({
|
|
|
4060
4098
|
// (「PRO 会员 · 到期 …」)讲的是**功能性**的到期时间,不是营销。
|
|
4061
4099
|
// 免费用户这里什么都不显示 —— 把「免费档」当标签挂在脸上,正是要减少的营销露出。
|
|
4062
4100
|
isMember ? h("div", { className: "plan" }, plan === "pro_max" ? "Pro Max" : "PRO") : null
|
|
4063
|
-
)
|
|
4101
|
+
),
|
|
4102
|
+
// 2026-10-17(业主):退出登录从按钮行挪到**账号行右侧** —— 它属于"账号维护",
|
|
4103
|
+
// 与账号信息同一行动线;主按钮行也因此少一个按钮。
|
|
4104
|
+
h("button", {
|
|
4105
|
+
type: "button",
|
|
4106
|
+
className: "dru-user-logout",
|
|
4107
|
+
disabled: busy !== "",
|
|
4108
|
+
title: "退出登录(电脑端后台服务与手机端连接不受影响)",
|
|
4109
|
+
onClick: function () { doLogout(false); }
|
|
4110
|
+
}, "退出登录")
|
|
4064
4111
|
),
|
|
4065
4112
|
// 额度状态:不限量说明 / 剩余额度百分比 / 会员到期日。
|
|
4066
4113
|
// 首屏只说「还剩多少」,不提档位名、不写带宽数值(数值在下面「更多」里)。
|
|
@@ -4069,90 +4116,57 @@ window.__ModuleLoader__.load({
|
|
|
4069
4116
|
h("span", null, planText)
|
|
4070
4117
|
),
|
|
4071
4118
|
h("div", { className: "dru-actions", style: { marginTop: 10 } },
|
|
4072
|
-
//
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
//
|
|
4080
|
-
// 按钮文字自带可访问名称;气泡在屏时用 aria-describedby 把「能得多少」也读出来。
|
|
4081
|
-
showInviteOnFace ? h("button", {
|
|
4082
|
-
type: "button",
|
|
4083
|
-
className: "dru-btn dru-btn-ghost",
|
|
4084
|
-
disabled: busy !== "",
|
|
4085
|
-
title: invTipRule ? "带 " + invTipRule.n + " 位新用户可得 " + invTipRule.days + " 天 PRO 会员" : "带新用户换会员",
|
|
4086
|
-
"aria-describedby": invTipOn ? INVITE_TIP_ID : undefined,
|
|
4087
|
-
onClick: function () { setView("invite"); loadInvite(); }
|
|
4088
|
-
}, "🎁 带新用户换会员") : null,
|
|
4119
|
+
// 主行动:免费=升级入口,会员=续费/转正(账号维护,永远在正面第一位)
|
|
4120
|
+
h("button", {
|
|
4121
|
+
type: "button", className: "dru-btn dru-btn-primary",
|
|
4122
|
+
style: { display: "inline-flex", alignItems: "center" }, disabled: busy !== "",
|
|
4123
|
+
onClick: openUpgradeAuth
|
|
4124
|
+
},
|
|
4125
|
+
busy === "upgrade" ? "生成链接中…" : (!isMember ? "🚀 升级 PRO" : source === "trial" ? "🚀 转正式 PRO" : "🔄 续费会员")),
|
|
4126
|
+
// 次要:用户反馈("联系我们"的高频入口,留在正面)
|
|
4089
4127
|
h("button", { type: "button", className: "dru-btn dru-btn-ghost", disabled: busy !== "", onClick: function () { setView("feedback"); } }, "💬 用户反馈"),
|
|
4090
|
-
//
|
|
4091
|
-
//
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
:
|
|
4102
|
-
|
|
4103
|
-
h("button", { type: "button", className: "dru-btn dru-btn-danger", disabled: busy !== "", onClick: function () { doLogout(false); } }, "退出登录")
|
|
4128
|
+
// 「更多」变成同一行里的普通按钮(原来是一条整宽披露条,视觉重量和按钮完全不匹配)。
|
|
4129
|
+
// 无障碍不变:id / aria-expanded / aria-controls 保持原样(用例按它们定位)。
|
|
4130
|
+
h("button", {
|
|
4131
|
+
type: "button",
|
|
4132
|
+
id: MKT_MORE_TOGGLE_ID,
|
|
4133
|
+
className: "dru-btn dru-btn-ghost dru-disclose-inline",
|
|
4134
|
+
"aria-expanded": moreOpen ? "true" : "false",
|
|
4135
|
+
"aria-controls": MKT_MORE_BODY_ID,
|
|
4136
|
+
onClick: function () { setMoreOpen(!moreOpen); }
|
|
4137
|
+
},
|
|
4138
|
+
h("span", null, "更多"),
|
|
4139
|
+
h("span", { className: "dru-disclose-caret", "aria-hidden": "true" }, moreOpen ? "▲" : "▼")
|
|
4140
|
+
)
|
|
4104
4141
|
),
|
|
4105
|
-
// 🎁
|
|
4106
|
-
// 它的 ✕ 同时是「营销入口收纳」的触发信号(0.6.10):点过之后两个入口搬进下面的「更多」。
|
|
4142
|
+
// 🎁 邀请引导气泡:紧跟按钮行(不遮挡按钮)。点 ✕ 只做"不再提示",不再改变入口位置。
|
|
4107
4143
|
renderInviteTip(),
|
|
4108
|
-
|
|
4109
|
-
"升级/续费以带登录态方式打开:点击后生成一次性访问链接并直接跳转,无需重新登录。" +
|
|
4110
|
-
(endsAt && isMember ? "到期后如需继续使用会员权益,请在到期前续费。" : "")),
|
|
4111
|
-
// 🧰 「更多」:主界面上唯一常驻的那一个营销入口(0.6.10)—— 收纳态下正面不再摆按钮行的一部分。
|
|
4112
|
-
// 折叠时它就是一个 .dru-disclose 按钮:命中区 ≥44px、键盘可聚焦(焦点环见样式表末尾的
|
|
4113
|
-
// :focus-visible 基线),开合状态用「展开 ▼ / 收起 ▲」**文字**加箭头表达,不靠颜色区分。
|
|
4114
|
-
// 无障碍:aria-expanded 表达开合,aria-controls 指向下面的内容体(内容体始终在 DOM 里、
|
|
4115
|
-
// 收起时 hidden,所以 aria-controls 永远指向一个真实存在的元素,不指向空气)。
|
|
4116
|
-
// 【0.6.18】加 .dru-disclose-inline:原来它继承 .dru-disclose 的 width:100%,
|
|
4117
|
-
// 在账号卡里被撑成一条横贯整卡的宽条,和上面那排按钮完全不是一个视觉重量(用户:"宽而丑")。
|
|
4118
|
-
// ⚠️ 变体只加在**这一处**:邀请页的「活动规则」披露仍是整行,那是对的(它是那一屏的主折叠)。
|
|
4119
|
-
// id / aria-controls / aria-expanded 一个都不能动 —— remote-access-ui.test.mjs 按它们定位。
|
|
4120
|
-
h("button", {
|
|
4121
|
-
type: "button",
|
|
4122
|
-
id: MKT_MORE_TOGGLE_ID,
|
|
4123
|
-
className: "dru-disclose dru-disclose-inline",
|
|
4124
|
-
style: { marginTop: 10 },
|
|
4125
|
-
"aria-expanded": moreOpen ? "true" : "false",
|
|
4126
|
-
"aria-controls": MKT_MORE_BODY_ID,
|
|
4127
|
-
onClick: function () { setMoreOpen(!moreOpen); }
|
|
4128
|
-
},
|
|
4129
|
-
h("span", null, "更多"),
|
|
4130
|
-
h("span", { className: "dru-disclose-caret", "aria-hidden": "true" }, moreOpen ? "收起 ▲" : "展开 ▼")
|
|
4131
|
-
),
|
|
4144
|
+
// 🧰 「更多」折叠体:带新用户 / 修改密码 / 加入交流群 + 修改密码表单
|
|
4132
4145
|
h("div", {
|
|
4133
4146
|
id: MKT_MORE_BODY_ID,
|
|
4134
4147
|
className: "dru-more-body",
|
|
4135
4148
|
hidden: !moreOpen
|
|
4136
4149
|
},
|
|
4137
|
-
|
|
4138
|
-
|
|
4139
|
-
|
|
4140
|
-
|
|
4141
|
-
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
:
|
|
4149
|
-
|
|
4150
|
+
h("div", { className: "dru-more-actions" },
|
|
4151
|
+
invOff ? null : h("button", {
|
|
4152
|
+
type: "button",
|
|
4153
|
+
className: "dru-btn dru-btn-ghost",
|
|
4154
|
+
disabled: busy !== "",
|
|
4155
|
+
title: invTipRule ? "带 " + invTipRule.n + " 位新用户可得 " + invTipRule.days + " 天 PRO 会员" : "带新用户换会员",
|
|
4156
|
+
onClick: function () { setView("invite"); loadInvite(); }
|
|
4157
|
+
}, "🎁 带新用户换会员"),
|
|
4158
|
+
h("button", { type: "button", className: "dru-btn dru-btn-ghost", disabled: busy !== "", onClick: togglePwdForm }, pwdOpen ? "收起修改密码" : "🔒 修改密码"),
|
|
4159
|
+
community && community.qrcode
|
|
4160
|
+
? h("button", {
|
|
4161
|
+
type: "button",
|
|
4162
|
+
className: "dru-btn dru-btn-ghost",
|
|
4163
|
+
disabled: busy !== "",
|
|
4164
|
+
onClick: function () { setCommOpen(true); }
|
|
4165
|
+
}, "💬 加入交流群")
|
|
4166
|
+
: null
|
|
4167
|
+
),
|
|
4168
|
+
pwdOpen ? renderResetPwdForm(false) : null
|
|
4150
4169
|
),
|
|
4151
|
-
// 额度将尽 / 已被限速 → 🔀 双路块:升级套餐(转化)or 带新用户换会员时长(拉新)。
|
|
4152
|
-
// 用户收纳过(mktFolded)时 renderDualPath 自己返回 null —— 那两条路这时都在「更多」里,
|
|
4153
|
-
// 这里不再重复摆一遍(也不留一个没有按钮的空壳块)。
|
|
4154
|
-
quotaTight ? renderDualPath("quota") : null,
|
|
4155
|
-
pwdOpen ? renderResetPwdForm(false) : null
|
|
4156
4170
|
);
|
|
4157
4171
|
}
|
|
4158
4172
|
|
|
@@ -5021,7 +5035,7 @@ window.__ModuleLoader__.load({
|
|
|
5021
5035
|
// 在线更新成功后出现,若照旧 15 秒自动重启,等于"更新完必定打断用户正在做的事"。
|
|
5022
5036
|
useEffect(function () {
|
|
5023
5037
|
// ⚠️ desktopHost 时**不自动重启**:桌面端重启 Host 由 Electron 托管,插件无权也不该做
|
|
5024
|
-
// (见 node 半 restartHarness
|
|
5038
|
+
// (见 node 半 restartHarness 的说明)。此时只提示刷新页面,不再引导重开应用。
|
|
5025
5039
|
if (!restartPending || isRefreshOnly || isRestartHard || desktopHost || busy !== "" || restartCancelled) { setRestartCountdown(null); return undefined; }
|
|
5026
5040
|
var at = restartInfo.at || 0;
|
|
5027
5041
|
if (autoRestartCancelled(at)) { setRestartCountdown(null); return undefined; }
|
|
@@ -5094,10 +5108,10 @@ window.__ModuleLoader__.load({
|
|
|
5094
5108
|
function openAnnItem(it) {
|
|
5095
5109
|
if (!it) return;
|
|
5096
5110
|
setAnnOpenId(it.id);
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5111
|
+
// 2026-10-17 业主约定:**点开不等于已读** —— 点开只上报「点击」,不动「已读」。
|
|
5112
|
+
// 「已读」由服务端在列表/弹窗下发时记(shown),后台把已读与点击分开统计;
|
|
5113
|
+
// 客户端也不在本地改 unread(下一次拉取以服务端为准,避免客户端自造已读口径)。
|
|
5114
|
+
if (it.unread) annReportClick(it.id);
|
|
5101
5115
|
}
|
|
5102
5116
|
/**
|
|
5103
5117
|
* 📣 公告卡:插在「🔑 账号」卡**之前**(运营要用户看到的东西,与"远程访问/账号"同属首屏)。
|
|
@@ -5130,14 +5144,6 @@ window.__ModuleLoader__.load({
|
|
|
5130
5144
|
h("span", { className: "dru-ann-item-time" }, it.created_at ? fmtDate(it.created_at) : "")
|
|
5131
5145
|
);
|
|
5132
5146
|
})),
|
|
5133
|
-
h("div", { className: "dru-hint", style: { marginTop: 8 } },
|
|
5134
|
-
"点开即视为已读(后台按已读与点击分别统计);公告顺序由后台设定。"),
|
|
5135
|
-
h("div", { className: "dru-actions", style: { marginTop: 8 } },
|
|
5136
|
-
h("button", {
|
|
5137
|
-
type: "button",
|
|
5138
|
-
className: "dru-btn dru-btn-ghost",
|
|
5139
|
-
onClick: function () { annFetch({ openPopup: false }); } // 主动刷新:只更新列表,不弹窗
|
|
5140
|
-
}, "刷新公告"))
|
|
5141
5147
|
]);
|
|
5142
5148
|
}
|
|
5143
5149
|
/** 公告详情(复用 .dru-popup 视觉;点遮罩/关闭即收起)。正文按**纯文本**渲染(一期不做富文本)。 */
|
|
@@ -5155,7 +5161,6 @@ window.__ModuleLoader__.load({
|
|
|
5155
5161
|
it.image ? h("img", { className: "dru-ann-img", src: it.image, alt: "公告图片" }) : null
|
|
5156
5162
|
),
|
|
5157
5163
|
h("div", { className: "dru-popup-foot" },
|
|
5158
|
-
h("span", null, "已读状态已同步到后台"),
|
|
5159
5164
|
h("button", { type: "button", onClick: close }, "关闭")
|
|
5160
5165
|
)
|
|
5161
5166
|
)
|
|
@@ -5181,17 +5186,15 @@ window.__ModuleLoader__.load({
|
|
|
5181
5186
|
if (restartPending) {
|
|
5182
5187
|
// 桌面端:刷新类照旧(刷新页面即可);需要重启 Host 的那一类**不给「立即重启」按钮** ——
|
|
5183
5188
|
// 桌面端 Host 由 Electron 托管,插件点了也做不到,给个点不动的按钮只会让人以为是 bug。
|
|
5184
|
-
//
|
|
5189
|
+
// 改成只提示刷新页面(2026-10-17:不再引导重开应用)。
|
|
5185
5190
|
// ⚠️ 非桌面端必须保持**原有判据 isRestartHard**:改成 isRefreshOnly 会让"历史遗留 kind"
|
|
5186
5191
|
// 的文案从"刷新页面即可生效"变成"重启 dsh web 后生效" —— 属于发布版用户可见的文案变更,
|
|
5187
5192
|
// 不该混在桌面端适配里顺手做掉。桌面端才走新文案。
|
|
5188
|
-
|
|
5189
|
-
|
|
5190
|
-
|
|
5191
|
-
|
|
5192
|
-
:
|
|
5193
|
-
? "🔄 插件已更新:重启 dsh web 后生效"
|
|
5194
|
-
: "🔄 插件已更新:刷新页面即可生效");
|
|
5193
|
+
// 2026-10-17(业主):桌面端运行环境由应用托管、更新自动热加载 ——
|
|
5194
|
+
// **不再引导用户重启 DeepSeek Harness**,统一只说「刷新页面即可生效」。
|
|
5195
|
+
var restartRowText = (desktopHost || !isRestartHard)
|
|
5196
|
+
? "🔄 插件已更新:刷新页面即可生效"
|
|
5197
|
+
: "🔄 插件已更新:重启 dsh web 后生效";
|
|
5195
5198
|
rows.push(h("div", { className: "dru-access-tip-row", key: "restart" },
|
|
5196
5199
|
h("span", null, restartRowText),
|
|
5197
5200
|
(isRefreshOnly || !desktopHost) ? h("button", {
|
|
@@ -5228,6 +5231,7 @@ window.__ModuleLoader__.load({
|
|
|
5228
5231
|
)
|
|
5229
5232
|
),
|
|
5230
5233
|
h("div", { className: "dru-settings-body" },
|
|
5234
|
+
renderSetupAlert(),
|
|
5231
5235
|
restartPending
|
|
5232
5236
|
// 【0.6.18】三种"待用户动一下"的情形,文案与主按钮**按 kind 一一对应**:
|
|
5233
5237
|
// · refresh(插件文件在运行中被改写)→ 软提示 + 主按钮「刷新页面」(零风险动作)
|
|
@@ -5238,28 +5242,25 @@ window.__ModuleLoader__.load({
|
|
|
5238
5242
|
className: "dru-restart-alert" + (isRestartHard ? " dru-restart-alert-strong" : ""),
|
|
5239
5243
|
role: isRestartHard ? "alert" : "status"
|
|
5240
5244
|
},
|
|
5241
|
-
h("span", { className: "dru-restart-alert-icon" }, isRestartHard ? "⚠️" : "🔔"),
|
|
5245
|
+
h("span", { className: "dru-restart-alert-icon" }, (!desktopHost && isRestartHard) ? "⚠️" : "🔔"),
|
|
5242
5246
|
h("div", { style: { flex: "1" } },
|
|
5243
5247
|
h("div", { className: "dru-restart-alert-title" },
|
|
5244
|
-
//
|
|
5245
|
-
//
|
|
5246
|
-
//
|
|
5247
|
-
|
|
5248
|
-
?
|
|
5249
|
-
|
|
5250
|
-
|
|
5251
|
-
: (
|
|
5252
|
-
: "需要重启 dsh web 才能载入新插件")),
|
|
5248
|
+
// 2026-10-17(业主):桌面端运行环境由应用托管、插件安装/更新自动热加载 ——
|
|
5249
|
+
// **任何情况都不再引导"重启/退出重开应用"**,只说「刷新页面即可生效」。
|
|
5250
|
+
// 非桌面端(自建 dsh web)保留原有 isRestartHard 判据,文案不变。
|
|
5251
|
+
desktopHost
|
|
5252
|
+
? "插件已更新:刷新页面即可生效"
|
|
5253
|
+
: (isRestartHard
|
|
5254
|
+
? "插件已更新,重启 dsh web 后生效"
|
|
5255
|
+
: (isRefreshOnly ? "插件已更新,刷新页面即可生效" : "需要重启 dsh web 才能载入新插件"))),
|
|
5253
5256
|
h("div", { className: "dru-restart-alert-sub" },
|
|
5254
|
-
|
|
5255
|
-
?
|
|
5256
|
-
|
|
5257
|
-
|
|
5258
|
-
|
|
5259
|
-
|
|
5260
|
-
|
|
5261
|
-
? "当前运行中的 DeepSeek Harness 里还没有载入这个插件。先刷新页面;如果刷新后仍然看不到面板,请退出并重新打开 DeepSeek Harness 应用。"
|
|
5262
|
-
: "当前运行中的 dsh web 里还没有载入这个插件。先刷新页面;如果刷新后仍然看不到面板,再重启一次 dsh web。")),
|
|
5257
|
+
desktopHost
|
|
5258
|
+
? "新插件已经在磁盘上,刷新一下这个页面即可载入(手机端连接与已登录状态都不受影响)。如果刷新后仍看不到面板,在应用内「插件」页重新安装一次即可。"
|
|
5259
|
+
: (isRestartHard
|
|
5260
|
+
? "新版本已经装到这台电脑上,但当前运行的 dsh web 还是旧代码(新的后台路由与面板要等它重新载入)。手机端连接与已登录状态都不受影响;重启期间页面会短暂断开,然后自动恢复。"
|
|
5261
|
+
: (isRefreshOnly
|
|
5262
|
+
? "刚装好/刚更新的插件已在磁盘上,浏览器里的面板还是旧版本。刷新一下这个页面即可(手机端连接与已登录状态都不受影响)。"
|
|
5263
|
+
: "当前运行中的 dsh web 里还没有载入这个插件。先刷新页面;如果刷新后仍然看不到面板,再重启一次 dsh web。"))),
|
|
5263
5264
|
// 【自动化】待重启时自动倒计时重启(用户零操作);倒计时期间可一键取消
|
|
5264
5265
|
restartCountdown !== null && restartCountdown > 0
|
|
5265
5266
|
? h("div", { className: "dru-restart-auto", role: "status" },
|
|
@@ -5311,21 +5312,17 @@ window.__ModuleLoader__.load({
|
|
|
5311
5312
|
: view === "invite" ? renderInvite()
|
|
5312
5313
|
: renderHome()
|
|
5313
5314
|
),
|
|
5314
|
-
//
|
|
5315
|
-
//
|
|
5316
|
-
//
|
|
5317
|
-
h("div", { className: "dru-restart-foot" },
|
|
5318
|
-
h("div", { className: "dru-hint" },
|
|
5319
|
-
|
|
5320
|
-
: "
|
|
5321
|
-
|
|
5322
|
-
|
|
5323
|
-
:
|
|
5324
|
-
|
|
5325
|
-
className: "dru-btn " + (restartPending ? "dru-btn-primary" : "dru-btn-ghost"),
|
|
5326
|
-
disabled: busy !== "",
|
|
5327
|
-
onClick: function () { restartHarness(); }
|
|
5328
|
-
}, busy === "restart" ? "重启中…" : "🔄 重启 dsh web")
|
|
5315
|
+
// 2026-10-17(业主):删除「重启 DeepSeek Harness」整段说明 ——
|
|
5316
|
+
// 桌面端运行环境由应用本身托管、插件安装/更新自动热加载,刷新页面即可;
|
|
5317
|
+
// 只有非桌面端(自建 dsh web)才保留重启入口,且文案只讲这一种场景。
|
|
5318
|
+
desktopHost ? null : h("div", { className: "dru-restart-foot" },
|
|
5319
|
+
h("div", { className: "dru-hint" }, "刷新页面后仍看不到面板时,才需要重启 dsh web;日常安装/更新插件会自动热加载。"),
|
|
5320
|
+
h("button", {
|
|
5321
|
+
type: "button",
|
|
5322
|
+
className: "dru-btn " + (restartPending ? "dru-btn-primary" : "dru-btn-ghost"),
|
|
5323
|
+
disabled: busy !== "",
|
|
5324
|
+
onClick: function () { restartHarness(); }
|
|
5325
|
+
}, busy === "restart" ? "重启中…" : "🔄 重启 dsh web")
|
|
5329
5326
|
),
|
|
5330
5327
|
renderCommunityModal(),
|
|
5331
5328
|
// 📣 公告详情弹窗(与交流群弹窗同一层:都挂在面板根上,点遮罩即收起)
|