@zhin.js/adapter-icqq 6.0.2 → 7.0.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 +65 -0
- package/README.md +48 -435
- package/adapters/icqq.ts +92 -0
- package/agent/tools/announce.ts +2 -2
- package/agent/tools/essence.ts +2 -2
- package/agent/tools/friend_list.ts +2 -2
- package/agent/tools/group_files.ts +2 -2
- package/agent/tools/group_invite.ts +2 -2
- package/agent/tools/group_list.ts +2 -2
- package/agent/tools/group_sign.ts +2 -2
- package/agent/tools/list_muted.ts +2 -2
- package/agent/tools/poke.ts +2 -2
- package/agent/tools/send_user_like.ts +2 -2
- package/agent/tools/set_anonymous.ts +2 -2
- package/agent/tools/set_title.ts +2 -2
- package/lib/agent-prompt.d.ts +2 -0
- package/lib/{src/agent-prompt.js → agent-prompt.js} +0 -1
- package/lib/cq-message.d.ts +9 -0
- package/lib/{src/cq-message.js → cq-message.js} +0 -1
- package/lib/endpoint.d.ts +101 -0
- package/lib/endpoint.js +715 -0
- package/lib/forward-msg.d.ts +26 -0
- package/lib/{src/forward-msg.js → forward-msg.js} +0 -1
- package/lib/icqq-agent-deps.d.ts +25 -0
- package/lib/icqq-agent-deps.js +32 -0
- package/lib/icqq-guild.d.ts +53 -0
- package/lib/{src/icqq-guild.js → icqq-guild.js} +4 -2
- package/lib/icqq-inbound.d.ts +139 -0
- package/lib/{src/icqq-inbound.js → icqq-inbound.js} +27 -3
- package/lib/icqq-inbox.d.ts +33 -0
- package/lib/icqq-inbox.js +129 -0
- package/lib/index.d.ts +6 -0
- package/lib/index.js +6 -0
- package/lib/ipc-client.d.ts +73 -0
- package/lib/{src/ipc-client.js → ipc-client.js} +0 -1
- package/lib/outbound-media.d.ts +13 -0
- package/lib/{src/outbound-media.js → outbound-media.js} +0 -1
- package/lib/protocol.d.ts +269 -0
- package/lib/{src/protocol.js → protocol.js} +124 -2
- package/lib/types.d.ts +87 -0
- package/lib/{src/types.js → types.js} +0 -1
- package/package.json +49 -45
- package/plugin.ts +32 -0
- package/schema.json +104 -0
- package/src/endpoint.ts +704 -795
- package/src/icqq-agent-deps.ts +48 -9
- package/src/icqq-guild.ts +10 -4
- package/src/icqq-inbound.ts +31 -2
- package/src/icqq-inbox.ts +155 -0
- package/src/index.ts +36 -69
- package/src/protocol.ts +191 -1
- package/src/types.ts +16 -0
- package/client/ICQQManagement.tsx +0 -147
- package/client/LoginAssistPanel.tsx +0 -300
- package/client/index.tsx +0 -11
- package/client/tsconfig.json +0 -7
- package/client/utils/api.ts +0 -30
- package/dist/index.js +0 -34
- package/lib/agent/tools/announce.js +0 -21
- package/lib/agent/tools/announce.js.map +0 -1
- package/lib/agent/tools/essence.js +0 -22
- package/lib/agent/tools/essence.js.map +0 -1
- package/lib/agent/tools/friend_list.js +0 -19
- package/lib/agent/tools/friend_list.js.map +0 -1
- package/lib/agent/tools/group_files.js +0 -29
- package/lib/agent/tools/group_files.js.map +0 -1
- package/lib/agent/tools/group_invite.js +0 -20
- package/lib/agent/tools/group_invite.js.map +0 -1
- package/lib/agent/tools/group_list.js +0 -20
- package/lib/agent/tools/group_list.js.map +0 -1
- package/lib/agent/tools/group_sign.js +0 -19
- package/lib/agent/tools/group_sign.js.map +0 -1
- package/lib/agent/tools/list_muted.js +0 -23
- package/lib/agent/tools/list_muted.js.map +0 -1
- package/lib/agent/tools/poke.js +0 -20
- package/lib/agent/tools/poke.js.map +0 -1
- package/lib/agent/tools/send_user_like.js +0 -22
- package/lib/agent/tools/send_user_like.js.map +0 -1
- package/lib/agent/tools/set_anonymous.js +0 -22
- package/lib/agent/tools/set_anonymous.js.map +0 -1
- package/lib/agent/tools/set_title.js +0 -25
- package/lib/agent/tools/set_title.js.map +0 -1
- package/lib/src/adapter.js +0 -128
- package/lib/src/adapter.js.map +0 -1
- package/lib/src/agent-prompt.js.map +0 -1
- package/lib/src/cq-message.js.map +0 -1
- package/lib/src/endpoint.js +0 -755
- package/lib/src/endpoint.js.map +0 -1
- package/lib/src/forward-msg.js.map +0 -1
- package/lib/src/get-msg.js +0 -46
- package/lib/src/get-msg.js.map +0 -1
- package/lib/src/icqq-agent-deps.js +0 -10
- package/lib/src/icqq-agent-deps.js.map +0 -1
- package/lib/src/icqq-guild.js.map +0 -1
- package/lib/src/icqq-inbound.js.map +0 -1
- package/lib/src/icqq-login-assist-bridge.js +0 -148
- package/lib/src/icqq-login-assist-bridge.js.map +0 -1
- package/lib/src/icqq-side-events.js +0 -130
- package/lib/src/icqq-side-events.js.map +0 -1
- package/lib/src/index.js +0 -50
- package/lib/src/index.js.map +0 -1
- package/lib/src/ipc-client.js.map +0 -1
- package/lib/src/login-assist-routes.js +0 -29
- package/lib/src/login-assist-routes.js.map +0 -1
- package/lib/src/login-ipc-contract.js +0 -35
- package/lib/src/login-ipc-contract.js.map +0 -1
- package/lib/src/outbound-media.js.map +0 -1
- package/lib/src/protocol.js.map +0 -1
- package/lib/src/routes.js +0 -67
- package/lib/src/routes.js.map +0 -1
- package/lib/src/segment-mapper.js +0 -2
- package/lib/src/segment-mapper.js.map +0 -1
- package/lib/src/tools/index.js +0 -23
- package/lib/src/tools/index.js.map +0 -1
- package/lib/src/types.js.map +0 -1
- package/plugin.yml +0 -3
- package/src/adapter.ts +0 -151
- package/src/get-msg.ts +0 -56
- package/src/icqq-login-assist-bridge.ts +0 -196
- package/src/icqq-side-events.ts +0 -143
- package/src/login-assist-routes.ts +0 -39
- package/src/login-ipc-contract.ts +0 -52
- package/src/routes.ts +0 -83
- package/src/segment-mapper.ts +0 -1
- package/src/tools/index.ts +0 -31
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
import { useCallback, useEffect, useState } from "react";
|
|
2
|
-
import { Activity, Bot, Endpoint, LogIn, Users, RefreshCw, Wifi, WifiOff, Loader2 } from "lucide-react";
|
|
3
|
-
import LoginAssistPanel from "./LoginAssistPanel";
|
|
4
|
-
import { apiFetch } from "./utils/api";
|
|
5
|
-
|
|
6
|
-
interface EndpointRow {
|
|
7
|
-
name: string;
|
|
8
|
-
connected: boolean;
|
|
9
|
-
groupCount: number;
|
|
10
|
-
friendCount: number;
|
|
11
|
-
loginMode: string;
|
|
12
|
-
status: string;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
type Tab = "overview" | "login";
|
|
16
|
-
|
|
17
|
-
export default function ICQQManagement() {
|
|
18
|
-
const [tab, setTab] = useState<Tab>("overview");
|
|
19
|
-
const [endpoints, setEndpoints] = useState<EndpointRow[]>([]);
|
|
20
|
-
const [loading, setLoading] = useState(true);
|
|
21
|
-
const [err, setErr] = useState<string | null>(null);
|
|
22
|
-
|
|
23
|
-
const loadBots = useCallback(async () => {
|
|
24
|
-
setLoading(true);
|
|
25
|
-
setErr(null);
|
|
26
|
-
try {
|
|
27
|
-
const res = await apiFetch("/api/icqq/endpoints");
|
|
28
|
-
const json = (await res.json()) as { success?: boolean; data?: EndpointRow[]; message?: string };
|
|
29
|
-
if (!res.ok || !json.success) throw new Error(json.message || "加载失败");
|
|
30
|
-
setEndpoints(Array.isArray(json.data) ? json.data : []);
|
|
31
|
-
} catch (e) {
|
|
32
|
-
setErr((e as Error).message);
|
|
33
|
-
setEndpoints([]);
|
|
34
|
-
} finally {
|
|
35
|
-
setLoading(false);
|
|
36
|
-
}
|
|
37
|
-
}, []);
|
|
38
|
-
|
|
39
|
-
useEffect(() => {
|
|
40
|
-
if (tab === "overview") void loadBots();
|
|
41
|
-
}, [tab, loadBots]);
|
|
42
|
-
|
|
43
|
-
return (
|
|
44
|
-
<div className="p-6 max-w-5xl mx-auto space-y-5">
|
|
45
|
-
{/* Header */}
|
|
46
|
-
<div className="flex items-center justify-between">
|
|
47
|
-
<div>
|
|
48
|
-
<h1 className="text-2xl font-bold flex items-center gap-2">
|
|
49
|
-
<Bot className="w-6 h-6" /> ICQQ 管理
|
|
50
|
-
</h1>
|
|
51
|
-
<p className="text-sm text-muted-foreground mt-1">
|
|
52
|
-
机器人概览与登录辅助(扫码 / 验证码 / 滑块)
|
|
53
|
-
</p>
|
|
54
|
-
</div>
|
|
55
|
-
{tab === "overview" && (
|
|
56
|
-
<button
|
|
57
|
-
onClick={loadBots}
|
|
58
|
-
disabled={loading}
|
|
59
|
-
className="flex items-center gap-1 px-3 py-1.5 rounded bg-blue-500 text-white hover:bg-blue-600 disabled:opacity-50 text-sm"
|
|
60
|
-
>
|
|
61
|
-
<RefreshCw className={`w-4 h-4 ${loading ? "animate-spin" : ""}`} /> 刷新
|
|
62
|
-
</button>
|
|
63
|
-
)}
|
|
64
|
-
</div>
|
|
65
|
-
|
|
66
|
-
{/* Tabs */}
|
|
67
|
-
<div className="flex gap-1 border-b">
|
|
68
|
-
<button
|
|
69
|
-
onClick={() => setTab("overview")}
|
|
70
|
-
className={`px-4 py-2 text-sm font-medium border-b-2 transition-colors ${
|
|
71
|
-
tab === "overview"
|
|
72
|
-
? "border-blue-500 text-blue-600"
|
|
73
|
-
: "border-transparent text-gray-500 hover:text-gray-700"
|
|
74
|
-
}`}
|
|
75
|
-
>
|
|
76
|
-
<span className="flex items-center gap-1.5">
|
|
77
|
-
<Bot className="w-4 h-4" /> 概览
|
|
78
|
-
</span>
|
|
79
|
-
</button>
|
|
80
|
-
<button
|
|
81
|
-
onClick={() => setTab("login")}
|
|
82
|
-
className={`px-4 py-2 text-sm font-medium border-b-2 transition-colors ${
|
|
83
|
-
tab === "login"
|
|
84
|
-
? "border-blue-500 text-blue-600"
|
|
85
|
-
: "border-transparent text-gray-500 hover:text-gray-700"
|
|
86
|
-
}`}
|
|
87
|
-
>
|
|
88
|
-
<span className="flex items-center gap-1.5">
|
|
89
|
-
<LogIn className="w-4 h-4" /> 登录辅助
|
|
90
|
-
</span>
|
|
91
|
-
</button>
|
|
92
|
-
</div>
|
|
93
|
-
|
|
94
|
-
{/* Overview Tab */}
|
|
95
|
-
{tab === "overview" && (
|
|
96
|
-
<>
|
|
97
|
-
{err && (
|
|
98
|
-
<div className="p-3 bg-red-50 text-red-600 rounded border border-red-200 text-sm dark:bg-red-900/20 dark:text-red-400 dark:border-red-800">
|
|
99
|
-
{err}
|
|
100
|
-
</div>
|
|
101
|
-
)}
|
|
102
|
-
{loading ? (
|
|
103
|
-
<div className="flex justify-center py-12">
|
|
104
|
-
<Loader2 className="w-6 h-6 animate-spin text-blue-500" />
|
|
105
|
-
</div>
|
|
106
|
-
) : endpoints.length === 0 ? (
|
|
107
|
-
<div className="text-center text-muted-foreground py-12">
|
|
108
|
-
暂无 ICQQ Endpoint 实例
|
|
109
|
-
</div>
|
|
110
|
-
) : (
|
|
111
|
-
<div className="grid gap-4 md:grid-cols-2">
|
|
112
|
-
{endpoints.map((endpoint) => (
|
|
113
|
-
<div key={endpoint.name} className="border rounded-lg p-4 bg-card shadow-sm">
|
|
114
|
-
<div className="flex items-center justify-between mb-3">
|
|
115
|
-
<span className="font-medium text-lg">{endpoint.name}</span>
|
|
116
|
-
{endpoint.connected ? (
|
|
117
|
-
<span className="flex items-center gap-1 text-green-600 text-sm">
|
|
118
|
-
<Wifi className="w-4 h-4" /> 在线
|
|
119
|
-
</span>
|
|
120
|
-
) : (
|
|
121
|
-
<span className="flex items-center gap-1 text-gray-400 text-sm">
|
|
122
|
-
<WifiOff className="w-4 h-4" /> 离线
|
|
123
|
-
</span>
|
|
124
|
-
)}
|
|
125
|
-
</div>
|
|
126
|
-
<div className="space-y-2 text-sm text-muted-foreground">
|
|
127
|
-
<div className="flex items-center gap-1.5">
|
|
128
|
-
<Users className="w-3.5 h-3.5" />
|
|
129
|
-
群 {endpoint.groupCount} · 好友 {endpoint.friendCount}
|
|
130
|
-
</div>
|
|
131
|
-
<div className="flex items-center gap-1.5">
|
|
132
|
-
<Activity className="w-3.5 h-3.5" />
|
|
133
|
-
登录方式 {endpoint.loginMode} · {endpoint.status}
|
|
134
|
-
</div>
|
|
135
|
-
</div>
|
|
136
|
-
</div>
|
|
137
|
-
))}
|
|
138
|
-
</div>
|
|
139
|
-
)}
|
|
140
|
-
</>
|
|
141
|
-
)}
|
|
142
|
-
|
|
143
|
-
{/* Login Tab */}
|
|
144
|
-
{tab === "login" && <LoginAssistPanel />}
|
|
145
|
-
</div>
|
|
146
|
-
);
|
|
147
|
-
}
|
|
@@ -1,300 +0,0 @@
|
|
|
1
|
-
import { useCallback, useEffect, useRef, useState } from "react";
|
|
2
|
-
import {
|
|
3
|
-
LogIn,
|
|
4
|
-
QrCode,
|
|
5
|
-
MessageSquare,
|
|
6
|
-
MousePointer,
|
|
7
|
-
Smartphone,
|
|
8
|
-
AlertCircle,
|
|
9
|
-
Loader2,
|
|
10
|
-
X,
|
|
11
|
-
} from "lucide-react";
|
|
12
|
-
import { apiFetch } from "./utils/api";
|
|
13
|
-
|
|
14
|
-
interface PendingLoginTask {
|
|
15
|
-
id: string;
|
|
16
|
-
adapter: string;
|
|
17
|
-
endpointId: string;
|
|
18
|
-
type: string;
|
|
19
|
-
payload?: {
|
|
20
|
-
message?: string;
|
|
21
|
-
image?: string;
|
|
22
|
-
url?: string;
|
|
23
|
-
[key: string]: unknown;
|
|
24
|
-
};
|
|
25
|
-
createdAt: number;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const POLL_BASE_MS = 2_000;
|
|
29
|
-
const POLL_MAX_MS = 15_000;
|
|
30
|
-
|
|
31
|
-
const TYPE_META: Record<string, { icon: React.ReactNode; label: string }> = {
|
|
32
|
-
qrcode: { icon: <QrCode className="w-4 h-4" />, label: "扫码登录" },
|
|
33
|
-
sms: { icon: <MessageSquare className="w-4 h-4" />, label: "短信验证码" },
|
|
34
|
-
device: { icon: <Smartphone className="w-4 h-4" />, label: "设备验证" },
|
|
35
|
-
auth: { icon: <Smartphone className="w-4 h-4" />, label: "身份验证" },
|
|
36
|
-
slider: { icon: <MousePointer className="w-4 h-4" />, label: "滑块验证" },
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
export default function LoginAssistPanel() {
|
|
40
|
-
const [pending, setPending] = useState<PendingLoginTask[]>([]);
|
|
41
|
-
const [loading, setLoading] = useState(true);
|
|
42
|
-
const [error, setError] = useState<string | null>(null);
|
|
43
|
-
const [submitting, setSubmitting] = useState<Record<string, boolean>>({});
|
|
44
|
-
const [inputValues, setInputValues] = useState<Record<string, string>>({});
|
|
45
|
-
|
|
46
|
-
/* ── Exponential-backoff polling ── */
|
|
47
|
-
const consecutiveEmptyRef = useRef(0);
|
|
48
|
-
const timerRef = useRef<ReturnType<typeof setTimeout>>();
|
|
49
|
-
|
|
50
|
-
const fetchPending = useCallback(async () => {
|
|
51
|
-
try {
|
|
52
|
-
const res = await apiFetch("/api/login-assist/pending");
|
|
53
|
-
if (!res.ok) throw new Error("获取待办失败");
|
|
54
|
-
const data = (await res.json()) as unknown;
|
|
55
|
-
const list = Array.isArray(data) ? (data as PendingLoginTask[]) : [];
|
|
56
|
-
const filtered = list.filter((t) => t.adapter === "icqq");
|
|
57
|
-
setPending(filtered);
|
|
58
|
-
setError(null);
|
|
59
|
-
consecutiveEmptyRef.current = filtered.length > 0 ? 0 : consecutiveEmptyRef.current + 1;
|
|
60
|
-
} catch (err) {
|
|
61
|
-
setError((err as Error).message);
|
|
62
|
-
consecutiveEmptyRef.current++;
|
|
63
|
-
} finally {
|
|
64
|
-
setLoading(false);
|
|
65
|
-
}
|
|
66
|
-
}, []);
|
|
67
|
-
|
|
68
|
-
const scheduleNext = useCallback(() => {
|
|
69
|
-
const delay = Math.min(
|
|
70
|
-
POLL_BASE_MS * Math.pow(1.5, consecutiveEmptyRef.current),
|
|
71
|
-
POLL_MAX_MS,
|
|
72
|
-
);
|
|
73
|
-
timerRef.current = setTimeout(async () => {
|
|
74
|
-
await fetchPending();
|
|
75
|
-
scheduleNext();
|
|
76
|
-
}, delay);
|
|
77
|
-
}, [fetchPending]);
|
|
78
|
-
|
|
79
|
-
useEffect(() => {
|
|
80
|
-
fetchPending().then(scheduleNext);
|
|
81
|
-
return () => clearTimeout(timerRef.current);
|
|
82
|
-
}, [fetchPending, scheduleNext]);
|
|
83
|
-
|
|
84
|
-
/* ── Actions ── */
|
|
85
|
-
const handleSubmit = async (id: string, value: string | Record<string, unknown>) => {
|
|
86
|
-
setSubmitting((s) => ({ ...s, [id]: true }));
|
|
87
|
-
try {
|
|
88
|
-
const res = await apiFetch("/api/login-assist/submit", {
|
|
89
|
-
method: "POST",
|
|
90
|
-
headers: { "Content-Type": "application/json" },
|
|
91
|
-
body: JSON.stringify({ id, value }),
|
|
92
|
-
});
|
|
93
|
-
if (!res.ok) throw new Error("提交失败");
|
|
94
|
-
setInputValues((v) => {
|
|
95
|
-
const next = { ...v };
|
|
96
|
-
delete next[id];
|
|
97
|
-
return next;
|
|
98
|
-
});
|
|
99
|
-
consecutiveEmptyRef.current = 0;
|
|
100
|
-
await fetchPending();
|
|
101
|
-
} catch (err) {
|
|
102
|
-
setError((err as Error).message);
|
|
103
|
-
} finally {
|
|
104
|
-
setSubmitting((s) => ({ ...s, [id]: false }));
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
const handleCancel = async (id: string) => {
|
|
109
|
-
try {
|
|
110
|
-
const res = await apiFetch("/api/login-assist/cancel", {
|
|
111
|
-
method: "POST",
|
|
112
|
-
headers: { "Content-Type": "application/json" },
|
|
113
|
-
body: JSON.stringify({ id }),
|
|
114
|
-
});
|
|
115
|
-
if (res.ok) await fetchPending();
|
|
116
|
-
} catch {
|
|
117
|
-
/* ignore */
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
/* ── Loading skeleton ── */
|
|
122
|
-
if (loading && pending.length === 0) {
|
|
123
|
-
return (
|
|
124
|
-
<div className="flex justify-center py-12">
|
|
125
|
-
<Loader2 className="w-6 h-6 animate-spin text-blue-500" />
|
|
126
|
-
</div>
|
|
127
|
-
);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
return (
|
|
131
|
-
<div className="space-y-4">
|
|
132
|
-
<p className="text-sm text-muted-foreground">
|
|
133
|
-
扫码、短信或滑块等验证会出现在下方;刷新页面后仍可继续处理(仅 ICQQ 待办)。
|
|
134
|
-
</p>
|
|
135
|
-
|
|
136
|
-
{error && (
|
|
137
|
-
<div className="flex items-center gap-2 p-3 rounded border border-red-200 bg-red-50 text-red-600 text-sm dark:bg-red-900/20 dark:text-red-400 dark:border-red-800">
|
|
138
|
-
<AlertCircle className="w-4 h-4 shrink-0" />
|
|
139
|
-
<span>{error}</span>
|
|
140
|
-
<button onClick={() => setError(null)} className="ml-auto">
|
|
141
|
-
<X className="w-3.5 h-3.5" />
|
|
142
|
-
</button>
|
|
143
|
-
</div>
|
|
144
|
-
)}
|
|
145
|
-
|
|
146
|
-
{pending.length === 0 ? (
|
|
147
|
-
<div className="border rounded-lg bg-card p-12 text-center">
|
|
148
|
-
<LogIn className="w-16 h-16 mx-auto mb-4 opacity-25" />
|
|
149
|
-
<h3 className="text-lg font-semibold mb-1">暂无待办</h3>
|
|
150
|
-
<p className="text-sm text-muted-foreground">机器人需要验证时,待办将显示在此处</p>
|
|
151
|
-
</div>
|
|
152
|
-
) : (
|
|
153
|
-
<div className="space-y-4">
|
|
154
|
-
{pending.map((task) => {
|
|
155
|
-
const meta = TYPE_META[task.type] ?? {
|
|
156
|
-
icon: <LogIn className="w-4 h-4" />,
|
|
157
|
-
label: task.type,
|
|
158
|
-
};
|
|
159
|
-
return (
|
|
160
|
-
<div key={task.id} className="border rounded-lg bg-card p-4 shadow-sm">
|
|
161
|
-
{/* Header */}
|
|
162
|
-
<div className="flex items-start justify-between flex-wrap gap-2 mb-2">
|
|
163
|
-
<div className="flex items-center gap-2 font-semibold">
|
|
164
|
-
{meta.icon} {meta.label}
|
|
165
|
-
</div>
|
|
166
|
-
<div className="flex gap-1 text-xs">
|
|
167
|
-
<span className="px-2 py-0.5 rounded border">{task.adapter}</span>
|
|
168
|
-
<span className="px-2 py-0.5 rounded bg-muted">{task.endpointId}</span>
|
|
169
|
-
</div>
|
|
170
|
-
</div>
|
|
171
|
-
|
|
172
|
-
{/* Message */}
|
|
173
|
-
{task.payload?.message && (
|
|
174
|
-
<p className="text-sm text-muted-foreground mb-3">{task.payload.message}</p>
|
|
175
|
-
)}
|
|
176
|
-
|
|
177
|
-
{/* QR Code */}
|
|
178
|
-
{task.type === "qrcode" && task.payload?.image && (
|
|
179
|
-
<div className="flex justify-center p-4 bg-muted/30 rounded-lg mb-3">
|
|
180
|
-
<img
|
|
181
|
-
src={String(task.payload.image)}
|
|
182
|
-
alt="登录二维码"
|
|
183
|
-
className="max-w-[200px] w-full h-auto"
|
|
184
|
-
/>
|
|
185
|
-
</div>
|
|
186
|
-
)}
|
|
187
|
-
|
|
188
|
-
{/* Slider / auth URL */}
|
|
189
|
-
{(task.type === "slider" || task.type === "auth") && task.payload?.url && (
|
|
190
|
-
<p className="text-sm break-all mb-3">
|
|
191
|
-
<span className="text-muted-foreground">验证链接:</span>{" "}
|
|
192
|
-
<a
|
|
193
|
-
href={String(task.payload.url)}
|
|
194
|
-
target="_blank"
|
|
195
|
-
rel="noopener noreferrer"
|
|
196
|
-
className="text-primary hover:underline"
|
|
197
|
-
>
|
|
198
|
-
{String(task.payload.url)}
|
|
199
|
-
</a>
|
|
200
|
-
</p>
|
|
201
|
-
)}
|
|
202
|
-
|
|
203
|
-
{/* system.login.auth 设备信息 */}
|
|
204
|
-
{task.type === "auth" && task.payload?.device && typeof task.payload.device === "object" && (
|
|
205
|
-
<div className="text-xs text-muted-foreground mb-3 space-y-1 rounded border p-3 bg-muted/20">
|
|
206
|
-
<div className="font-medium text-foreground">设备信息(登录续传用)</div>
|
|
207
|
-
{Object.entries(task.payload.device as Record<string, unknown>)
|
|
208
|
-
.filter(([, v]) => v != null && String(v) !== "")
|
|
209
|
-
.map(([k, v]) => (
|
|
210
|
-
<div key={k}>
|
|
211
|
-
<span className="opacity-70">{k}: </span>
|
|
212
|
-
<span className="font-mono break-all">{String(v)}</span>
|
|
213
|
-
</div>
|
|
214
|
-
))}
|
|
215
|
-
</div>
|
|
216
|
-
)}
|
|
217
|
-
|
|
218
|
-
{/* auth 确认 */}
|
|
219
|
-
{task.type === "auth" && (
|
|
220
|
-
<div className="flex gap-2 mt-3">
|
|
221
|
-
<button
|
|
222
|
-
className="h-9 px-4 rounded-md bg-primary text-primary-foreground text-sm disabled:opacity-50"
|
|
223
|
-
disabled={!!submitting[task.id]}
|
|
224
|
-
onClick={() => void handleSubmit(task.id, { done: true })}
|
|
225
|
-
>
|
|
226
|
-
{submitting[task.id] ? "提交中…" : "我已完成验证"}
|
|
227
|
-
</button>
|
|
228
|
-
<button
|
|
229
|
-
className="h-9 px-4 rounded-md border text-sm hover:bg-accent transition-colors"
|
|
230
|
-
onClick={() => void handleCancel(task.id)}
|
|
231
|
-
>
|
|
232
|
-
取消
|
|
233
|
-
</button>
|
|
234
|
-
</div>
|
|
235
|
-
)}
|
|
236
|
-
|
|
237
|
-
{/* Text input (sms / device / slider ticket) */}
|
|
238
|
-
{(task.type === "sms" || task.type === "device" || task.type === "slider") && (
|
|
239
|
-
<div className="flex flex-wrap gap-2 items-center">
|
|
240
|
-
<input
|
|
241
|
-
className="h-9 px-3 rounded-md border border-input bg-background text-sm max-w-[18rem] flex-1"
|
|
242
|
-
placeholder={task.type === "slider" ? "输入 ticket" : "输入验证码"}
|
|
243
|
-
value={inputValues[task.id] ?? ""}
|
|
244
|
-
onChange={(e) =>
|
|
245
|
-
setInputValues((v) => ({ ...v, [task.id]: e.target.value }))
|
|
246
|
-
}
|
|
247
|
-
onKeyDown={(e) => {
|
|
248
|
-
if (e.key === "Enter") {
|
|
249
|
-
const val = inputValues[task.id]?.trim();
|
|
250
|
-
if (val)
|
|
251
|
-
void handleSubmit(
|
|
252
|
-
task.id,
|
|
253
|
-
task.type === "slider" ? { ticket: val } : val,
|
|
254
|
-
);
|
|
255
|
-
}
|
|
256
|
-
}}
|
|
257
|
-
/>
|
|
258
|
-
<button
|
|
259
|
-
className="h-9 px-4 rounded-md bg-primary text-primary-foreground text-sm disabled:opacity-50"
|
|
260
|
-
disabled={submitting[task.id] || !inputValues[task.id]?.trim()}
|
|
261
|
-
onClick={() => {
|
|
262
|
-
const val = inputValues[task.id]?.trim();
|
|
263
|
-
if (val)
|
|
264
|
-
void handleSubmit(
|
|
265
|
-
task.id,
|
|
266
|
-
task.type === "slider" ? { ticket: val } : val,
|
|
267
|
-
);
|
|
268
|
-
}}
|
|
269
|
-
>
|
|
270
|
-
{submitting[task.id] ? "提交中…" : "提交"}
|
|
271
|
-
</button>
|
|
272
|
-
</div>
|
|
273
|
-
)}
|
|
274
|
-
|
|
275
|
-
{/* QR code actions */}
|
|
276
|
-
{task.type === "qrcode" && (
|
|
277
|
-
<div className="flex gap-2 mt-3">
|
|
278
|
-
<button
|
|
279
|
-
className="h-9 px-4 rounded-md bg-primary text-primary-foreground text-sm disabled:opacity-50"
|
|
280
|
-
disabled={!!submitting[task.id]}
|
|
281
|
-
onClick={() => void handleSubmit(task.id, { done: true })}
|
|
282
|
-
>
|
|
283
|
-
{submitting[task.id] ? "提交中…" : "我已扫码"}
|
|
284
|
-
</button>
|
|
285
|
-
<button
|
|
286
|
-
className="h-9 px-4 rounded-md border text-sm hover:bg-accent transition-colors"
|
|
287
|
-
onClick={() => void handleCancel(task.id)}
|
|
288
|
-
>
|
|
289
|
-
取消
|
|
290
|
-
</button>
|
|
291
|
-
</div>
|
|
292
|
-
)}
|
|
293
|
-
</div>
|
|
294
|
-
);
|
|
295
|
-
})}
|
|
296
|
-
</div>
|
|
297
|
-
)}
|
|
298
|
-
</div>
|
|
299
|
-
);
|
|
300
|
-
}
|
package/client/index.tsx
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { PluginRegisterHostApi } from '@zhin.js/contract'
|
|
2
|
-
import ICQQManagement from './ICQQManagement'
|
|
3
|
-
|
|
4
|
-
export function register(api: PluginRegisterHostApi) {
|
|
5
|
-
api.addRoute({
|
|
6
|
-
path: '/console/icqq',
|
|
7
|
-
name: 'ICQQ管理',
|
|
8
|
-
element: api.React.createElement(ICQQManagement, { hostReact: api.React }),
|
|
9
|
-
})
|
|
10
|
-
api.addTool({ id: 'icqq', name: 'ICQQ', path: '/console/icqq' })
|
|
11
|
-
}
|
package/client/tsconfig.json
DELETED
package/client/utils/api.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
const TOKEN_KEY = "zhin_api_token";
|
|
2
|
-
const API_BASE_KEY = "zhin_api_base";
|
|
3
|
-
|
|
4
|
-
export function getApiBase(): string {
|
|
5
|
-
const stored = localStorage.getItem(API_BASE_KEY)?.trim();
|
|
6
|
-
if (stored) return stored.replace(/\/$/, "");
|
|
7
|
-
if (typeof window !== "undefined") return window.location.origin;
|
|
8
|
-
return "";
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export function getToken(): string | null {
|
|
12
|
-
return localStorage.getItem(TOKEN_KEY);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export async function apiFetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response> {
|
|
16
|
-
const token = getToken();
|
|
17
|
-
const headers = new Headers(init?.headers);
|
|
18
|
-
if (token) headers.set("Authorization", `Bearer ${token}`);
|
|
19
|
-
|
|
20
|
-
const base = getApiBase();
|
|
21
|
-
const url =
|
|
22
|
-
typeof input === "string" && input.startsWith("/") ? `${base}${input}` : input;
|
|
23
|
-
|
|
24
|
-
const res = await fetch(url, { ...init, headers });
|
|
25
|
-
if (res.status === 401) {
|
|
26
|
-
localStorage.removeItem(TOKEN_KEY);
|
|
27
|
-
window.dispatchEvent(new CustomEvent("zhin:auth-required"));
|
|
28
|
-
}
|
|
29
|
-
return res;
|
|
30
|
-
}
|
package/dist/index.js
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import{useCallback as ye,useEffect as Re,useState as z}from"react";import{forwardRef as re,createElement as fe}from"react";var N=(...a)=>a.filter((u,f,s)=>!!u&&u.trim()!==""&&s.indexOf(u)===f).join(" ").trim();var Q=a=>a.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase();var J=a=>a.replace(/^([A-Z])|[\s-_]+(\w)/g,(u,f,s)=>s?s.toUpperCase():f.toLowerCase());var X=a=>{let u=J(a);return u.charAt(0).toUpperCase()+u.slice(1)};import{forwardRef as le,createElement as Y}from"react";var V={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"};var _=a=>{for(let u in a)if(u.startsWith("aria-")||u==="role"||u==="title")return!0;return!1};import{createContext as oe,useContext as ue,useMemo as Ee,createElement as Ne}from"react";var de=oe({});var j=()=>ue(de);var $=le(({color:a,size:u,strokeWidth:f,absoluteStrokeWidth:s,className:L="",children:i,iconNode:n,...h},x)=>{let{size:l=24,strokeWidth:m=2,absoluteStrokeWidth:G=!1,color:g="currentColor",className:D=""}=j()??{},P=s??G?Number(f??m)*24/Number(u??l):f??m;return Y("svg",{ref:x,...V,width:u??l??V.width,height:u??l??V.height,stroke:a??g,strokeWidth:P,className:N("lucide",D,L),...!i&&!_(h)&&{"aria-hidden":"true"},...h},[...n.map(([W,e])=>Y(W,e)),...Array.isArray(i)?i:[i]])});var o=(a,u)=>{let f=re(({className:s,...L},i)=>fe($,{ref:i,iconNode:u,className:N(`lucide-${Q(X(a))}`,`lucide-${a}`,s),...L}));return f.displayName=X(a),f};var se=[["path",{d:"M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2",key:"169zse"}]],F=o("activity",se);var ie=[["path",{d:"M12 8V4H8",key:"hb8ula"}],["rect",{width:"16",height:"12",x:"4",y:"8",rx:"2",key:"enze0r"}],["path",{d:"M2 14h2",key:"vft8re"}],["path",{d:"M20 14h2",key:"4cs60a"}],["path",{d:"M15 13v2",key:"1xurst"}],["path",{d:"M9 13v2",key:"rq6x2g"}]],A=o("bot",ie);var ce=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["line",{x1:"12",x2:"12",y1:"8",y2:"12",key:"1pkeuh"}],["line",{x1:"12",x2:"12.01",y1:"16",y2:"16",key:"4dfq90"}]],k=o("circle-alert",ce);var ne=[["path",{d:"M21 12a9 9 0 1 1-6.219-8.56",key:"13zald"}]],C=o("loader-circle",ne);var pe=[["path",{d:"m10 17 5-5-5-5",key:"1bsop3"}],["path",{d:"M15 12H3",key:"6jk70r"}],["path",{d:"M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4",key:"u53s6r"}]],w=o("log-in",pe);var me=[["path",{d:"M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z",key:"18887p"}]],y=o("message-square",me);var Le=[["path",{d:"M12.586 12.586 19 19",key:"ea5xo7"}],["path",{d:"M3.688 3.037a.497.497 0 0 0-.651.651l6.5 15.999a.501.501 0 0 0 .947-.062l1.569-6.083a2 2 0 0 1 1.448-1.479l6.124-1.579a.5.5 0 0 0 .063-.947z",key:"277e5u"}]],R=o("mouse-pointer",Le);var Ie=[["rect",{width:"5",height:"5",x:"3",y:"3",rx:"1",key:"1tu5fj"}],["rect",{width:"5",height:"5",x:"16",y:"3",rx:"1",key:"1v8r4q"}],["rect",{width:"5",height:"5",x:"3",y:"16",rx:"1",key:"1x03jg"}],["path",{d:"M21 16h-3a2 2 0 0 0-2 2v3",key:"177gqh"}],["path",{d:"M21 21v.01",key:"ents32"}],["path",{d:"M12 7v3a2 2 0 0 1-2 2H7",key:"8crl2c"}],["path",{d:"M3 12h.01",key:"nlz23k"}],["path",{d:"M12 3h.01",key:"n36tog"}],["path",{d:"M12 16v.01",key:"133mhm"}],["path",{d:"M16 12h1",key:"1slzba"}],["path",{d:"M21 12v.01",key:"1lwtk9"}],["path",{d:"M12 21v-1",key:"1880an"}]],b=o("qr-code",Ie);var xe=[["path",{d:"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8",key:"v9h5vc"}],["path",{d:"M21 3v5h-5",key:"1q7to0"}],["path",{d:"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16",key:"3uifl3"}],["path",{d:"M8 16H3v5",key:"1cv678"}]],T=o("refresh-cw",xe);var Ce=[["rect",{width:"14",height:"20",x:"5",y:"2",rx:"2",ry:"2",key:"1yt0o3"}],["path",{d:"M12 18h.01",key:"mhygvu"}]],B=o("smartphone",Ce);var he=[["path",{d:"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2",key:"1yyitq"}],["path",{d:"M16 3.128a4 4 0 0 1 0 7.744",key:"16gr8j"}],["path",{d:"M22 21v-2a4 4 0 0 0-3-3.87",key:"kshegd"}],["circle",{cx:"9",cy:"7",r:"4",key:"nufk8"}]],q=o("users",he);var ge=[["path",{d:"M12 20h.01",key:"zekei9"}],["path",{d:"M8.5 16.429a5 5 0 0 1 7 0",key:"1bycff"}],["path",{d:"M5 12.859a10 10 0 0 1 5.17-2.69",key:"1dl1wf"}],["path",{d:"M19 12.859a10 10 0 0 0-2.007-1.523",key:"4k23kn"}],["path",{d:"M2 8.82a15 15 0 0 1 4.177-2.643",key:"1grhjp"}],["path",{d:"M22 8.82a15 15 0 0 0-11.288-3.764",key:"z3jwby"}],["path",{d:"m2 2 20 20",key:"1ooewy"}]],v=o("wifi-off",ge);var Se=[["path",{d:"M12 20h.01",key:"zekei9"}],["path",{d:"M2 8.82a15 15 0 0 1 20 0",key:"dnpr2z"}],["path",{d:"M5 12.859a10 10 0 0 1 14 0",key:"1x1e6c"}],["path",{d:"M8.5 16.429a5 5 0 0 1 7 0",key:"1bycff"}]],U=o("wifi",Se);var ke=[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]],O=o("x",ke);import{useCallback as ae,useEffect as Be,useRef as te,useState as H}from"react";var ee="zhin_api_token",we="zhin_api_base";function Pe(){let a=localStorage.getItem(we)?.trim();return a?a.replace(/\/$/,""):typeof window<"u"?window.location.origin:""}function Ae(){return localStorage.getItem(ee)}async function M(a,u){let f=Ae(),s=new Headers(u?.headers);f&&s.set("Authorization",`Bearer ${f}`);let L=Pe(),i=typeof a=="string"&&a.startsWith("/")?`${L}${a}`:a,n=await fetch(i,{...u,headers:s});return n.status===401&&(localStorage.removeItem(ee),window.dispatchEvent(new CustomEvent("zhin:auth-required"))),n}import{jsx as t,jsxs as p}from"react/jsx-runtime";var Me=2e3,De=15e3,Fe={qrcode:{icon:t(b,{className:"w-4 h-4"}),label:"\u626B\u7801\u767B\u5F55"},sms:{icon:t(y,{className:"w-4 h-4"}),label:"\u77ED\u4FE1\u9A8C\u8BC1\u7801"},device:{icon:t(B,{className:"w-4 h-4"}),label:"\u8BBE\u5907\u9A8C\u8BC1"},auth:{icon:t(B,{className:"w-4 h-4"}),label:"\u8EAB\u4EFD\u9A8C\u8BC1"},slider:{icon:t(R,{className:"w-4 h-4"}),label:"\u6ED1\u5757\u9A8C\u8BC1"}};function K(){let[a,u]=H([]),[f,s]=H(!0),[L,i]=H(null),[n,h]=H({}),[x,l]=H({}),m=te(0),G=te(),g=ae(async()=>{try{let e=await M("/api/login-assist/pending");if(!e.ok)throw new Error("\u83B7\u53D6\u5F85\u529E\u5931\u8D25");let S=await e.json(),I=(Array.isArray(S)?S:[]).filter(E=>E.adapter==="icqq");u(I),i(null),m.current=I.length>0?0:m.current+1}catch(e){i(e.message),m.current++}finally{s(!1)}},[]),D=ae(()=>{let e=Math.min(Me*Math.pow(1.5,m.current),De);G.current=setTimeout(async()=>{await g(),D()},e)},[g]);Be(()=>(g().then(D),()=>clearTimeout(G.current)),[g,D]);let P=async(e,S)=>{h(d=>({...d,[e]:!0}));try{if(!(await M("/api/login-assist/submit",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({id:e,value:S})})).ok)throw new Error("\u63D0\u4EA4\u5931\u8D25");l(I=>{let E={...I};return delete E[e],E}),m.current=0,await g()}catch(d){i(d.message)}finally{h(d=>({...d,[e]:!1}))}},W=async e=>{try{(await M("/api/login-assist/cancel",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({id:e})})).ok&&await g()}catch{}};return f&&a.length===0?t("div",{className:"flex justify-center py-12",children:t(C,{className:"w-6 h-6 animate-spin text-blue-500"})}):p("div",{className:"space-y-4",children:[t("p",{className:"text-sm text-muted-foreground",children:"\u626B\u7801\u3001\u77ED\u4FE1\u6216\u6ED1\u5757\u7B49\u9A8C\u8BC1\u4F1A\u51FA\u73B0\u5728\u4E0B\u65B9\uFF1B\u5237\u65B0\u9875\u9762\u540E\u4ECD\u53EF\u7EE7\u7EED\u5904\u7406\uFF08\u4EC5 ICQQ \u5F85\u529E\uFF09\u3002"}),L&&p("div",{className:"flex items-center gap-2 p-3 rounded border border-red-200 bg-red-50 text-red-600 text-sm dark:bg-red-900/20 dark:text-red-400 dark:border-red-800",children:[t(k,{className:"w-4 h-4 shrink-0"}),t("span",{children:L}),t("button",{onClick:()=>i(null),className:"ml-auto",children:t(O,{className:"w-3.5 h-3.5"})})]}),a.length===0?p("div",{className:"border rounded-lg bg-card p-12 text-center",children:[t(w,{className:"w-16 h-16 mx-auto mb-4 opacity-25"}),t("h3",{className:"text-lg font-semibold mb-1",children:"\u6682\u65E0\u5F85\u529E"}),t("p",{className:"text-sm text-muted-foreground",children:"\u673A\u5668\u4EBA\u9700\u8981\u9A8C\u8BC1\u65F6\uFF0C\u5F85\u529E\u5C06\u663E\u793A\u5728\u6B64\u5904"})]}):t("div",{className:"space-y-4",children:a.map(e=>{let S=Fe[e.type]??{icon:t(w,{className:"w-4 h-4"}),label:e.type};return p("div",{className:"border rounded-lg bg-card p-4 shadow-sm",children:[p("div",{className:"flex items-start justify-between flex-wrap gap-2 mb-2",children:[p("div",{className:"flex items-center gap-2 font-semibold",children:[S.icon," ",S.label]}),p("div",{className:"flex gap-1 text-xs",children:[t("span",{className:"px-2 py-0.5 rounded border",children:e.adapter}),t("span",{className:"px-2 py-0.5 rounded bg-muted",children:e.endpointId})]})]}),e.payload?.message&&t("p",{className:"text-sm text-muted-foreground mb-3",children:e.payload.message}),e.type==="qrcode"&&e.payload?.image&&t("div",{className:"flex justify-center p-4 bg-muted/30 rounded-lg mb-3",children:t("img",{src:String(e.payload.image),alt:"\u767B\u5F55\u4E8C\u7EF4\u7801",className:"max-w-[200px] w-full h-auto"})}),(e.type==="slider"||e.type==="auth")&&e.payload?.url&&p("p",{className:"text-sm break-all mb-3",children:[t("span",{className:"text-muted-foreground",children:"\u9A8C\u8BC1\u94FE\u63A5\uFF1A"})," ",t("a",{href:String(e.payload.url),target:"_blank",rel:"noopener noreferrer",className:"text-primary hover:underline",children:String(e.payload.url)})]}),e.type==="auth"&&e.payload?.device&&typeof e.payload.device=="object"&&p("div",{className:"text-xs text-muted-foreground mb-3 space-y-1 rounded border p-3 bg-muted/20",children:[t("div",{className:"font-medium text-foreground",children:"\u8BBE\u5907\u4FE1\u606F\uFF08\u767B\u5F55\u7EED\u4F20\u7528\uFF09"}),Object.entries(e.payload.device).filter(([,d])=>d!=null&&String(d)!=="").map(([d,I])=>p("div",{children:[p("span",{className:"opacity-70",children:[d,": "]}),t("span",{className:"font-mono break-all",children:String(I)})]},d))]}),e.type==="auth"&&p("div",{className:"flex gap-2 mt-3",children:[t("button",{className:"h-9 px-4 rounded-md bg-primary text-primary-foreground text-sm disabled:opacity-50",disabled:!!n[e.id],onClick:()=>{P(e.id,{done:!0})},children:n[e.id]?"\u63D0\u4EA4\u4E2D\u2026":"\u6211\u5DF2\u5B8C\u6210\u9A8C\u8BC1"}),t("button",{className:"h-9 px-4 rounded-md border text-sm hover:bg-accent transition-colors",onClick:()=>{W(e.id)},children:"\u53D6\u6D88"})]}),(e.type==="sms"||e.type==="device"||e.type==="slider")&&p("div",{className:"flex flex-wrap gap-2 items-center",children:[t("input",{className:"h-9 px-3 rounded-md border border-input bg-background text-sm max-w-[18rem] flex-1",placeholder:e.type==="slider"?"\u8F93\u5165 ticket":"\u8F93\u5165\u9A8C\u8BC1\u7801",value:x[e.id]??"",onChange:d=>l(I=>({...I,[e.id]:d.target.value})),onKeyDown:d=>{if(d.key==="Enter"){let I=x[e.id]?.trim();I&&P(e.id,e.type==="slider"?{ticket:I}:I)}}}),t("button",{className:"h-9 px-4 rounded-md bg-primary text-primary-foreground text-sm disabled:opacity-50",disabled:n[e.id]||!x[e.id]?.trim(),onClick:()=>{let d=x[e.id]?.trim();d&&P(e.id,e.type==="slider"?{ticket:d}:d)},children:n[e.id]?"\u63D0\u4EA4\u4E2D\u2026":"\u63D0\u4EA4"})]}),e.type==="qrcode"&&p("div",{className:"flex gap-2 mt-3",children:[t("button",{className:"h-9 px-4 rounded-md bg-primary text-primary-foreground text-sm disabled:opacity-50",disabled:!!n[e.id],onClick:()=>{P(e.id,{done:!0})},children:n[e.id]?"\u63D0\u4EA4\u4E2D\u2026":"\u6211\u5DF2\u626B\u7801"}),t("button",{className:"h-9 px-4 rounded-md border text-sm hover:bg-accent transition-colors",onClick:()=>{W(e.id)},children:"\u53D6\u6D88"})]})]},e.id)})})]})}import{Fragment as be,jsx as r,jsxs as c}from"react/jsx-runtime";function Z(){let[a,u]=z("overview"),[f,s]=z([]),[L,i]=z(!0),[n,h]=z(null),x=ye(async()=>{i(!0),h(null);try{let l=await M("/api/icqq/endpoints"),m=await l.json();if(!l.ok||!m.success)throw new Error(m.message||"\u52A0\u8F7D\u5931\u8D25");s(Array.isArray(m.data)?m.data:[])}catch(l){h(l.message),s([])}finally{i(!1)}},[]);return Re(()=>{a==="overview"&&x()},[a,x]),c("div",{className:"p-6 max-w-5xl mx-auto space-y-5",children:[c("div",{className:"flex items-center justify-between",children:[c("div",{children:[c("h1",{className:"text-2xl font-bold flex items-center gap-2",children:[r(A,{className:"w-6 h-6"})," ICQQ \u7BA1\u7406"]}),r("p",{className:"text-sm text-muted-foreground mt-1",children:"\u673A\u5668\u4EBA\u6982\u89C8\u4E0E\u767B\u5F55\u8F85\u52A9\uFF08\u626B\u7801 / \u9A8C\u8BC1\u7801 / \u6ED1\u5757\uFF09"})]}),a==="overview"&&c("button",{onClick:x,disabled:L,className:"flex items-center gap-1 px-3 py-1.5 rounded bg-blue-500 text-white hover:bg-blue-600 disabled:opacity-50 text-sm",children:[r(T,{className:`w-4 h-4 ${L?"animate-spin":""}`})," \u5237\u65B0"]})]}),c("div",{className:"flex gap-1 border-b",children:[r("button",{onClick:()=>u("overview"),className:`px-4 py-2 text-sm font-medium border-b-2 transition-colors ${a==="overview"?"border-blue-500 text-blue-600":"border-transparent text-gray-500 hover:text-gray-700"}`,children:c("span",{className:"flex items-center gap-1.5",children:[r(A,{className:"w-4 h-4"})," \u6982\u89C8"]})}),r("button",{onClick:()=>u("login"),className:`px-4 py-2 text-sm font-medium border-b-2 transition-colors ${a==="login"?"border-blue-500 text-blue-600":"border-transparent text-gray-500 hover:text-gray-700"}`,children:c("span",{className:"flex items-center gap-1.5",children:[r(w,{className:"w-4 h-4"})," \u767B\u5F55\u8F85\u52A9"]})})]}),a==="overview"&&c(be,{children:[n&&r("div",{className:"p-3 bg-red-50 text-red-600 rounded border border-red-200 text-sm dark:bg-red-900/20 dark:text-red-400 dark:border-red-800",children:n}),L?r("div",{className:"flex justify-center py-12",children:r(C,{className:"w-6 h-6 animate-spin text-blue-500"})}):f.length===0?r("div",{className:"text-center text-muted-foreground py-12",children:"\u6682\u65E0 ICQQ Endpoint \u5B9E\u4F8B"}):r("div",{className:"grid gap-4 md:grid-cols-2",children:f.map(l=>c("div",{className:"border rounded-lg p-4 bg-card shadow-sm",children:[c("div",{className:"flex items-center justify-between mb-3",children:[r("span",{className:"font-medium text-lg",children:l.name}),l.connected?c("span",{className:"flex items-center gap-1 text-green-600 text-sm",children:[r(U,{className:"w-4 h-4"})," \u5728\u7EBF"]}):c("span",{className:"flex items-center gap-1 text-gray-400 text-sm",children:[r(v,{className:"w-4 h-4"})," \u79BB\u7EBF"]})]}),c("div",{className:"space-y-2 text-sm text-muted-foreground",children:[c("div",{className:"flex items-center gap-1.5",children:[r(q,{className:"w-3.5 h-3.5"}),"\u7FA4 ",l.groupCount," \xB7 \u597D\u53CB ",l.friendCount]}),c("div",{className:"flex items-center gap-1.5",children:[r(F,{className:"w-3.5 h-3.5"}),"\u767B\u5F55\u65B9\u5F0F ",l.loginMode," \xB7 ",l.status]})]})]},l.name))})]}),a==="login"&&r(K,{})]})}function dt(a){a.addRoute({path:"/console/icqq",name:"ICQQ\u7BA1\u7406",element:a.React.createElement(Z,{hostReact:a.React})}),a.addTool({id:"icqq",name:"ICQQ",path:"/console/icqq"})}export{dt as register};
|
|
2
|
-
/*! Bundled license information:
|
|
3
|
-
|
|
4
|
-
lucide-react/dist/esm/shared/src/utils/mergeClasses.mjs:
|
|
5
|
-
lucide-react/dist/esm/shared/src/utils/toKebabCase.mjs:
|
|
6
|
-
lucide-react/dist/esm/shared/src/utils/toCamelCase.mjs:
|
|
7
|
-
lucide-react/dist/esm/shared/src/utils/toPascalCase.mjs:
|
|
8
|
-
lucide-react/dist/esm/defaultAttributes.mjs:
|
|
9
|
-
lucide-react/dist/esm/shared/src/utils/hasA11yProp.mjs:
|
|
10
|
-
lucide-react/dist/esm/context.mjs:
|
|
11
|
-
lucide-react/dist/esm/Icon.mjs:
|
|
12
|
-
lucide-react/dist/esm/createLucideIcon.mjs:
|
|
13
|
-
lucide-react/dist/esm/icons/activity.mjs:
|
|
14
|
-
lucide-react/dist/esm/icons/bot.mjs:
|
|
15
|
-
lucide-react/dist/esm/icons/circle-alert.mjs:
|
|
16
|
-
lucide-react/dist/esm/icons/loader-circle.mjs:
|
|
17
|
-
lucide-react/dist/esm/icons/log-in.mjs:
|
|
18
|
-
lucide-react/dist/esm/icons/message-square.mjs:
|
|
19
|
-
lucide-react/dist/esm/icons/mouse-pointer.mjs:
|
|
20
|
-
lucide-react/dist/esm/icons/qr-code.mjs:
|
|
21
|
-
lucide-react/dist/esm/icons/refresh-cw.mjs:
|
|
22
|
-
lucide-react/dist/esm/icons/smartphone.mjs:
|
|
23
|
-
lucide-react/dist/esm/icons/users.mjs:
|
|
24
|
-
lucide-react/dist/esm/icons/wifi-off.mjs:
|
|
25
|
-
lucide-react/dist/esm/icons/wifi.mjs:
|
|
26
|
-
lucide-react/dist/esm/icons/x.mjs:
|
|
27
|
-
lucide-react/dist/esm/lucide-react.mjs:
|
|
28
|
-
(**
|
|
29
|
-
* @license lucide-react v1.23.0 - ISC
|
|
30
|
-
*
|
|
31
|
-
* This source code is licensed under the ISC license.
|
|
32
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
33
|
-
*)
|
|
34
|
-
*/
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { defineTool } from '@zhin.js/agent/tools';
|
|
2
|
-
import { z } from 'zod';
|
|
3
|
-
import { getIcqqAgentDeps } from '../../src/icqq-agent-deps.js';
|
|
4
|
-
export default defineTool({
|
|
5
|
-
description: '发送 QQ 群公告(需要管理员权限)',
|
|
6
|
-
inputSchema: z.object({
|
|
7
|
-
endpoint_id: z.string().describe('Endpoint QQ号'),
|
|
8
|
-
group_id: z.number().describe('目标群号'),
|
|
9
|
-
content: z.string().describe('公告内容'),
|
|
10
|
-
}),
|
|
11
|
-
platforms: ['icqq'],
|
|
12
|
-
tags: ['icqq'],
|
|
13
|
-
permissions: ['platform(icqq,scene_admin)'],
|
|
14
|
-
async execute({ endpoint_id, group_id, content }) {
|
|
15
|
-
const { Actions } = await import('../../src/protocol.js');
|
|
16
|
-
const endpoint = getIcqqAgentDeps().getEndpoint(endpoint_id);
|
|
17
|
-
const resp = await endpoint.ipc.request(Actions.GROUP_ANNOUNCE, { group_id, content });
|
|
18
|
-
return { success: resp.ok, message: resp.ok ? '群公告已发送' : (resp.error ?? '发送失败') };
|
|
19
|
-
},
|
|
20
|
-
});
|
|
21
|
-
//# sourceMappingURL=announce.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"announce.js","sourceRoot":"","sources":["../../../agent/tools/announce.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,eAAe,UAAU,CAA6D;IACpF,WAAW,EAAE,oBAAoB;IACjC,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;QACpB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC;QAChD,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC;QACrC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC;KACrC,CAAC;IACF,SAAS,EAAE,CAAC,MAAM,CAAC;IACnB,IAAI,EAAE,CAAC,MAAM,CAAC;IACd,WAAW,EAAE,CAAC,4BAA4B,CAAC;IAC3C,KAAK,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,QAAQ,EAAE,OAAO,EAAiE;QAC7G,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,CAAC,uBAAuB,CAAC,CAAC;QAC1D,MAAM,QAAQ,GAAG,gBAAgB,EAAE,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;QAC7D,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;QACvF,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,EAAE,CAAC;IACpF,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { defineTool } from '@zhin.js/agent/tools';
|
|
2
|
-
import { z } from 'zod';
|
|
3
|
-
import { getIcqqAgentDeps } from '../../src/icqq-agent-deps.js';
|
|
4
|
-
export default defineTool({
|
|
5
|
-
description: '设置或移除 QQ 群精华消息',
|
|
6
|
-
inputSchema: z.object({
|
|
7
|
-
endpoint_id: z.string().describe('Endpoint QQ号'),
|
|
8
|
-
message_id: z.string().describe('消息 ID'),
|
|
9
|
-
action: z.enum(['add', 'remove']).describe('add=设为精华, remove=移除精华'),
|
|
10
|
-
}),
|
|
11
|
-
platforms: ['icqq'],
|
|
12
|
-
tags: ['icqq'],
|
|
13
|
-
permissions: ['platform(icqq,scene_admin)'],
|
|
14
|
-
async execute({ endpoint_id, message_id, action }) {
|
|
15
|
-
const { Actions } = await import('../../src/protocol.js');
|
|
16
|
-
const endpoint = getIcqqAgentDeps().getEndpoint(endpoint_id);
|
|
17
|
-
const act = action === 'add' ? Actions.GROUP_ESSENCE_ADD : Actions.GROUP_ESSENCE_REMOVE;
|
|
18
|
-
const resp = await endpoint.ipc.request(act, { message_id });
|
|
19
|
-
return { success: resp.ok, message: resp.ok ? (action === 'add' ? '已设为精华' : '已移除精华') : (resp.error ?? '操作失败') };
|
|
20
|
-
},
|
|
21
|
-
});
|
|
22
|
-
//# sourceMappingURL=essence.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"essence.js","sourceRoot":"","sources":["../../../agent/tools/essence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,eAAe,UAAU,CAAwE;IAC/F,WAAW,EAAE,gBAAgB;IAC7B,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;QACpB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC;QAChD,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC;QACxC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,uBAAuB,CAAC;KACpE,CAAC;IACF,SAAS,EAAE,CAAC,MAAM,CAAC;IACnB,IAAI,EAAE,CAAC,MAAM,CAAC;IACd,WAAW,EAAE,CAAC,4BAA4B,CAAC;IAC3C,KAAK,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,EAAyE;QACtH,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,CAAC,uBAAuB,CAAC,CAAC;QAC1D,MAAM,QAAQ,GAAG,gBAAgB,EAAE,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;QAC7D,MAAM,GAAG,GAAG,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,OAAO,CAAC,oBAAoB,CAAC;QACxF,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC;QAC7D,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,EAAE,CAAC;IAClH,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { defineTool } from '@zhin.js/agent/tools';
|
|
2
|
-
import { z } from 'zod';
|
|
3
|
-
import { getIcqqAgentDeps } from '../../src/icqq-agent-deps.js';
|
|
4
|
-
export default defineTool({
|
|
5
|
-
description: '获取 QQ 好友列表',
|
|
6
|
-
inputSchema: z.object({
|
|
7
|
-
endpoint_id: z.string().describe('Endpoint 名称'),
|
|
8
|
-
}),
|
|
9
|
-
platforms: ['icqq'],
|
|
10
|
-
tags: ['icqq'],
|
|
11
|
-
async execute({ endpoint_id }) {
|
|
12
|
-
const endpoint = getIcqqAgentDeps().getEndpoint(endpoint_id);
|
|
13
|
-
const friends = Array.from(endpoint.friends.values()).map((f) => ({
|
|
14
|
-
user_id: f.user_id, nickname: f.nickname, remark: f.remark,
|
|
15
|
-
}));
|
|
16
|
-
return { friends: friends.slice(0, 50), count: endpoint.friends.size };
|
|
17
|
-
},
|
|
18
|
-
});
|
|
19
|
-
//# sourceMappingURL=friend_list.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"friend_list.js","sourceRoot":"","sources":["../../../agent/tools/friend_list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,eAAe,UAAU,CAA0B;IACjD,WAAW,EAAE,YAAY;IACzB,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;QACpB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC;KAChD,CAAC;IACF,SAAS,EAAE,CAAC,MAAM,CAAC;IACnB,IAAI,EAAE,CAAC,MAAM,CAAC;IACd,KAAK,CAAC,OAAO,CAAC,EAAE,WAAW,EAA8B;QACvD,MAAM,QAAQ,GAAG,gBAAgB,EAAE,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;QAC7D,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAChE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM;SAC3D,CAAC,CAAC,CAAC;QACJ,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;IACzE,CAAC;CACF,CAAC,CAAC"}
|