dsh-remote-web 0.7.12-beta.1 → 0.7.12-beta.3
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/lib/client.js +500 -4
- package/lib/index.js +581 -27
- package/package.json +1 -1
- package/runtime/clients/dsh-remote/dingtalk-bot.mjs +1361 -0
- package/runtime/clients/dsh-remote/docs/feishu-bot-contract.md +217 -0
- package/runtime/clients/dsh-remote/dsh-bridge.mjs +404 -90
- package/runtime/clients/dsh-remote/feishu-bot.mjs +1852 -0
- package/runtime/clients/dsh-remote/mirror-diag-script.js +53 -14
- package/runtime/clients/dsh-remote/mobile-adapter.mjs +355 -40
- package/runtime/dsh-setup.mjs +1 -1
package/lib/client.js
CHANGED
|
@@ -675,6 +675,11 @@ window.__ModuleLoader__.load({
|
|
|
675
675
|
".dru-ia-tier-link:hover{text-decoration:underline}",
|
|
676
676
|
".dru-ia-badge{display:inline-flex;align-items:center;padding:1px 6px;border-radius:999px;font-size:11px;font-weight:600;line-height:1.4;color:var(--dru-accent-fg);background:var(--dru-accent-tint);border:1px solid var(--dru-accent-tint-border);cursor:help}",
|
|
677
677
|
"select.dru-ia-input[disabled]{opacity:.6;cursor:not-allowed;background:var(--dru-surface-3)}",
|
|
678
|
+
// 能力行置灰(缺 Robot Code 时不可用,但仍可读 + 有提示)
|
|
679
|
+
".dru-ia-state.is-disabled{opacity:.6;background:var(--dru-surface-3);cursor:not-allowed}",
|
|
680
|
+
// 飞书 8 步向导:编号列表紧凑可读(一屏内可滚,不撑破弹层)
|
|
681
|
+
".dru-ia-steps{margin:6px 0 8px;padding-left:20px;font-size:12px;line-height:1.7;color:var(--dsw-alias-label-secondary,var(--dru-fg-muted))}",
|
|
682
|
+
".dru-ia-steps li{margin:2px 0}",
|
|
678
683
|
// A3/A6(2026-11-07 业主逐条 UI 修正):状态头右侧按钮组 / 后台服务横向紧凑布局 / 卸载反馈单选行
|
|
679
684
|
".dru-ia-head-actions{display:flex;align-items:center;gap:8px;flex-wrap:wrap;justify-content:flex-end}",
|
|
680
685
|
".dru-bridge-keep{display:flex;align-items:center;gap:6px;margin:8px 0 10px;padding:7px 10px;border-radius:8px;font-size:12px;line-height:1.5;color:var(--dru-warn-fg);background:var(--dru-warn-soft);border:1px solid var(--dru-warn-border)}",
|
|
@@ -3584,6 +3589,24 @@ window.__ModuleLoader__.load({
|
|
|
3584
3589
|
// 未登录守卫:为什么弹登录(A4/A5)+ 登录后自动回到哪个流程("手机访问"登录完继续生成访问码)。
|
|
3585
3590
|
var iaLoginWhyArr = useState(""); var iaLoginWhy = iaLoginWhyArr[0]; var setIaLoginWhy = iaLoginWhyArr[1];
|
|
3586
3591
|
var iaAfterLoginArr = useState(""); var iaAfterLogin = iaAfterLoginArr[0]; var setIaAfterLogin = iaAfterLoginArr[1];
|
|
3592
|
+
// ── 钉钉 / 飞书(2026-11-08):与 wecom 并列的两条通道 ──
|
|
3593
|
+
var imDingIdArr = useState(""); var imDingId = imDingIdArr[0]; var setImDingId = imDingIdArr[1];
|
|
3594
|
+
var imDingSecretArr = useState(""); var imDingSecret = imDingSecretArr[0]; var setImDingSecret = imDingSecretArr[1];
|
|
3595
|
+
var imDingRobotArr = useState(""); var imDingRobot = imDingRobotArr[0]; var setImDingRobot = imDingRobotArr[1];
|
|
3596
|
+
// 钉钉扫码一键创建(2026-11-08):authId/授权链接/等待态;手动配置默认折叠
|
|
3597
|
+
var imDingAuthArr = useState(null); var imDingAuth = imDingAuthArr[0]; var setImDingAuth = imDingAuthArr[1];
|
|
3598
|
+
var imDingManualArr = useState(false); var imDingManual = imDingManualArr[0]; var setImDingManual = imDingManualArr[1];
|
|
3599
|
+
var imFeishuAppIdArr = useState(""); var imFeishuAppId = imFeishuAppIdArr[0]; var setImFeishuAppId = imFeishuAppIdArr[1];
|
|
3600
|
+
var imFeishuSecretArr = useState(""); var imFeishuSecret = imFeishuSecretArr[0]; var setImFeishuSecret = imFeishuSecretArr[1];
|
|
3601
|
+
var imFeishuRecvArr = useState(""); var imFeishuRecv = imFeishuRecvArr[0]; var setImFeishuRecv = imFeishuRecvArr[1];
|
|
3602
|
+
var imFeishuTypeArr = useState("open_id"); var imFeishuType = imFeishuTypeArr[0]; var setImFeishuType = imFeishuTypeArr[1];
|
|
3603
|
+
// 平台级消息/错误/忙碌(与 wecom 的 imBotsMsg 分开:切平台时不会串台)
|
|
3604
|
+
var imPlatMsgArr = useState(null); var imPlatMsg = imPlatMsgArr[0]; var setImPlatMsg = imPlatMsgArr[1]; // {kind,text}
|
|
3605
|
+
var imPlatErrArr = useState({}); var imPlatErr = imPlatErrArr[0]; var setImPlatErr = imPlatErrArr[1]; // {field: msg}
|
|
3606
|
+
var imPlatBusyArr = useState(""); var imPlatBusy = imPlatBusyArr[0]; var setImPlatBusy = imPlatBusyArr[1]; // ""|"save"|"test"|"deps"
|
|
3607
|
+
// 飞书 SDK 依赖(按需下载):installed/version/phase/lastError
|
|
3608
|
+
var imDepsArr = useState(null); var imDeps = imDepsArr[0]; var setImDeps = imDepsArr[1];
|
|
3609
|
+
var imFeishuWizardArr = useState(false); var imFeishuWizard = imFeishuWizardArr[0]; var setImFeishuWizard = imFeishuWizardArr[1];
|
|
3587
3610
|
|
|
3588
3611
|
/** 读通道配置(GET 只回脱敏视图:botId/hasSecret/url/targetChatId + 桥写的状态)。 */
|
|
3589
3612
|
function loadImBots() {
|
|
@@ -5989,6 +6012,21 @@ window.__ModuleLoader__.load({
|
|
|
5989
6012
|
setImBotsSessionTitle(String(w.sessionTitle || ""));
|
|
5990
6013
|
setImBotsWhyOpen(false);
|
|
5991
6014
|
setImBotsUrl(String(w.url || ""));
|
|
6015
|
+
var d = (b && b.dingtalk) || {};
|
|
6016
|
+
setImDingId(String(d.clientId || ""));
|
|
6017
|
+
setImDingSecret("");
|
|
6018
|
+
setImDingRobot(String(d.robotCode || ""));
|
|
6019
|
+
var f = (b && b.feishu) || {};
|
|
6020
|
+
setImFeishuAppId(String(f.appId || ""));
|
|
6021
|
+
setImFeishuSecret("");
|
|
6022
|
+
setImFeishuRecv(String(f.receiveId || ""));
|
|
6023
|
+
setImFeishuType(String(f.receiveIdType || "open_id"));
|
|
6024
|
+
setImFeishuWizard(false);
|
|
6025
|
+
setImPlatMsg(null);
|
|
6026
|
+
setImPlatErr({});
|
|
6027
|
+
var deps = b && b.status && b.status.deps && b.status.deps.feishu;
|
|
6028
|
+
if (deps) setImDeps(deps);
|
|
6029
|
+
loadImDeps();
|
|
5992
6030
|
});
|
|
5993
6031
|
}
|
|
5994
6032
|
// 数据加载交给下面的 effect(按"弹层是否打开"触发):
|
|
@@ -6554,6 +6592,446 @@ window.__ModuleLoader__.load({
|
|
|
6554
6592
|
}, "去登录"))] }));
|
|
6555
6593
|
}
|
|
6556
6594
|
|
|
6595
|
+
// ══════════════════════════════════════════════════════════════════════════════════
|
|
6596
|
+
// 钉钉 / 飞书(2026-11-08):与 wecom 并列的两条通道;飞书 SDK 走「按需下载」。
|
|
6597
|
+
// ══════════════════════════════════════════════════════════════════════════════════
|
|
6598
|
+
|
|
6599
|
+
/** 飞书官方文档(配置页顶部固定展示;外链一律 target=_blank + rel=noopener)。 */
|
|
6600
|
+
var FEISHU_DOCS = {
|
|
6601
|
+
// 业主给的两个官方入口(必须出现在配置流程里)
|
|
6602
|
+
createApp: "https://open.feishu.cn/app?lang=zh-CN",
|
|
6603
|
+
cardBot: "https://open.feishu.cn/document/uAjLw4CM/ukzMukzMukzM/feishu-cards/quick-start/develop-a-card-interactive-bot"
|
|
6604
|
+
};
|
|
6605
|
+
/** 主路径只有 3 件事(业主:接收人参数用户根本不知道怎么获取,别让用户配)。 */
|
|
6606
|
+
var FEISHU_MAIN_STEPS = [
|
|
6607
|
+
"创建企业自建应用(打开上面的「创建应用」链接)",
|
|
6608
|
+
"复制应用凭证里的 App ID / App Secret",
|
|
6609
|
+
"填到下面两个框,点「保存并连接」——接收群/私聊会自动发现,不用你配"
|
|
6610
|
+
];
|
|
6611
|
+
/** 细步骤(折叠):开机器人能力 / 权限 / 事件与回调切长连接 / 发布。 */
|
|
6612
|
+
var FEISHU_DETAIL_STEPS = [
|
|
6613
|
+
"开通机器人能力:应用功能 → 机器人 → 启用",
|
|
6614
|
+
"申请权限:收 p2p / 群@消息,发 im:message:send_as_bot",
|
|
6615
|
+
"事件配置:订阅方式选「长连接」,添加「接收消息 v2.0」",
|
|
6616
|
+
"回调配置:订阅方式选「长连接」,添加 card.action.trigger",
|
|
6617
|
+
"发布版本:版本管理与发布 → 创建版本 → 申请发布(管理员审核)"
|
|
6618
|
+
];
|
|
6619
|
+
|
|
6620
|
+
/** GET /dsh-remote/im-deps:飞书 SDK 是否已装 + phase(下载进度轮询用)。 */
|
|
6621
|
+
function loadImDeps() {
|
|
6622
|
+
return api("/dsh-remote/im-deps").then(function (b) {
|
|
6623
|
+
var f = b && b.feishu;
|
|
6624
|
+
if (f) setImDeps(f);
|
|
6625
|
+
return f || null;
|
|
6626
|
+
}).catch(function () { return null; });
|
|
6627
|
+
}
|
|
6628
|
+
|
|
6629
|
+
/** 触发飞书 SDK 下载(后台 npm install;进度靠轮询 im-deps 的 phase)。 */
|
|
6630
|
+
function startFeishuDownload() {
|
|
6631
|
+
if (imPlatBusy) return;
|
|
6632
|
+
setImPlatBusy("deps");
|
|
6633
|
+
setImPlatMsg({ kind: "ok", text: "正在下载依赖(约 41MB,仅装一次)…" });
|
|
6634
|
+
post("/dsh-remote/im-deps/feishu", {}).then(function (b) {
|
|
6635
|
+
if (b && b.deps && b.deps.feishu) setImDeps(b.deps.feishu);
|
|
6636
|
+
loadImDeps();
|
|
6637
|
+
}).catch(function (e) {
|
|
6638
|
+
setImPlatMsg({ kind: "err", text: "下载失败:" + ((e && e.message) || e) + "(可重试)" });
|
|
6639
|
+
}).finally(function () { setImPlatBusy(""); });
|
|
6640
|
+
}
|
|
6641
|
+
|
|
6642
|
+
/** 依赖下载中:每 ~900ms 轮询一次 phase;失败/完成后自动停。 */
|
|
6643
|
+
useEffect(function () {
|
|
6644
|
+
if (iaModal !== "channel" || iaChStep !== "feishu") return undefined;
|
|
6645
|
+
var phase = imDeps && imDeps.phase;
|
|
6646
|
+
if (phase !== "downloading" && phase !== "installing") return undefined;
|
|
6647
|
+
var t = null;
|
|
6648
|
+
try {
|
|
6649
|
+
t = setTimeout(function () { loadImDeps(); }, 900);
|
|
6650
|
+
} catch (e) { /* 忽略 */ }
|
|
6651
|
+
return function () { try { if (t) clearTimeout(t); } catch (e) { /* 忽略 */ } };
|
|
6652
|
+
}, [iaModal, iaChStep, imDeps]);
|
|
6653
|
+
|
|
6654
|
+
/** 钉钉表单提交体(空 secret = 不修改,与 wecom 一致)。 */
|
|
6655
|
+
function imDingPayload() {
|
|
6656
|
+
return {
|
|
6657
|
+
clientId: String(imDingId || "").trim(),
|
|
6658
|
+
clientSecret: String(imDingSecret || ""),
|
|
6659
|
+
robotCode: String(imDingRobot || "").trim()
|
|
6660
|
+
};
|
|
6661
|
+
}
|
|
6662
|
+
/** 飞书表单提交体。 */
|
|
6663
|
+
function imFeishuPayload() {
|
|
6664
|
+
// 只提交两个凭据:接收群/私聊由桥侧自动发现(业主:不让用户填不知道怎么获取的 ID)。
|
|
6665
|
+
return {
|
|
6666
|
+
appId: String(imFeishuAppId || "").trim(),
|
|
6667
|
+
appSecret: String(imFeishuSecret || "")
|
|
6668
|
+
};
|
|
6669
|
+
}
|
|
6670
|
+
function imPlatFieldErrOf(code) {
|
|
6671
|
+
var map = {
|
|
6672
|
+
missing_client_id: "clientId", missing_client_secret: "clientSecret", missing_robot_code: "robotCode",
|
|
6673
|
+
missing_app_id: "appId", missing_app_secret: "appSecret", missing_receive_id: "receiveId",
|
|
6674
|
+
invalid_receive_id_type: "receiveIdType"
|
|
6675
|
+
};
|
|
6676
|
+
return map[String(code || "")] || "";
|
|
6677
|
+
}
|
|
6678
|
+
var IM_PLAT_FIELD_NAMES = {
|
|
6679
|
+
clientId: "Client ID", clientSecret: "Client Secret", robotCode: "Robot Code",
|
|
6680
|
+
appId: "App ID", appSecret: "App Secret", receiveId: "接收人", receiveIdType: "接收对象类型"
|
|
6681
|
+
};
|
|
6682
|
+
|
|
6683
|
+
/**
|
|
6684
|
+
* 保存 / 测试(钉钉·飞书共用)。
|
|
6685
|
+
* @param {"dingtalk"|"feishu"} platform
|
|
6686
|
+
* @param {"save"|"test"} mode save=只保存;test=先保存再连接测试(「保存并连接」)
|
|
6687
|
+
*/
|
|
6688
|
+
function saveImPlatform(platform, mode) {
|
|
6689
|
+
if (imPlatBusy) return;
|
|
6690
|
+
var cfg = platform === "dingtalk" ? imDingPayload() : imFeishuPayload();
|
|
6691
|
+
setImPlatBusy(mode === "test" ? "test" : "save");
|
|
6692
|
+
setImPlatMsg(null);
|
|
6693
|
+
setImPlatErr({});
|
|
6694
|
+
// ⚠️ 必须是 PUT:/dsh-remote/im-bots 在节点半按 method 分发(GET/PUT),POST 会被 405。
|
|
6695
|
+
api("/dsh-remote/im-bots", {
|
|
6696
|
+
method: "PUT", headers: { "content-type": "application/json" },
|
|
6697
|
+
body: JSON.stringify({ platform: platform, config: cfg })
|
|
6698
|
+
}, 15000).then(function () {
|
|
6699
|
+
if (mode !== "test") {
|
|
6700
|
+
setImPlatMsg({ kind: "ok", text: "已保存(配置只在本机,Secret 不会回显)" });
|
|
6701
|
+
return loadImBots();
|
|
6702
|
+
}
|
|
6703
|
+
return post("/dsh-remote/im-bots/test", { platform: platform, config: cfg }, 15000).then(function (r) {
|
|
6704
|
+
if (r && r.connected) setImPlatMsg({ kind: "ok", text: "已连接,消息可以正常收发了" });
|
|
6705
|
+
else setImPlatMsg({ kind: "warn", text: "已保存,但连接还没成功" + (r && r.lastError ? ":" + r.lastError : "(稍后自动重试)") });
|
|
6706
|
+
return loadImBots();
|
|
6707
|
+
});
|
|
6708
|
+
}).catch(function (e) {
|
|
6709
|
+
var body = (e && e.body) || {};
|
|
6710
|
+
var code = String(body.error || "");
|
|
6711
|
+
var field = imPlatFieldErrOf(code);
|
|
6712
|
+
if (field) {
|
|
6713
|
+
var errs = {}; errs[field] = String(body.message || "请填写完整");
|
|
6714
|
+
setImPlatErr(errs);
|
|
6715
|
+
setImPlatMsg({ kind: "err", text: "请补全:" + IM_PLAT_FIELD_NAMES[field] });
|
|
6716
|
+
} else {
|
|
6717
|
+
setImPlatMsg({ kind: "err", text: "保存失败:" + (body.message || (e && e.message) || "未知错误") });
|
|
6718
|
+
}
|
|
6719
|
+
return null;
|
|
6720
|
+
}).finally(function () { setImPlatBusy(""); });
|
|
6721
|
+
}
|
|
6722
|
+
|
|
6723
|
+
/** 平台状态行(连接中 / 已连接 / 失败;文案面向非技术用户)。 */
|
|
6724
|
+
function imPlatStateLine(st) {
|
|
6725
|
+
if (imPlatBusy === "test") return h("div", { className: "dru-ia-state", role: "status" }, h("span", { className: "dru-spin" }), "正在连接…(最多 10 秒)");
|
|
6726
|
+
if (imPlatMsg) return h("div", { className: "dru-ia-state " + (imPlatMsg.kind === "ok" ? "is-ok" : imPlatMsg.kind === "warn" ? "is-warn" : "is-err"), role: "status" }, imPlatMsg.text);
|
|
6727
|
+
if (st && st.connected) return h("div", { className: "dru-ia-state is-ok", role: "status" }, druIcon("check"), "已连接");
|
|
6728
|
+
if (st && st.lastError) return h("div", { className: "dru-ia-state is-err", role: "status" }, "上次连接失败:" + st.lastError);
|
|
6729
|
+
return null;
|
|
6730
|
+
}
|
|
6731
|
+
|
|
6732
|
+
/** 钉钉扫码授权:开始(POST begin)→ 拿授权链接;deviceCode 只在服务端,不落浏览器。 */
|
|
6733
|
+
function startDingAuth() {
|
|
6734
|
+
if (imPlatBusy) return;
|
|
6735
|
+
setImPlatBusy("auth");
|
|
6736
|
+
setImPlatMsg(null);
|
|
6737
|
+
setImPlatErr({});
|
|
6738
|
+
post("/dsh-remote/im-dingtalk-auth/begin", {}).then(function (b) {
|
|
6739
|
+
if (!b || b.ok !== true || !b.url) {
|
|
6740
|
+
setImDingAuth(null);
|
|
6741
|
+
setImPlatMsg({ kind: "err", text: "发起授权失败:" + ((b && b.message) || "请稍后重试") });
|
|
6742
|
+
return;
|
|
6743
|
+
}
|
|
6744
|
+
setImDingAuth({
|
|
6745
|
+
authId: String(b.authId || ""),
|
|
6746
|
+
url: String(b.url || ""),
|
|
6747
|
+
interval: Math.max(1, Math.min(10, Number(b.interval) || 2)),
|
|
6748
|
+
expiresAt: Date.now() + Math.max(10, Math.min(600, Number(b.expiresIn) || 120)) * 1000,
|
|
6749
|
+
phase: "waiting",
|
|
6750
|
+
error: ""
|
|
6751
|
+
});
|
|
6752
|
+
}).catch(function (e) {
|
|
6753
|
+
setImDingAuth(null);
|
|
6754
|
+
var body = (e && e.body) || {};
|
|
6755
|
+
setImPlatMsg({ kind: "err", text: "发起授权失败:" + (body.message || (e && e.message) || "网络错误") });
|
|
6756
|
+
}).finally(function () { setImPlatBusy(""); });
|
|
6757
|
+
}
|
|
6758
|
+
/** 查询一次授权状态;成功后凭据已由服务端写盘 → 刷新面板即"已连接"。 */
|
|
6759
|
+
function pollDingAuth() {
|
|
6760
|
+
var a = imDingAuth;
|
|
6761
|
+
if (!a || !a.authId || a.phase !== "waiting") return;
|
|
6762
|
+
api("/dsh-remote/im-dingtalk-auth/status?id=" + encodeURIComponent(a.authId)).then(function (b) {
|
|
6763
|
+
if (b && b.status === "success") {
|
|
6764
|
+
setImDingAuth(null);
|
|
6765
|
+
setImPlatMsg({ kind: "ok", text: "已创建机器人并建立连接" + (b.clientIdTail ? "(Client ID 尾号 " + b.clientIdTail + ")" : "") + ",去钉钉里发条消息试试" });
|
|
6766
|
+
loadImBots();
|
|
6767
|
+
return;
|
|
6768
|
+
}
|
|
6769
|
+
if (b && (b.status === "failed" || b.status === "expired")) {
|
|
6770
|
+
setImDingAuth({ authId: a.authId, url: a.url, interval: a.interval, expiresAt: a.expiresAt, phase: "failed", error: String(b.message || "授权失败,请重试") });
|
|
6771
|
+
return;
|
|
6772
|
+
}
|
|
6773
|
+
if (Date.now() > a.expiresAt) {
|
|
6774
|
+
setImDingAuth({ authId: a.authId, url: a.url, interval: a.interval, expiresAt: a.expiresAt, phase: "failed", error: "授权已超时(2 分钟内未确认),请重新发起" });
|
|
6775
|
+
return;
|
|
6776
|
+
}
|
|
6777
|
+
// waiting:**换一个新对象** → 轮询 effect 依赖变化 → 继续排下一次(否则只会轮询一次)。
|
|
6778
|
+
setImDingAuth({ authId: a.authId, url: a.url, interval: a.interval, expiresAt: a.expiresAt, phase: "waiting", error: "", polledAt: Date.now() });
|
|
6779
|
+
}).catch(function () { /* 网络抖动:下一轮再试(轮询期内不打断用户) */ });
|
|
6780
|
+
}
|
|
6781
|
+
/** 等待确认中:每 ~2s 轮询一次 status(最长到 expiresAt)。 */
|
|
6782
|
+
useEffect(function () {
|
|
6783
|
+
if (iaModal !== "channel" || iaChStep !== "dingtalk") return undefined;
|
|
6784
|
+
if (!imDingAuth || imDingAuth.phase !== "waiting") return undefined;
|
|
6785
|
+
var t = null;
|
|
6786
|
+
try { t = setTimeout(pollDingAuth, Math.max(1000, (imDingAuth.interval || 2) * 1000)); } catch (e) { /* 忽略 */ }
|
|
6787
|
+
return function () { try { if (t) clearTimeout(t); } catch (e) { /* 忽略 */ } };
|
|
6788
|
+
}, [iaModal, iaChStep, imDingAuth]);
|
|
6789
|
+
|
|
6790
|
+
/** 钉钉手动创建 7 步(2026-11-08 业主给的官方链接;每步一句 + 链接)。 */
|
|
6791
|
+
var DINGTALK_STEPS = [
|
|
6792
|
+
{ t: "用钉钉账号登录开发者后台", url: "https://open-dev.dingtalk.com/" },
|
|
6793
|
+
{ t: "「应用开发 → 企业内部应用 → 钉钉应用 → 创建应用」,起个名字保存", url: "https://open.dingtalk.com/document/orgapp/create-an-application" },
|
|
6794
|
+
{ t: "「基础信息 → 凭证与基础信息」复制 Client ID / Client Secret(Secret 只显示一次,丢了要重置)", url: "" },
|
|
6795
|
+
{ t: "「应用能力 → 机器人」开启机器人配置(名称/图标/简介/预览图)", url: "https://open.dingtalk.com/document/orgapp/add-application-capabilities" },
|
|
6796
|
+
{ t: "「消息接收模式」必须选 Stream 模式(不要选 HTTP、不要填地址),保存并发布机器人", url: "https://open.dingtalk.com/document/orgapp/configure-the-robot-application" },
|
|
6797
|
+
{ t: "同一页找到 Robot Code(一般与 Client ID 相同)一起填", url: "https://open.dingtalk.com/document/orgapp/faq-robot" },
|
|
6798
|
+
{ t: "「应用发布 → 版本管理与发布 → 创建新版本 → 发布」,回来点「测试连接」", url: "https://open.dingtalk.com/document/orgapp/robot-receive-message" }
|
|
6799
|
+
];
|
|
6800
|
+
/** 三个高频坑(折叠底部,警示样式)。 */
|
|
6801
|
+
var DINGTALK_PITFALLS = [
|
|
6802
|
+
"建错机器人:群设置里加的「自定义机器人」只有 webhook 地址,没有 Client ID/Secret,也不可能长连接",
|
|
6803
|
+
"只保存没发布:机器人发布 + 应用版本发布是两步,漏任一步会 400 或群里搜不到机器人",
|
|
6804
|
+
"模式选错/凭证脏:消息接收模式留 HTTP、Secret 复制带空格、开了 IP 白名单 → 都会「连不上但报错含糊」;建议「连接成功才放行」"
|
|
6805
|
+
];
|
|
6806
|
+
|
|
6807
|
+
/** 钉钉能力行:缺 Robot Code 时置灰并提示(业主:补 Robot Code 可开启)。 */
|
|
6808
|
+
function dingCapabilityRow(label, enabled, hint) {
|
|
6809
|
+
return h("div", {
|
|
6810
|
+
className: "dru-ia-state" + (enabled ? "" : " is-disabled"),
|
|
6811
|
+
"aria-disabled": enabled ? "false" : "true",
|
|
6812
|
+
title: enabled ? "" : hint
|
|
6813
|
+
},
|
|
6814
|
+
druIcon(enabled ? "check" : "alert"),
|
|
6815
|
+
label,
|
|
6816
|
+
enabled ? null : h("span", { className: "dru-ia-badge" }, hint));
|
|
6817
|
+
}
|
|
6818
|
+
|
|
6819
|
+
/** 钉钉配置页:主路径 = 扫码一键创建;手动创建 7 步 + 三个坑折叠在「高级」。 */
|
|
6820
|
+
function renderDingtalkStep(close) {
|
|
6821
|
+
var d = (imBots && imBots.dingtalk) || {};
|
|
6822
|
+
var st = (imBots && imBots.status && imBots.status.dingtalk) || {};
|
|
6823
|
+
var err = imPlatErr || {};
|
|
6824
|
+
var auth = imDingAuth;
|
|
6825
|
+
var sourceText = (st.credentialSource || d.credentialSource) === "scan" ? "扫码创建"
|
|
6826
|
+
: (st.credentialSource || d.credentialSource) === "manual" ? "手动填写" : "";
|
|
6827
|
+
var clientTail = String(d.clientId || "").length > 4 ? String(d.clientId).slice(-4) : String(d.clientId || "");
|
|
6828
|
+
// Robot Code 是否已配置:优先用桥状态;旧桥没这个字段时退回配置里的 robotCode。
|
|
6829
|
+
var robotCodeOk = st.robotCodeConfigured === true || !!String(d.robotCode || "").trim();
|
|
6830
|
+
var caps = st.capabilities || null;
|
|
6831
|
+
return iaDialog(Object.assign({}, {
|
|
6832
|
+
title: "钉钉机器人",
|
|
6833
|
+
sub: "不用去开发者后台创建应用:扫码点一下就会自动创建机器人",
|
|
6834
|
+
onClose: close,
|
|
6835
|
+
foot: [
|
|
6836
|
+
h("button", {
|
|
6837
|
+
type: "button", className: "dru-ia-btn is-primary", disabled: imPlatBusy !== "",
|
|
6838
|
+
onClick: function () { if (!auth || auth.phase !== "waiting") startDingAuth(); }
|
|
6839
|
+
}, imPlatBusy === "auth" ? "正在生成授权链接…" : (auth && auth.phase === "waiting" ? "重新发起扫码" : "用钉钉扫码,一键创建机器人")),
|
|
6840
|
+
h("button", { type: "button", className: "dru-ia-btn is-ghost", onClick: function () { close(); } }, "关闭")
|
|
6841
|
+
]
|
|
6842
|
+
}, { children: [
|
|
6843
|
+
// 判断口诀(醒目):帮用户尽早排除"群 webhook 机器人"这个错误方向
|
|
6844
|
+
h("div", { className: "dru-ia-state is-warn", role: "note" },
|
|
6845
|
+
"要你填「消息接收地址」的,就是群 webhook 机器人——那种不能长连接,请退出重来"),
|
|
6846
|
+
h("div", { className: "dru-ia-hint" },
|
|
6847
|
+
"官方入口:",
|
|
6848
|
+
h("a", { className: "dru-ia-tier-link", href: "https://open.dingtalk.com/", target: "_blank", rel: "noopener" }, "钉钉开放平台"),
|
|
6849
|
+
" · ",
|
|
6850
|
+
h("a", { className: "dru-ia-tier-link", href: "https://open-dev.dingtalk.com/", target: "_blank", rel: "noopener" }, "开发者后台")),
|
|
6851
|
+
// 已连接状态:clientId 尾号 + 来源
|
|
6852
|
+
(st.connected || d.hasSecret)
|
|
6853
|
+
? h("div", { className: "dru-ia-state is-ok" }, druIcon("check"),
|
|
6854
|
+
(st.connected ? "已连接" : "已保存凭据") + (clientTail ? "(Client ID 尾号 " + clientTail + ")" : "")
|
|
6855
|
+
+ (sourceText ? " · 来源:" + sourceText : ""))
|
|
6856
|
+
: h("div", { className: "dru-ia-state" }, druIcon("chat"), "还没有连接:点下方按钮扫码创建机器人"),
|
|
6857
|
+
// 扫码授权中:链接 + 提示 + 复制/打开(无 QR 库 → 降级,明确告知用手机钉钉扫码)
|
|
6858
|
+
(auth && auth.phase === "waiting")
|
|
6859
|
+
? h("div", { className: "dru-ia-field" },
|
|
6860
|
+
h("div", { className: "dru-ia-state", role: "status" }, h("span", { className: "dru-spin" }),
|
|
6861
|
+
"等待你在钉钉里确认…(用手机钉钉扫下方链接,或复制到手机打开)"),
|
|
6862
|
+
h("div", { className: "dru-copy-row" },
|
|
6863
|
+
h("div", { className: "dru-copy-box" },
|
|
6864
|
+
h("span", { className: "dru-link-val" }, auth.url),
|
|
6865
|
+
h("button", {
|
|
6866
|
+
type: "button", className: "dru-copy-btn", "aria-label": "复制授权链接",
|
|
6867
|
+
onClick: function () {
|
|
6868
|
+
copyText(auth.url).then(function (ok) { if (!ok) setImPlatMsg({ kind: "err", text: "复制失败:请手动选中链接复制" }); });
|
|
6869
|
+
}
|
|
6870
|
+
}, "复制授权链接")),
|
|
6871
|
+
h("div", { className: "dru-actions", style: { marginTop: 8 } },
|
|
6872
|
+
h("a", { className: "dru-ia-btn is-primary", href: auth.url, target: "_blank", rel: "noopener" }, "在浏览器打开授权页"),
|
|
6873
|
+
h("button", { type: "button", className: "dru-ia-btn", onClick: function () { setImDingAuth(null); setImPlatMsg({ kind: "ok", text: "已取消本次扫码授权" }); } }, "取消授权"))))
|
|
6874
|
+
: null,
|
|
6875
|
+
(auth && auth.phase === "failed")
|
|
6876
|
+
? h("div", { className: "dru-ia-field" },
|
|
6877
|
+
h("div", { className: "dru-ia-state is-err", role: "alert" }, auth.error || "授权失败"),
|
|
6878
|
+
h("button", { type: "button", className: "dru-ia-btn", onClick: function () { startDingAuth(); } }, "重试扫码授权"))
|
|
6879
|
+
: null,
|
|
6880
|
+
// 能力:主动推送 / 卡片(缺 Robot Code 时置灰,提示补 Robot Code)
|
|
6881
|
+
h("div", { className: "dru-ia-field" },
|
|
6882
|
+
h("div", { className: "dru-ia-label" }, "机器人能力"),
|
|
6883
|
+
dingCapabilityRow("主动推送(任务完成/出错通知)", robotCodeOk && (!caps || caps.openapi !== false), "补 Robot Code 可开启"),
|
|
6884
|
+
dingCapabilityRow("卡片交互(审批卡片,点按钮放行/拒绝)", robotCodeOk && (!caps || caps.card !== false), "补 Robot Code 可开启")),
|
|
6885
|
+
// 高级:手动创建(7 步 + 三个坑 + 手动填凭据;默认折叠)
|
|
6886
|
+
h("div", { className: "dru-ia-field" },
|
|
6887
|
+
h("button", {
|
|
6888
|
+
type: "button", className: "dru-ia-disclose", "aria-expanded": imDingManual ? "true" : "false",
|
|
6889
|
+
onClick: function () { setImDingManual(!imDingManual); }
|
|
6890
|
+
}, "高级:去开发者后台手动创建(或手动填凭据)", druIcon(imDingManual ? "left" : "right")),
|
|
6891
|
+
imDingManual
|
|
6892
|
+
? h("div", null,
|
|
6893
|
+
h("ol", { className: "dru-ia-steps" }, DINGTALK_STEPS.map(function (stp, i) {
|
|
6894
|
+
return h("li", { key: "dt" + i }, stp.t,
|
|
6895
|
+
stp.url
|
|
6896
|
+
? h("a", { className: "dru-ia-tier-link", href: stp.url, target: "_blank", rel: "noopener", style: { marginLeft: 6 } }, "官方文档")
|
|
6897
|
+
: null);
|
|
6898
|
+
})),
|
|
6899
|
+
// 三个高频坑(警示)
|
|
6900
|
+
h("div", { className: "dru-ia-state is-warn", role: "alert" },
|
|
6901
|
+
h("div", null, "三个高频坑:"),
|
|
6902
|
+
h("ol", { className: "dru-ia-steps" }, DINGTALK_PITFALLS.map(function (t, i) {
|
|
6903
|
+
return h("li", { key: "pf" + i }, t);
|
|
6904
|
+
}))),
|
|
6905
|
+
// 手动填三层字段(已有应用的兜底)
|
|
6906
|
+
h("div", { className: "dru-ia-hint" }, "已有钉钉应用的话可以手填:Client ID/Secret 就是 AppKey/AppSecret;Robot Code 在机器人页复制。"),
|
|
6907
|
+
iaField("Client ID(= AppKey)", "dru-ding-client", h("input", {
|
|
6908
|
+
id: "dru-ding-client", className: "dru-ia-input", type: "text", value: imDingId, autoComplete: "off", spellCheck: false,
|
|
6909
|
+
placeholder: "钉钉应用 AppKey", "aria-invalid": err.clientId ? "true" : "false",
|
|
6910
|
+
onChange: function (e) { setImDingId(e.target.value); }
|
|
6911
|
+
}), err.clientId || ""),
|
|
6912
|
+
iaField("Client Secret(= AppSecret)", "dru-ding-secret", h("input", {
|
|
6913
|
+
id: "dru-ding-secret", className: "dru-ia-input", type: "password", value: imDingSecret, autoComplete: "new-password", spellCheck: false,
|
|
6914
|
+
placeholder: d.hasSecret ? "已保存(留空表示不修改)" : "钉钉应用 AppSecret", "aria-invalid": err.clientSecret ? "true" : "false",
|
|
6915
|
+
onChange: function (e) { setImDingSecret(e.target.value); }
|
|
6916
|
+
}), err.clientSecret || "", "只保存在本机;已保存的 Secret 永远不回显。"),
|
|
6917
|
+
iaField("Robot Code", "dru-ding-robot", h("input", {
|
|
6918
|
+
id: "dru-ding-robot", className: "dru-ia-input", type: "text", value: imDingRobot, autoComplete: "off", spellCheck: false,
|
|
6919
|
+
placeholder: "机器人编码(开放平台 → 机器人页复制)", "aria-invalid": err.robotCode ? "true" : "false",
|
|
6920
|
+
onChange: function (e) { setImDingRobot(e.target.value); }
|
|
6921
|
+
}), err.robotCode || "", "三个字段都要填。"),
|
|
6922
|
+
h("div", { className: "dru-actions", style: { marginTop: 8 } },
|
|
6923
|
+
h("button", { type: "button", className: "dru-ia-btn is-primary", disabled: imPlatBusy !== "", onClick: function () { saveImPlatform("dingtalk", "test"); } },
|
|
6924
|
+
imPlatBusy === "test" ? "连接中…" : "保存并连接"),
|
|
6925
|
+
h("button", { type: "button", className: "dru-ia-btn", disabled: imPlatBusy !== "", onClick: function () { saveImPlatform("dingtalk", "save"); } },
|
|
6926
|
+
imPlatBusy === "save" ? "保存中…" : "仅保存")))
|
|
6927
|
+
: null),
|
|
6928
|
+
imPlatStateLine(st)
|
|
6929
|
+
] }));
|
|
6930
|
+
}
|
|
6931
|
+
|
|
6932
|
+
/** 飞书 SDK 依赖未安装时的那一屏(按需下载,不装也能用其它通道)。 */
|
|
6933
|
+
function renderFeishuDepsGate(close) {
|
|
6934
|
+
var deps = imDeps || {};
|
|
6935
|
+
var running = deps.phase === "downloading" || deps.phase === "installing";
|
|
6936
|
+
return iaDialog(Object.assign({}, {
|
|
6937
|
+
title: "飞书机器人",
|
|
6938
|
+
sub: "首次使用需要先下载依赖(约 41MB,仅装一次)",
|
|
6939
|
+
onClose: close,
|
|
6940
|
+
foot: [
|
|
6941
|
+
h("button", { type: "button", className: "dru-ia-btn is-primary", disabled: imPlatBusy !== "" || running, onClick: startFeishuDownload },
|
|
6942
|
+
running ? "下载中…" : (deps.phase === "failed" ? "重试下载" : "下载依赖")),
|
|
6943
|
+
h("button", { type: "button", className: "dru-ia-btn", onClick: function () { setIaChStep("list"); } }, "返回平台列表")
|
|
6944
|
+
]
|
|
6945
|
+
}, { children: [
|
|
6946
|
+
h("div", { className: "dru-ia-state" }, druIcon("bell"),
|
|
6947
|
+
running ? "正在下载并安装(约 41MB,仅装一次)…" : (deps.phase === "failed" ? "上次下载失败" : "还没有安装飞书依赖")),
|
|
6948
|
+
deps.lastError ? h("div", { className: "dru-ia-state is-err", role: "alert" }, deps.lastError) : null,
|
|
6949
|
+
h("div", { className: "dru-ia-hint" }, "下载的是飞书官方 Node SDK,仅装在这个插件自己的目录里,不影响其它插件和系统环境。"),
|
|
6950
|
+
h("div", { className: "dru-ia-hint" }, "不下载也能用其它通道:企业微信、钉钉都可正常配置;飞书随时回来装即可,不会影响已有通知。")
|
|
6951
|
+
] }));
|
|
6952
|
+
}
|
|
6953
|
+
|
|
6954
|
+
/** 飞书配置页(依赖已装):官方文档 + 3 步主路径(细步骤折叠)+ 只有 App ID / App Secret。 */
|
|
6955
|
+
function renderFeishuStep(close) {
|
|
6956
|
+
var deps = imDeps || {};
|
|
6957
|
+
if (deps.installed !== true) return renderFeishuDepsGate(close);
|
|
6958
|
+
var f = (imBots && imBots.feishu) || {};
|
|
6959
|
+
var st = (imBots && imBots.status && imBots.status.feishu) || {};
|
|
6960
|
+
var err = imPlatErr || {};
|
|
6961
|
+
// 自动绑定状态(业主:接收人不需要用户填,由插件自动发现)
|
|
6962
|
+
var bindLine = (function () {
|
|
6963
|
+
var bound = String(st.boundChatId || "").trim();
|
|
6964
|
+
if (!bound) return h("div", { className: "dru-ia-state" }, druIcon("chat"),
|
|
6965
|
+
"连接后会自动绑定你的机器人所在群/你与机器人的私聊(不需要操作)");
|
|
6966
|
+
var type = String(st.boundChatType || "").toLowerCase();
|
|
6967
|
+
var src = String(st.receiveIdSource || "").toLowerCase();
|
|
6968
|
+
var isP2p = type === "p2p" || src === "p2p" || src === "private";
|
|
6969
|
+
var name = isP2p ? "私聊" : (/^oc_/.test(bound) || /^ou_/.test(bound) ? ("群 " + iaShortId(bound)) : bound);
|
|
6970
|
+
return h("div", { className: "dru-ia-state is-ok" }, druIcon("check"),
|
|
6971
|
+
"已自动绑定:" + name,
|
|
6972
|
+
src ? h("span", { className: "dru-ia-hint", style: { marginLeft: 6 } }, "(自动发现,无需配置)") : null);
|
|
6973
|
+
})();
|
|
6974
|
+
return iaDialog(Object.assign({}, {
|
|
6975
|
+
title: "飞书机器人",
|
|
6976
|
+
sub: "依赖已就绪(v" + (deps.version || f.sdkVersion || "?") + ");只需填 App ID 与 App Secret",
|
|
6977
|
+
onClose: close,
|
|
6978
|
+
foot: [
|
|
6979
|
+
h("button", { type: "button", className: "dru-ia-btn is-primary", disabled: imPlatBusy !== "", onClick: function () { saveImPlatform("feishu", "test"); } },
|
|
6980
|
+
imPlatBusy === "test" ? "连接中…" : "保存并连接"),
|
|
6981
|
+
h("button", { type: "button", className: "dru-ia-btn", disabled: imPlatBusy !== "", onClick: function () { saveImPlatform("feishu", "save"); } },
|
|
6982
|
+
imPlatBusy === "save" ? "保存中…" : "仅保存"),
|
|
6983
|
+
h("button", { type: "button", className: "dru-ia-btn is-ghost", disabled: imPlatBusy !== "", onClick: function () {
|
|
6984
|
+
if (imPlatBusy) return;
|
|
6985
|
+
setImPlatBusy("test"); setImPlatMsg(null);
|
|
6986
|
+
post("/dsh-remote/im-bots/test", { platform: "feishu" }, 15000).then(function (r) {
|
|
6987
|
+
setImPlatMsg({ kind: r && r.connected ? "ok" : "warn", text: r && r.connected ? "已连接" : ("连接失败" + (r && r.lastError ? ":" + r.lastError : "(稍后自动重试)")) });
|
|
6988
|
+
}).catch(function (e) { setImPlatMsg({ kind: "err", text: "测试失败:" + ((e && e.message) || e) }); })
|
|
6989
|
+
.finally(function () { setImPlatBusy(""); });
|
|
6990
|
+
} }, "测试")
|
|
6991
|
+
]
|
|
6992
|
+
}, { children: [
|
|
6993
|
+
// 官方入口固定顶部(业主给的两个链接)
|
|
6994
|
+
h("div", { className: "dru-ia-hint" },
|
|
6995
|
+
"官方入口:",
|
|
6996
|
+
h("a", { className: "dru-ia-tier-link", href: FEISHU_DOCS.createApp, target: "_blank", rel: "noopener" }, "创建企业自建应用"),
|
|
6997
|
+
" · ",
|
|
6998
|
+
h("a", { className: "dru-ia-tier-link", href: FEISHU_DOCS.cardBot, target: "_blank", rel: "noopener" }, "卡片交互机器人文档")),
|
|
6999
|
+
// 主路径只有 3 件事;细步骤折叠(业主:别让用户读 8 步才敢动手)
|
|
7000
|
+
h("div", { className: "dru-ia-field" },
|
|
7001
|
+
h("div", { className: "dru-ia-hint" }, "三步就能用:"),
|
|
7002
|
+
h("ol", { className: "dru-ia-steps" }, FEISHU_MAIN_STEPS.map(function (t, i) {
|
|
7003
|
+
return h("li", { key: "m" + i }, t);
|
|
7004
|
+
})),
|
|
7005
|
+
h("button", {
|
|
7006
|
+
type: "button", className: "dru-ia-disclose", "aria-expanded": imFeishuWizard ? "true" : "false",
|
|
7007
|
+
onClick: function () { setImFeishuWizard(!imFeishuWizard); }
|
|
7008
|
+
}, "细步骤(机器人能力 / 权限 / 长连接 / 发布)", druIcon(imFeishuWizard ? "left" : "right")),
|
|
7009
|
+
imFeishuWizard
|
|
7010
|
+
? h("div", null,
|
|
7011
|
+
h("ol", { className: "dru-ia-steps" }, FEISHU_DETAIL_STEPS.map(function (t, i) {
|
|
7012
|
+
return h("li", { key: "d" + i }, t);
|
|
7013
|
+
})),
|
|
7014
|
+
h("div", { className: "dru-ia-state is-warn", role: "note" },
|
|
7015
|
+
"顺序很重要:保存事件/回调配置时飞书的「长连接必须已在线」——",
|
|
7016
|
+
"请**先在上面填凭据点「保存并连接」让插件连上**,再回飞书后台保存事件配置;顺序反了会保存失败。"))
|
|
7017
|
+
: null),
|
|
7018
|
+
// 自动绑定状态行(不再让用户填接收人)
|
|
7019
|
+
bindLine,
|
|
7020
|
+
iaField("App ID", "dru-fs-appid", h("input", {
|
|
7021
|
+
id: "dru-fs-appid", className: "dru-ia-input", type: "text", value: imFeishuAppId, autoComplete: "off", spellCheck: false,
|
|
7022
|
+
placeholder: "cli_xxxxxxxx", "aria-invalid": err.appId ? "true" : "false",
|
|
7023
|
+
onChange: function (e) { setImFeishuAppId(e.target.value); }
|
|
7024
|
+
}), err.appId || ""),
|
|
7025
|
+
iaField("App Secret", "dru-fs-secret", h("input", {
|
|
7026
|
+
id: "dru-fs-secret", className: "dru-ia-input", type: "password", value: imFeishuSecret, autoComplete: "new-password", spellCheck: false,
|
|
7027
|
+
placeholder: f.hasSecret ? "已保存(留空表示不修改)" : "从应用详情 → 凭证与基础信息复制",
|
|
7028
|
+
"aria-invalid": err.appSecret ? "true" : "false",
|
|
7029
|
+
onChange: function (e) { setImFeishuSecret(e.target.value); }
|
|
7030
|
+
}), err.appSecret || "", "只保存在本机;已保存的 Secret 永远不回显。"),
|
|
7031
|
+
imPlatStateLine(st)
|
|
7032
|
+
] }));
|
|
7033
|
+
}
|
|
7034
|
+
|
|
6557
7035
|
/** 还没支持的平台:只给**诚实**的空状态(说明 + 反馈入口),绝不放假表单/假入口。 */
|
|
6558
7036
|
function renderComingSoonStep(close, kind) {
|
|
6559
7037
|
var meta = {
|
|
@@ -6600,12 +7078,30 @@ window.__ModuleLoader__.load({
|
|
|
6600
7078
|
if (iaModal !== "channel") return null;
|
|
6601
7079
|
if (iaChStep === "wecom") return renderWecomStep(closeIAModal);
|
|
6602
7080
|
if (iaChStep === "wechat") return renderWechatStep(closeIAModal);
|
|
6603
|
-
if (iaChStep === "
|
|
7081
|
+
if (iaChStep === "dingtalk") return renderDingtalkStep(closeIAModal);
|
|
7082
|
+
if (iaChStep === "feishu") return renderFeishuStep(closeIAModal);
|
|
7083
|
+
if (iaChStep === "webhook") return renderComingSoonStep(closeIAModal, "webhook");
|
|
6604
7084
|
var w = (imBots && imBots.wecom) || {};
|
|
6605
7085
|
var ws = (imBots && imBots.status) || {};
|
|
6606
7086
|
var wecomSub = ws.connected
|
|
6607
7087
|
? "已连接 · 推送消息到企业微信"
|
|
6608
7088
|
: (w.enabled || w.hasSecret ? "已配置,等待连接" : "未配置 · 填 Bot ID 与 Secret 即可");
|
|
7089
|
+
var d = (imBots && imBots.dingtalk) || {};
|
|
7090
|
+
var f = (imBots && imBots.feishu) || {};
|
|
7091
|
+
var dst = (imBots && imBots.status && imBots.status.dingtalk) || {};
|
|
7092
|
+
var fst = (imBots && imBots.status && imBots.status.feishu) || {};
|
|
7093
|
+
var dingSub = dst.connected
|
|
7094
|
+
? "已连接 · 推送消息到钉钉"
|
|
7095
|
+
: (d.enabled || d.hasSecret ? "已配置,等待连接" : "未配置 · 填 Client ID / Secret / Robot Code");
|
|
7096
|
+
var feishuSub = !(imDeps && imDeps.installed)
|
|
7097
|
+
? "需要先下载依赖(约 41MB,仅装一次)"
|
|
7098
|
+
: (fst.connected ? "已连接 · 推送消息到飞书" : (f.enabled || f.hasSecret ? "已配置,等待连接" : "依赖已就绪 · 填 App ID / Secret / 接收人"));
|
|
7099
|
+
var resetPlatStep = function (step) {
|
|
7100
|
+
setIaChStep(step);
|
|
7101
|
+
setImPlatMsg(null);
|
|
7102
|
+
setImPlatErr({});
|
|
7103
|
+
if (step === "feishu") loadImDeps();
|
|
7104
|
+
};
|
|
6609
7105
|
return iaDialog(Object.assign({}, {
|
|
6610
7106
|
title: "通知与消息通道",
|
|
6611
7107
|
sub: "选一个平台,让电脑端在任务完成、出错或需要拍板时主动通知你",
|
|
@@ -6613,10 +7109,10 @@ window.__ModuleLoader__.load({
|
|
|
6613
7109
|
foot: h("button", { type: "button", className: "dru-ia-btn", onClick: closeIAModal }, "关闭")
|
|
6614
7110
|
}, { children: [h("div", { className: "dru-ia-list" },
|
|
6615
7111
|
iaChannelRow("chat", "企业微信智能机器人", wecomSub, function () { setIaChStep("wecom"); setImBotsMsg(null); setImBotsFieldErr({}); }, "配置"),
|
|
7112
|
+
iaChannelRow("send", "钉钉机器人", dingSub, function () { resetPlatStep("dingtalk"); }, "配置"),
|
|
7113
|
+
iaChannelRow("send", "飞书机器人", feishuSub, function () { resetPlatStep("feishu"); }, imDeps && imDeps.installed ? "配置" : "下载依赖"),
|
|
6616
7114
|
iaChannelRow("chat", "微信机器人(扫码绑定)", "扫码绑定 · 在微信里收通知 / 回数字拍板", function () { setIaChStep("wechat"); }, "打开"),
|
|
6617
|
-
iaChannelRow("
|
|
6618
|
-
iaChannelRow("send", "钉钉机器人", "即将支持 · 需要企业管理员创建应用", function () { setIaChStep("dingtalk"); }, "查看"),
|
|
6619
|
-
iaChannelRow("code", "高级 · Webhook", "高级用法 · 自备公网端点", function () { setIaChStep("webhook"); }, "查看")
|
|
7115
|
+
iaChannelRow("code", "高级 · Webhook", "免费 · 高级用法:自备公网端点", function () { setIaChStep("webhook"); }, "查看")
|
|
6620
7116
|
)] }));
|
|
6621
7117
|
}
|
|
6622
7118
|
|