@yuku123/z-team-component 0.2.28 → 0.2.30

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.
Files changed (45) hide show
  1. package/dist/{ChangeLogView-CG-o5YP1.js → ChangeLogView-FLd1wS8H.js} +1 -1
  2. package/dist/{InvitationManagementPage-DpA3Xlq1.js → InvitationManagementPage-CttWZdu8.js} +87 -82
  3. package/dist/{OnboardingPage-DFRAwruv.js → OnboardingPage-CAI-P20Q.js} +2 -2
  4. package/dist/ProjectApp-ZR_QUlPs.js +3839 -0
  5. package/dist/{SystemShell-BLXTOqFb.js → SystemShell-BKNdXqXt.js} +1 -1
  6. package/dist/{admin-logs-C2V1ElH9.js → admin-logs-Dv86pFvY.js} +2 -2
  7. package/dist/{api--Fg0hL9Y.js → api-19TXED_O.js} +52 -39
  8. package/dist/api-BNwdLozd.js +20 -0
  9. package/dist/{createWorkspaceWsHandler-CqGqcTh_.js → createWorkspaceWsHandler-CBk4DqP4.js} +6 -5
  10. package/dist/{index-hPzswwk2.js → index-B5_xKK08.js} +1139 -1152
  11. package/dist/{index-D5u3BjCZ.js → index-BIJnjJd5.js} +2 -2
  12. package/dist/{index-BylksTyk.js → index-BKwpQ-HW.js} +136 -134
  13. package/dist/{index-bbwTcNjB.js → index-BTLD5gUt.js} +3 -3
  14. package/dist/{index-C9BOtjtQ.js → index-BTaLAs80.js} +9 -9
  15. package/dist/{index-CiMxCTOS.js → index-B_EBV24V.js} +1 -1
  16. package/dist/{index-BafC42Cl.js → index-Bd57t_yF.js} +1 -1
  17. package/dist/{index-C2aPiQSz.js → index-BjqYiZpC.js} +3 -3
  18. package/dist/{index-BaCiSbPR.js → index-BoGVJ0hC.js} +1 -1
  19. package/dist/{index-C01UUprh.js → index-BpuJ9Njb.js} +7016 -6946
  20. package/dist/{index-CcFJEYgr.js → index-C815hPWS.js} +55 -52
  21. package/dist/{index-DIxwe_pk.js → index-C8GK1bOQ.js} +358 -347
  22. package/dist/{index-DvIHX7lZ.js → index-CcpWacSZ.js} +243 -236
  23. package/dist/{index-Da7ls5q6.js → index-DOPkM2W8.js} +6 -6
  24. package/dist/index-DQNZE7Go.js +169 -0
  25. package/dist/{index-BYEx4vlI.js → index-DR_FCf71.js} +1134 -1132
  26. package/dist/{index-CTD7k9dP.js → index-DYgD6BuB.js} +4 -4
  27. package/dist/{index-dSnK7qcL.js → index-DdN9Apqq.js} +5 -5
  28. package/dist/{index-CPF3LS0x.js → index-DuGWlMWm.js} +3 -3
  29. package/dist/index-JMzBzwiO.js +1746 -0
  30. package/dist/{index-Dao4uqQd.js → index-x4-W5ClM.js} +4 -4
  31. package/dist/index.js +1 -1
  32. package/dist/{instance-1QEDBRqA.js → instance-D951fRuD.js} +1 -1
  33. package/dist/pages.js +5 -4
  34. package/dist/{schedule-C89oiqIR.js → schedule-DD50-7cs.js} +1 -1
  35. package/dist/{send-default-agent-team-message-CxkWi3XC.js → send-default-agent-team-message-Bbs2rMNf.js} +1 -1
  36. package/dist/{sso-user-BE1Ell5F.js → sso-user-BEY5ICaR.js} +1 -1
  37. package/dist/{training-o-vSBkqP.js → training-B-9tNFQw.js} +1 -1
  38. package/dist/{useAppStore-wgWaxcyc.js → useAppStore-BQN-26ns.js} +1 -1
  39. package/dist/{webide-BxD6cYe-.js → webide-P867RFZi.js} +4 -4
  40. package/dist/z-team-component.css +1 -1
  41. package/package.json +3 -3
  42. package/dist/ProjectApp-BquB_X7K.js +0 -4591
  43. package/dist/api-CX7MUpws.js +0 -19
  44. package/dist/index-CcTdM5kT.js +0 -178
  45. package/dist/index-pfzY68PH.js +0 -1408
@@ -0,0 +1,3839 @@
1
+ import { jsx as e, jsxs as r, Fragment as Le } from "react/jsx-runtime";
2
+ import { lazy as xt, Suspense as wt, useState as m, useEffect as U, useRef as st } from "react";
3
+ import { useLocation as It, useNavigate as xe, useParams as ot, Routes as ct, Route as ne, Navigate as dt, useSearchParams as St } from "react-router-dom";
4
+ import { Row as Y, Col as z, Typography as le, Alert as V, Card as M, Space as P, Button as _, Table as Q, Drawer as we, Descriptions as R, Tag as w, Tooltip as pe, message as b, Modal as me, Statistic as K, Input as B, Select as X, Tabs as Ie, Form as E, Upload as kt, Popconfirm as je, Spin as Ae, Radio as re, InputNumber as Oe, Empty as Ct } from "antd";
5
+ import { SettingOutlined as Tt, ProjectOutlined as Ee, UserOutlined as ut, AuditOutlined as $e, RobotOutlined as Ne, ApiOutlined as Fe, AppstoreOutlined as vt, ThunderboltOutlined as be, BarChartOutlined as _t, ScheduleOutlined as At, FileTextOutlined as Ke, ReloadOutlined as ee, ExperimentOutlined as Et, PlayCircleOutlined as Pe, CopyOutlined as ht, GlobalOutlined as pt, NodeIndexOutlined as Pt, UndoOutlined as Rt, FileSearchOutlined as Ot, VideoCameraOutlined as Je, SearchOutlined as mt, EyeOutlined as zt, CodeOutlined as fe, InfoCircleOutlined as Mt, FunctionOutlined as ke, ImportOutlined as De, CloudUploadOutlined as Xe, FileAddOutlined as Lt, PlusOutlined as yt, EditOutlined as $t, PauseCircleOutlined as Nt, CheckCircleOutlined as Ue, DeleteOutlined as Dt, ExclamationCircleOutlined as Bt, SaveOutlined as gt, ArrowLeftOutlined as ft, SendOutlined as qt } from "@ant-design/icons";
6
+ import "@yuku123/z-frontend-common";
7
+ import { PageHeader as ye, GradientStatCard as Ce, SectionHeader as jt, FeatureCard as Ft, DarkBanner as Kt, ListTable as ie, TableToolbar as Ut, ErrorState as Ht } from "@yuku123/z-frontend-common/ui";
8
+ import He from "axios";
9
+ const Z = (t) => {
10
+ const s = xt(t);
11
+ return (n) => /* @__PURE__ */ e(wt, { fallback: null, children: /* @__PURE__ */ e(s, { ...n }) });
12
+ }, oe = Z(() => import("./index-DR_FCf71.js").then((t) => t.H)), Gt = Z(() => import("./index-DOPkM2W8.js")), Vt = Z(() => import("./index-BTLD5gUt.js")), Jt = Z(() => import("./index-DYgD6BuB.js")), Xt = Z(() => import("./index-x4-W5ClM.js")), Wt = Z(() => import("./index-BIJnjJd5.js"));
13
+ Z(() => import("./index-BpuJ9Njb.js"));
14
+ const Zt = Z(() => import("./index-C815hPWS.js")), Yt = Z(() => import("./index-UsGqMo11.js")), Qt = Z(() => import("./index-BkX0I2aB.js")), er = Z(() => import("./index-B_EBV24V.js")), tr = Z(() => import("./index-Bd57t_yF.js")), rr = Z(() => import("./index-BjqYiZpC.js"));
15
+ function Wr({ forcedMode: t }) {
16
+ const { pathname: s } = It(), n = s.replace(/\/+$/, "") || "/";
17
+ return t === "system" ? /* @__PURE__ */ e(oe, { forcedChatMode: "system" }) : t === "rpa" ? /* @__PURE__ */ e(oe, { forcedChatMode: "rpa" }) : t === "dev" ? /* @__PURE__ */ e(oe, { forcedChatMode: "dev" }) : n === "/workspace" ? /* @__PURE__ */ e(oe, {}) : n === "/workspace/phone" ? /* @__PURE__ */ e(Gt, {}) : n === "/workspace/from-ticket" ? /* @__PURE__ */ e(Vt, {}) : n === "/workspace/from-scenario" ? /* @__PURE__ */ e(Jt, {}) : n === "/workspace/build-by-form" ? /* @__PURE__ */ e(Xt, {}) : n === "/scenario" ? /* @__PURE__ */ e(Wt, {}) : n === "/admin" ? /* @__PURE__ */ e(oe, {}) : n === "/welcome" ? /* @__PURE__ */ e(Yt, {}) : n === "/portal" ? /* @__PURE__ */ e(Qt, {}) : n === "/chatdemo" ? /* @__PURE__ */ e(Zt, {}) : n === "/embed/chat" || n.startsWith("/embed/chat/") ? /* @__PURE__ */ e(rr, {}) : n === "/change-log" ? /* @__PURE__ */ e(er, {}) : n === "/docs" ? /* @__PURE__ */ e(tr, {}) : /* @__PURE__ */ e(oe, {});
18
+ }
19
+ function nr(t) {
20
+ if (!t || typeof t != "string") return null;
21
+ const s = t.split(".");
22
+ if (s.length !== 3) return null;
23
+ try {
24
+ let n = s[1].replace(/-/g, "+").replace(/_/g, "/");
25
+ const k = n.length % 4;
26
+ k && (n += "=".repeat(4 - k));
27
+ const a = atob(n), y = Uint8Array.from(a, (x) => x.charCodeAt(0)), c = new TextDecoder().decode(y), f = JSON.parse(c);
28
+ return f && typeof f == "object" && !Array.isArray(f) ? f : null;
29
+ } catch {
30
+ return null;
31
+ }
32
+ }
33
+ function lr(t, s = 30) {
34
+ const n = nr(t);
35
+ return !n || typeof n.exp != "number" ? !0 : Date.now() / 1e3 > n.exp - s;
36
+ }
37
+ let We = !1;
38
+ const ar = [
39
+ "/ctc/authn/login",
40
+ "/ctc/authn/register",
41
+ "/ctc/authn/send-code",
42
+ "/ctc/authn/register-phone",
43
+ "/ctc/authn/reset-password",
44
+ "/ctc/authn/phone-login",
45
+ "/ctc/authn/verify",
46
+ "/ctc/ac/login",
47
+ "/auth/login",
48
+ "/auth/register",
49
+ "/auth/reset-password",
50
+ "/uc/login",
51
+ "/uc/register",
52
+ "/uc/phone-login",
53
+ "/sso/login",
54
+ "/sso/callback"
55
+ ];
56
+ function ir(t) {
57
+ return ar.some((s) => t.includes(s));
58
+ }
59
+ function Ze(t) {
60
+ if (We || typeof window > "u" || window.location.pathname.startsWith("/login")) return;
61
+ We = !0;
62
+ try {
63
+ localStorage.removeItem("token"), localStorage.removeItem("userInfo");
64
+ } catch {
65
+ }
66
+ console.warn(`[Auth] ${t}, 跳转到 /login`);
67
+ const s = window.location.pathname + window.location.search, n = encodeURIComponent(s);
68
+ window.location.href = `/login?redirect=${n}`;
69
+ }
70
+ function sr(t) {
71
+ if (t && typeof t == "object" && "code" in t && "data" in t) {
72
+ const s = t;
73
+ return (typeof s.success == "boolean" ? s.success : typeof s.code == "number" && s.code >= 200 && s.code < 300) ? s.data : Promise.reject(new Error(s.message || "请求失败"));
74
+ }
75
+ return t;
76
+ }
77
+ function or(t, s = {}) {
78
+ const { tokenKey: n = "token", userInfoKey: k = "userInfo" } = s;
79
+ t.interceptors.request.use((a) => {
80
+ const y = localStorage.getItem(n);
81
+ if (y && lr(y))
82
+ return Ze(`请求前检测到 token 已过期 (${a.url || ""})`), Promise.reject(new He.CanceledError("token expired"));
83
+ try {
84
+ const c = localStorage.getItem(k);
85
+ if (c) {
86
+ const f = JSON.parse(c), x = f.tenantCode || "default", T = f.domainCode || "default", A = f.id ?? f.userId, p = (a.method || "get").toLowerCase();
87
+ if (typeof a.url == "string" && a.url.includes("/ctc/ac/") && (a.params = { ...a.params || {} }, a.params.tenantCode || (a.params.tenantCode = x), a.params.domainCode || (a.params.domainCode = T)), A != null && (a.headers["X-User-Id"] = String(A)), p !== "get" && p !== "delete" && a.data && typeof a.data == "object") {
88
+ const l = a.data;
89
+ l.tenantCode == null && (l.tenantCode = x), l.domainCode == null && (l.domainCode = T);
90
+ }
91
+ }
92
+ } catch {
93
+ }
94
+ return a;
95
+ }), t.interceptors.response.use(
96
+ (a) => sr(a.data),
97
+ (a) => {
98
+ var f, x;
99
+ const y = (f = a.response) == null ? void 0 : f.status, c = ((x = a.config) == null ? void 0 : x.url) || "";
100
+ return y === 401 ? ir(c) ? console.warn(`[401] 公开接口返回 401 (不是 token 问题): ${c}`) : Ze(`接口 ${c} 返回 401`) : y === 403 ? console.warn("[403] 没有权限访问该资源:", c) : y === 404 ? console.warn("[404] 接口不存在:", c) : y === 500 && console.error("[500] 服务器内部错误:", c), Promise.reject(a);
101
+ }
102
+ );
103
+ }
104
+ function Ge(t = {}) {
105
+ const s = He.create({
106
+ baseURL: t.baseURL ?? "/api",
107
+ timeout: t.timeout ?? 1e4,
108
+ withCredentials: !0
109
+ // Cookie 模式:浏览器自动携带 Cookie
110
+ });
111
+ return or(s, {
112
+ tokenKey: t.tokenKey,
113
+ userInfoKey: t.userInfoKey
114
+ }), s;
115
+ }
116
+ const N = Ge(), Zr = Ge(), Te = Ge({ baseURL: "/api", timeout: 1e4 }), ve = (t) => t ? typeof t.total == "number" ? t.total : Array.isArray(t) ? t.length : Array.isArray(t.records) ? t.records.length : Array.isArray(t.data) ? t.data.length : 0 : 0, cr = [
117
+ {
118
+ key: "ai",
119
+ color: "violet",
120
+ title: "智能中心",
121
+ subtitle: "Agent · 模型 · MCP · 技能",
122
+ icon: /* @__PURE__ */ e(Ne, {}),
123
+ href: "/ai/agent/app",
124
+ items: [
125
+ {
126
+ title: "Agent 应用",
127
+ description: "创建和管理 AI Agent 应用, 支持多种 LLM 模型",
128
+ icon: /* @__PURE__ */ e(Ne, {}),
129
+ color: "violet",
130
+ tags: [{ label: "AI", color: "violet" }, { label: "推荐", color: "orange" }],
131
+ meta: "12 个应用"
132
+ },
133
+ {
134
+ title: "多 Agent 实例",
135
+ description: "多 Agent 协同执行, 支持 ZBOT / Hermes / Claude Code / OpenCode",
136
+ icon: /* @__PURE__ */ e(Fe, {}),
137
+ color: "blue",
138
+ tags: [{ label: "AI", color: "blue" }],
139
+ meta: "5 种引擎"
140
+ },
141
+ {
142
+ title: "模板市场",
143
+ description: "精选 AI 应用模板, 一键复制即可使用",
144
+ icon: /* @__PURE__ */ e(vt, {}),
145
+ color: "pink",
146
+ tags: [{ label: "模板", color: "pink" }],
147
+ meta: "24 个模板"
148
+ },
149
+ {
150
+ title: "技能市场",
151
+ description: "为 Agent 装配技能, 拓展能力边界",
152
+ icon: /* @__PURE__ */ e(be, {}),
153
+ color: "orange",
154
+ tags: [{ label: "扩展", color: "orange" }]
155
+ }
156
+ ]
157
+ },
158
+ // 运维中心已迁出独立平台 z-ops (2026-09-24, github.com/z-opc-foundation/z-ops)
159
+ {
160
+ key: "task",
161
+ color: "green",
162
+ title: "任务中心",
163
+ subtitle: "仪表盘 · 任务 · 项目",
164
+ icon: /* @__PURE__ */ e(Ee, {}),
165
+ href: "/task/dashboard",
166
+ items: [
167
+ {
168
+ title: "任务仪表盘",
169
+ description: "实时任务执行情况, 成功率与时长统计",
170
+ icon: /* @__PURE__ */ e(_t, {}),
171
+ color: "green",
172
+ tags: [{ label: "看板", color: "green" }]
173
+ },
174
+ {
175
+ title: "任务列表",
176
+ description: "所有定时/手动任务, 支持 Cron 表达式",
177
+ icon: /* @__PURE__ */ e(At, {}),
178
+ color: "blue",
179
+ tags: [{ label: "调度", color: "blue" }]
180
+ },
181
+ {
182
+ title: "项目管理",
183
+ description: "项目维度组织任务, 支持里程碑",
184
+ icon: /* @__PURE__ */ e(Ee, {}),
185
+ color: "violet",
186
+ tags: [{ label: "项目", color: "violet" }]
187
+ }
188
+ ]
189
+ },
190
+ {
191
+ key: "workflow",
192
+ color: "orange",
193
+ title: "流程中心",
194
+ subtitle: "审批 · 待办 · 我的",
195
+ icon: /* @__PURE__ */ e($e, {}),
196
+ href: "/workflow/dashboard",
197
+ items: [
198
+ {
199
+ title: "流程仪表盘",
200
+ description: "流程实例统计与效率分析",
201
+ icon: /* @__PURE__ */ e($e, {}),
202
+ color: "orange",
203
+ tags: [{ label: "审批", color: "orange" }]
204
+ },
205
+ {
206
+ title: "待办任务",
207
+ description: "我的待审批任务, 实时推送",
208
+ icon: /* @__PURE__ */ e(Ke, {}),
209
+ color: "red",
210
+ tags: [{ label: "待办", color: "red" }]
211
+ }
212
+ ]
213
+ }
214
+ ], Yr = () => {
215
+ const [t, s] = m({
216
+ configCount: null,
217
+ projectCount: null,
218
+ userCount: null,
219
+ roleCount: null
220
+ });
221
+ return U(() => {
222
+ let n = !0;
223
+ const k = [
224
+ Te.get("/config/list", { params: { pageSize: 1 } }).then((a) => ve(a)).then((a) => n && s((y) => ({ ...y, configCount: a }))).catch(() => n && s((a) => ({ ...a, configCount: 0 }))),
225
+ Te.get("/project/user/list").then((a) => ve(a)).then((a) => n && s((y) => ({ ...y, projectCount: a }))).catch(() => n && s((a) => ({ ...a, projectCount: 0 }))),
226
+ Te.get("/ctc/ac/accounts", { params: { pageSize: 1 } }).then((a) => ve(a)).then((a) => n && s((y) => ({ ...y, userCount: a }))).catch(() => n && s((a) => ({ ...a, userCount: 0 }))),
227
+ Te.get("/ctc/authz/roles/list").then((a) => ve(a)).then((a) => n && s((y) => ({ ...y, roleCount: a }))).catch(() => n && s((a) => ({ ...a, roleCount: 0 })))
228
+ ];
229
+ return () => {
230
+ n = !1, k.forEach((a) => {
231
+ var y;
232
+ return (y = a == null ? void 0 : a.catch) == null ? void 0 : y.call(a, () => {
233
+ });
234
+ });
235
+ };
236
+ }, []), /* @__PURE__ */ r("div", { children: [
237
+ /* @__PURE__ */ e(
238
+ ye,
239
+ {
240
+ title: "统一管理平台",
241
+ subtitle: "一站式企业级应用管理平台 · 整合配置 / 任务 / 工作流 / 用户 / 调度 等核心模块",
242
+ breadcrumb: [{ label: "首页" }]
243
+ }
244
+ ),
245
+ /* @__PURE__ */ r(Y, { gutter: [16, 16], children: [
246
+ /* @__PURE__ */ e(z, { xs: 24, sm: 12, md: 12, lg: 6, children: /* @__PURE__ */ e(
247
+ Ce,
248
+ {
249
+ icon: /* @__PURE__ */ e(Tt, {}),
250
+ label: "配置中心",
251
+ value: t.configCount,
252
+ suffix: "条",
253
+ color: "violet",
254
+ trend: 12.5,
255
+ href: "/config/list"
256
+ }
257
+ ) }),
258
+ /* @__PURE__ */ e(z, { xs: 24, sm: 12, md: 12, lg: 6, children: /* @__PURE__ */ e(
259
+ Ce,
260
+ {
261
+ icon: /* @__PURE__ */ e(Ee, {}),
262
+ label: "我的项目",
263
+ value: t.projectCount,
264
+ suffix: "个",
265
+ color: "blue",
266
+ trend: 8.3,
267
+ href: "/project/list"
268
+ }
269
+ ) }),
270
+ /* @__PURE__ */ e(z, { xs: 24, sm: 12, md: 12, lg: 6, children: /* @__PURE__ */ e(
271
+ Ce,
272
+ {
273
+ icon: /* @__PURE__ */ e(ut, {}),
274
+ label: "账号数",
275
+ value: t.userCount,
276
+ suffix: "人",
277
+ color: "green",
278
+ trend: -2.1,
279
+ href: "/ctc/4a/account"
280
+ }
281
+ ) }),
282
+ /* @__PURE__ */ e(z, { xs: 24, sm: 12, md: 12, lg: 6, children: /* @__PURE__ */ e(
283
+ Ce,
284
+ {
285
+ icon: /* @__PURE__ */ e($e, {}),
286
+ label: "角色数",
287
+ value: t.roleCount,
288
+ suffix: "个",
289
+ color: "orange",
290
+ trend: 4.7,
291
+ href: "/ctc/4a/role"
292
+ }
293
+ ) })
294
+ ] }),
295
+ cr.map((n) => /* @__PURE__ */ r("div", { style: { marginBottom: 32 }, children: [
296
+ /* @__PURE__ */ e(
297
+ jt,
298
+ {
299
+ color: n.color,
300
+ title: n.title,
301
+ subtitle: n.subtitle,
302
+ moreHref: n.href
303
+ }
304
+ ),
305
+ /* @__PURE__ */ e(Y, { gutter: [16, 16], children: n.items.map((k, a) => /* @__PURE__ */ e(
306
+ z,
307
+ {
308
+ xs: 24,
309
+ sm: 12,
310
+ md: 12,
311
+ lg: 6,
312
+ xl: 6,
313
+ xxl: 6,
314
+ children: /* @__PURE__ */ e(
315
+ Ft,
316
+ {
317
+ title: k.title,
318
+ description: k.description,
319
+ icon: k.icon,
320
+ color: k.color,
321
+ tags: k.tags,
322
+ meta: k.meta,
323
+ href: n.href
324
+ }
325
+ )
326
+ },
327
+ a
328
+ )) })
329
+ ] }, n.key)),
330
+ /* @__PURE__ */ e(
331
+ Kt,
332
+ {
333
+ tag: "FOR ENGINEERS",
334
+ title: "把 Z-One Company 接入你的工作流",
335
+ description: "通过 OpenAPI、Webhook 与 SDK,把统一管理平台的能力嵌入到你的业务系统中。支持配置查询、任务触发、流程审批等 200+ 接口。",
336
+ buttonText: "查看开发文档",
337
+ buttonHref: "/z-tool/webide"
338
+ }
339
+ )
340
+ ] });
341
+ };
342
+ let dr = "/api";
343
+ function bt() {
344
+ return He.create({ baseURL: dr, timeout: 15e3, withCredentials: !0 });
345
+ }
346
+ const Se = bt(), ur = bt();
347
+ ur.interceptors.request.use((t) => t);
348
+ Se.interceptors.request.use((t) => t);
349
+ const Re = "/mock-platform", G = (t, s) => Se.get(`${Re}${t}`, { params: s }).then((n) => n.data), F = (t, s, n) => Se.post(`${Re}${t}`, s, { params: n }).then((k) => k.data), _e = (t, s, n) => Se.put(`${Re}${t}`, s, { params: n }).then((k) => k.data), ce = (t, s) => Se.delete(`${Re}${t}`, { params: s }).then((n) => n.data), q = {
350
+ stats: () => G("/stats"),
351
+ environments: {
352
+ list: () => G("/environments/list"),
353
+ create: (t) => F("/environments", t),
354
+ update: (t, s) => _e("/environments", s, { envCode: t }),
355
+ delete: (t) => ce("/environments", { envCode: t })
356
+ },
357
+ endpoints: {
358
+ list: (t, s, n) => G("/endpoints/list", { envCode: t, scenarioCode: s, status: n }),
359
+ get: (t) => G("/endpoints/byCode", { mockCode: t }),
360
+ create: (t) => F("/endpoints", t),
361
+ update: (t, s) => _e("/endpoints", s, { mockCode: t }),
362
+ delete: (t) => ce("/endpoints", { mockCode: t }),
363
+ toggle: (t, s) => F("/endpoints/toggle", null, { mockCode: t, status: s })
364
+ },
365
+ scenarios: {
366
+ list: () => G("/scenarios/list"),
367
+ get: (t) => G("/scenarios/byCode", { scenarioCode: t }),
368
+ create: (t) => F("/scenarios", t),
369
+ update: (t, s) => _e("/scenarios", s, { scenarioCode: t }),
370
+ delete: (t) => ce("/scenarios", { scenarioCode: t }),
371
+ reset: (t) => F("/scenarios/reset", null, { scenarioCode: t }),
372
+ instances: (t) => G("/scenarios/instances", { scenarioCode: t })
373
+ },
374
+ cases: {
375
+ list: () => G("/cases/list"),
376
+ get: (t) => G("/cases/byCode", { caseCode: t }),
377
+ create: (t) => F("/cases", t),
378
+ update: (t, s) => _e("/cases", s, { caseCode: t }),
379
+ delete: (t) => ce("/cases", { caseCode: t }),
380
+ run: (t) => F("/cases/run", null, { caseCode: t }),
381
+ runBatch: (t) => F("/cases/run-batch", { caseCodes: t })
382
+ },
383
+ recordings: {
384
+ list: () => G("/recordings/list"),
385
+ get: (t) => G("/recordings/byCode", { recordingCode: t }),
386
+ requests: (t) => G("/recordings/requests", { recordingCode: t }),
387
+ start: (t, s, n) => F("/recordings/start", {
388
+ recordingCode: t,
389
+ recordingName: s,
390
+ targetUrl: n
391
+ }),
392
+ stop: (t) => F("/recordings/stop", null, { recordingCode: t }),
393
+ export: (t, s) => F("/recordings/export", { recordingCode: t, projectCode: s }),
394
+ import: (t, s) => F("/recordings/import", { recordingCode: t, projectCode: s }),
395
+ playback: (t, s) => F("/recordings/playback", { recordingCode: t, targetUrl: s }),
396
+ delete: (t) => ce("/recordings", { recordingCode: t })
397
+ },
398
+ requestLogs: {
399
+ list: (t) => G("/request-logs/list", t),
400
+ stats: () => G("/request-logs/stats"),
401
+ clear: (t) => ce("/request-logs/clear", { limit: t })
402
+ },
403
+ curl: {
404
+ parse: (t) => F("/curl/parse", { curlText: t }),
405
+ run: (t) => F("/curl/run", { curlText: t }),
406
+ importAsCase: (t) => F("/curl/import-as-case", t),
407
+ importAsEndpoint: (t) => F("/curl/import-as-endpoint", t)
408
+ },
409
+ openapi: {
410
+ parse: (t) => F("/openapi/parse", { content: t }),
411
+ importBatch: (t) => F("/openapi/import-batch", t),
412
+ sample: (t) => G("/openapi/sample", { format: t })
413
+ }
414
+ }, { Text: ae, Paragraph: hr } = le, Ye = { GET: "green", POST: "blue", PUT: "orange", DELETE: "red", PATCH: "purple" };
415
+ function Be({ activeEnvCode: t }) {
416
+ const [s, n] = m([]), [k, a] = m(!1), [y, c] = m(null), [f, x] = m(!1), [T, A] = m(null);
417
+ U(() => {
418
+ p();
419
+ }, [t]);
420
+ const p = async () => {
421
+ a(!0), c(null);
422
+ try {
423
+ const g = await q.endpoints.list(t);
424
+ n(Array.isArray(g) ? g : []);
425
+ } catch (g) {
426
+ c((g == null ? void 0 : g.message) || "API unavailable"), n([]);
427
+ } finally {
428
+ a(!1);
429
+ }
430
+ }, l = (g) => `${window.location.origin}/api/mock/${g.env_code || t || "default"}${g.path || ""}`, d = [
431
+ {
432
+ title: "路径",
433
+ dataIndex: "path",
434
+ key: "path",
435
+ width: 280,
436
+ render: (g, v) => /* @__PURE__ */ r(P, { children: [
437
+ /* @__PURE__ */ e(w, { color: Ye[v.method] || "default", children: v.method }),
438
+ /* @__PURE__ */ e(ae, { code: !0, copyable: { text: g }, children: g })
439
+ ] })
440
+ },
441
+ { title: "编码", dataIndex: "mock_code", key: "mock_code", width: 160 },
442
+ {
443
+ title: "优先级",
444
+ dataIndex: "priority",
445
+ key: "priority",
446
+ width: 80,
447
+ align: "center",
448
+ render: (g) => /* @__PURE__ */ r(w, { color: "blue", children: [
449
+ "P",
450
+ g || 5
451
+ ] })
452
+ },
453
+ { title: "状态码", dataIndex: "status_code", key: "status_code", width: 80, align: "center" },
454
+ {
455
+ title: "延迟",
456
+ dataIndex: "delay_ms",
457
+ key: "delay_ms",
458
+ width: 80,
459
+ align: "center",
460
+ render: (g) => g > 0 ? /* @__PURE__ */ r(ae, { type: "warning", children: [
461
+ g,
462
+ "ms"
463
+ ] }) : /* @__PURE__ */ e(ae, { type: "secondary", children: "-" })
464
+ },
465
+ {
466
+ title: "故障",
467
+ dataIndex: "fault_type",
468
+ key: "fault_type",
469
+ width: 110,
470
+ render: (g) => g && g !== "NONE" ? /* @__PURE__ */ e(w, { color: "red", children: g }) : /* @__PURE__ */ e(ae, { type: "secondary", children: "-" })
471
+ },
472
+ {
473
+ title: "场景",
474
+ dataIndex: "scenario_code",
475
+ key: "scenario_code",
476
+ width: 130,
477
+ render: (g) => g ? /* @__PURE__ */ e(w, { color: "purple", children: g }) : /* @__PURE__ */ e(ae, { type: "secondary", children: "-" })
478
+ },
479
+ {
480
+ title: "命中",
481
+ dataIndex: "hit_count",
482
+ key: "hit_count",
483
+ width: 80,
484
+ align: "center",
485
+ render: (g) => /* @__PURE__ */ e(ae, { strong: !0, children: g || 0 })
486
+ },
487
+ {
488
+ title: "状态",
489
+ dataIndex: "status",
490
+ key: "status",
491
+ width: 100,
492
+ align: "center",
493
+ render: (g) => g === 1 ? /* @__PURE__ */ e(w, { color: "green", children: "启用" }) : /* @__PURE__ */ e(w, { children: "禁用" })
494
+ },
495
+ {
496
+ title: "操作",
497
+ key: "action",
498
+ width: 160,
499
+ fixed: "right",
500
+ render: (g, v) => /* @__PURE__ */ r(P, { size: "small", children: [
501
+ /* @__PURE__ */ e(pe, { title: "预览响应", children: /* @__PURE__ */ e(
502
+ _,
503
+ {
504
+ size: "small",
505
+ type: "link",
506
+ icon: /* @__PURE__ */ e(Pe, {}),
507
+ onClick: () => {
508
+ A(v), x(!0);
509
+ },
510
+ children: "预览"
511
+ }
512
+ ) }),
513
+ /* @__PURE__ */ e(pe, { title: "复制URL", children: /* @__PURE__ */ e(
514
+ _,
515
+ {
516
+ size: "small",
517
+ type: "link",
518
+ icon: /* @__PURE__ */ e(ht, {}),
519
+ onClick: () => {
520
+ navigator.clipboard.writeText(l(v)), b.success("已复制");
521
+ }
522
+ }
523
+ ) })
524
+ ] })
525
+ }
526
+ ];
527
+ return /* @__PURE__ */ r("div", { children: [
528
+ y && /* @__PURE__ */ e(
529
+ V,
530
+ {
531
+ type: "warning",
532
+ showIcon: !0,
533
+ style: { marginBottom: 16 },
534
+ title: "后端 API 暂未连接",
535
+ description: y
536
+ }
537
+ ),
538
+ /* @__PURE__ */ r(Y, { gutter: 16, style: { marginBottom: 16 }, children: [
539
+ /* @__PURE__ */ e(z, { span: 6, children: /* @__PURE__ */ r(M, { children: [
540
+ /* @__PURE__ */ e("strong", { children: "总端点" }),
541
+ /* @__PURE__ */ e("div", { style: { fontSize: 22 }, children: s.length })
542
+ ] }) }),
543
+ /* @__PURE__ */ e(z, { span: 6, children: /* @__PURE__ */ r(M, { children: [
544
+ /* @__PURE__ */ e("strong", { children: "已启用" }),
545
+ /* @__PURE__ */ e("div", { style: { fontSize: 22, color: "#52c41a" }, children: s.filter((g) => g.status === 1).length })
546
+ ] }) }),
547
+ /* @__PURE__ */ e(z, { span: 6, children: /* @__PURE__ */ r(M, { children: [
548
+ /* @__PURE__ */ e("strong", { children: "已禁用" }),
549
+ /* @__PURE__ */ e("div", { style: { fontSize: 22, color: "#ff4d4f" }, children: s.filter((g) => g.status === 0).length })
550
+ ] }) }),
551
+ /* @__PURE__ */ e(z, { span: 6, children: /* @__PURE__ */ r(M, { children: [
552
+ /* @__PURE__ */ e("strong", { children: "总命中" }),
553
+ /* @__PURE__ */ e("div", { style: {
554
+ fontSize: 22,
555
+ color: "#1890ff"
556
+ }, children: s.reduce((g, v) => g + (v.hit_count || 0), 0) })
557
+ ] }) })
558
+ ] }),
559
+ /* @__PURE__ */ e(P, { style: { marginBottom: 16 }, children: /* @__PURE__ */ e(_, { icon: /* @__PURE__ */ e(ee, {}), onClick: p, children: "刷新" }) }),
560
+ /* @__PURE__ */ e(
561
+ Q,
562
+ {
563
+ dataSource: s,
564
+ columns: d,
565
+ rowKey: "id",
566
+ loading: k,
567
+ pagination: { pageSize: 10 },
568
+ scroll: { x: 1300 },
569
+ size: "small"
570
+ }
571
+ ),
572
+ /* @__PURE__ */ e(
573
+ we,
574
+ {
575
+ title: /* @__PURE__ */ r(P, { children: [
576
+ /* @__PURE__ */ e(Et, {}),
577
+ "端点详情: ",
578
+ T == null ? void 0 : T.mock_code
579
+ ] }),
580
+ open: f,
581
+ onClose: () => x(!1),
582
+ size: "large",
583
+ children: T && /* @__PURE__ */ r("div", { children: [
584
+ /* @__PURE__ */ r(R, { column: 2, size: "small", bordered: !0, style: { marginBottom: 16 }, children: [
585
+ /* @__PURE__ */ e(R.Item, { label: "编码", children: T.mock_code }),
586
+ /* @__PURE__ */ e(R.Item, { label: "名称", children: T.mock_name }),
587
+ /* @__PURE__ */ e(R.Item, { label: "方法", children: /* @__PURE__ */ e(w, { color: Ye[T.method], children: T.method }) }),
588
+ /* @__PURE__ */ e(R.Item, { label: "环境", children: T.env_code }),
589
+ /* @__PURE__ */ e(R.Item, { label: "路径", span: 2, children: T.path }),
590
+ /* @__PURE__ */ e(R.Item, { label: "状态码", children: T.status_code }),
591
+ /* @__PURE__ */ r(R.Item, { label: "延迟", children: [
592
+ T.delay_ms,
593
+ "ms"
594
+ ] }),
595
+ /* @__PURE__ */ r(R.Item, { label: "优先级", children: [
596
+ "P",
597
+ T.priority
598
+ ] }),
599
+ /* @__PURE__ */ e(R.Item, { label: "命中", children: T.hit_count || 0 }),
600
+ /* @__PURE__ */ e(R.Item, { label: "故障", children: T.fault_type && T.fault_type !== "NONE" ? /* @__PURE__ */ e(w, { color: "red", children: T.fault_type }) : /* @__PURE__ */ e(ae, { type: "secondary", children: "-" }) }),
601
+ /* @__PURE__ */ e(R.Item, { label: "场景", children: T.scenario_code || "-" }),
602
+ /* @__PURE__ */ e(R.Item, { label: "状态", span: 2, children: T.status === 1 ? /* @__PURE__ */ e(w, { color: "green", children: "启用" }) : /* @__PURE__ */ e(w, { children: "禁用" }) }),
603
+ /* @__PURE__ */ e(R.Item, { label: "完整 URL", span: 2, children: /* @__PURE__ */ e(ae, { copyable: !0, children: l(T) }) })
604
+ ] }),
605
+ /* @__PURE__ */ e(hr, { strong: !0, children: "响应模板:" }),
606
+ /* @__PURE__ */ e("pre", { style: {
607
+ background: "#f5f5f5",
608
+ padding: 12,
609
+ borderRadius: 4,
610
+ maxHeight: 350,
611
+ overflow: "auto",
612
+ fontSize: 13,
613
+ fontFamily: "monospace",
614
+ whiteSpace: "pre-wrap",
615
+ wordBreak: "break-all"
616
+ }, children: T.response_template })
617
+ ] })
618
+ }
619
+ )
620
+ ] });
621
+ }
622
+ const { Text: ze } = le, pr = { MOCK: "green", REAL: "blue", MIXED: "orange" };
623
+ function qe({ onEnvChange: t }) {
624
+ const [s, n] = m([]), [k, a] = m(!1);
625
+ U(() => {
626
+ y();
627
+ }, []);
628
+ const y = async () => {
629
+ a(!0);
630
+ try {
631
+ const f = await q.environments.list();
632
+ n(Array.isArray(f) ? f : []);
633
+ } catch (f) {
634
+ b.warning("加载环境列表失败: " + (f == null ? void 0 : f.message));
635
+ } finally {
636
+ a(!1);
637
+ }
638
+ };
639
+ return /* @__PURE__ */ r("div", { children: [
640
+ /* @__PURE__ */ e(
641
+ V,
642
+ {
643
+ type: "info",
644
+ showIcon: !0,
645
+ style: { marginBottom: 16 },
646
+ message: "环境隔离 - 控制 Mock 与真实服务的切换",
647
+ description: /* @__PURE__ */ r("div", { children: [
648
+ /* @__PURE__ */ r("div", { children: [
649
+ /* @__PURE__ */ e(w, { color: "green", children: "MOCK" }),
650
+ " 完全拦截,仅返回 Mock 数据"
651
+ ] }),
652
+ /* @__PURE__ */ r("div", { children: [
653
+ /* @__PURE__ */ e(w, { color: "blue", children: "REAL" }),
654
+ " 全部代理到 base_url(适合压测、回归测试)"
655
+ ] }),
656
+ /* @__PURE__ */ r("div", { children: [
657
+ /* @__PURE__ */ e(w, { color: "orange", children: "MIXED" }),
658
+ " Mock 优先,未匹配时转发到 base_url(开发联调)"
659
+ ] })
660
+ ] })
661
+ }
662
+ ),
663
+ /* @__PURE__ */ e(P, { style: { marginBottom: 16 }, children: /* @__PURE__ */ e(_, { icon: /* @__PURE__ */ e(ee, {}), onClick: y, children: "刷新" }) }),
664
+ /* @__PURE__ */ e(
665
+ Q,
666
+ {
667
+ dataSource: s,
668
+ columns: [
669
+ {
670
+ title: "环境编码",
671
+ dataIndex: "env_code",
672
+ key: "env_code",
673
+ width: 140,
674
+ render: (f) => /* @__PURE__ */ e(ze, { code: !0, children: f })
675
+ },
676
+ { title: "环境名称", dataIndex: "env_name", key: "env_name", width: 160 },
677
+ {
678
+ title: "类型",
679
+ dataIndex: "env_type",
680
+ key: "env_type",
681
+ width: 240,
682
+ render: (f) => /* @__PURE__ */ e(w, { color: pr[f] || "default", children: f })
683
+ },
684
+ {
685
+ title: "真实服务地址",
686
+ dataIndex: "base_url",
687
+ key: "base_url",
688
+ render: (f) => f ? /* @__PURE__ */ e(ze, { copyable: !0, children: f }) : /* @__PURE__ */ e(ze, { type: "secondary", children: "-" })
689
+ },
690
+ {
691
+ title: "默认",
692
+ dataIndex: "is_default",
693
+ key: "is_default",
694
+ width: 90,
695
+ align: "center",
696
+ render: (f) => f === 1 ? /* @__PURE__ */ e(w, { color: "gold", children: "默认" }) : "-"
697
+ },
698
+ {
699
+ title: "描述",
700
+ dataIndex: "description",
701
+ key: "description",
702
+ width: 220,
703
+ render: (f) => f || "-"
704
+ },
705
+ {
706
+ title: "操作",
707
+ key: "action",
708
+ width: 120,
709
+ render: (f, x) => /* @__PURE__ */ e(P, { size: "small", children: /* @__PURE__ */ e(
710
+ _,
711
+ {
712
+ size: "small",
713
+ type: "link",
714
+ icon: /* @__PURE__ */ e(pt, {}),
715
+ onClick: () => {
716
+ t && t(x.env_code);
717
+ },
718
+ children: "切换"
719
+ }
720
+ ) })
721
+ }
722
+ ],
723
+ rowKey: "id",
724
+ loading: k,
725
+ pagination: { pageSize: 10 },
726
+ size: "small"
727
+ }
728
+ )
729
+ ] });
730
+ }
731
+ const { Text: mr } = le;
732
+ function yr() {
733
+ const [t, s] = m([]), [n, k] = m(!1), [a, y] = m(!1), [c, f] = m(null);
734
+ U(() => {
735
+ x();
736
+ }, []);
737
+ const x = async () => {
738
+ k(!0);
739
+ try {
740
+ const l = await q.scenarios.list();
741
+ s(Array.isArray(l) ? l : []);
742
+ } catch {
743
+ b.warning("加载场景列表失败");
744
+ } finally {
745
+ k(!1);
746
+ }
747
+ }, T = async (l) => {
748
+ try {
749
+ await q.scenarios.reset(l), b.success("已重置所有实例状态");
750
+ } catch {
751
+ b.error("重置失败");
752
+ }
753
+ }, A = async (l) => {
754
+ try {
755
+ const d = await q.scenarios.instances(l);
756
+ f({ code: l, list: d }), y(!0);
757
+ } catch {
758
+ b.error("加载失败");
759
+ }
760
+ };
761
+ return /* @__PURE__ */ r("div", { children: [
762
+ /* @__PURE__ */ e(
763
+ V,
764
+ {
765
+ type: "info",
766
+ showIcon: !0,
767
+ style: { marginBottom: 16 },
768
+ title: "场景状态机 (Scenario)",
769
+ description: "用状态机驱动 Mock 集合,模拟完整业务流程(如:未登录→登录中→已登录→下单→已支付→完成)。实例通过 X-Session-Id 或 X-Trace-Id 区分,每个实例独立维护当前状态。"
770
+ }
771
+ ),
772
+ /* @__PURE__ */ e(P, { style: { marginBottom: 16 }, children: /* @__PURE__ */ e(_, { icon: /* @__PURE__ */ e(ee, {}), onClick: x, children: "刷新" }) }),
773
+ /* @__PURE__ */ e(
774
+ Q,
775
+ {
776
+ dataSource: t,
777
+ columns: [
778
+ {
779
+ title: "场景编码",
780
+ dataIndex: "scenario_code",
781
+ key: "scenario_code",
782
+ width: 160,
783
+ render: (l) => /* @__PURE__ */ e(mr, { code: !0, children: l })
784
+ },
785
+ { title: "场景名称", dataIndex: "scenario_name", key: "scenario_name", width: 200 },
786
+ {
787
+ title: "初始状态",
788
+ dataIndex: "initial_state",
789
+ key: "initial_state",
790
+ width: 140,
791
+ render: (l) => /* @__PURE__ */ e(w, { color: "blue", children: l })
792
+ },
793
+ {
794
+ title: "描述",
795
+ dataIndex: "description",
796
+ key: "description",
797
+ width: 240,
798
+ render: (l) => l || "-"
799
+ },
800
+ {
801
+ title: "操作",
802
+ key: "action",
803
+ width: 200,
804
+ fixed: "right",
805
+ render: (l, d) => /* @__PURE__ */ r(P, { size: "small", children: [
806
+ /* @__PURE__ */ e(
807
+ _,
808
+ {
809
+ size: "small",
810
+ type: "link",
811
+ icon: /* @__PURE__ */ e(Pt, {}),
812
+ onClick: () => A(d.scenario_code),
813
+ children: "实例"
814
+ }
815
+ ),
816
+ /* @__PURE__ */ e(
817
+ _,
818
+ {
819
+ size: "small",
820
+ type: "link",
821
+ icon: /* @__PURE__ */ e(Rt, {}),
822
+ onClick: () => T(d.scenario_code),
823
+ children: "重置"
824
+ }
825
+ )
826
+ ] })
827
+ }
828
+ ],
829
+ rowKey: "id",
830
+ loading: n,
831
+ pagination: { pageSize: 10 },
832
+ scroll: { x: 1100 },
833
+ size: "small"
834
+ }
835
+ ),
836
+ /* @__PURE__ */ e(
837
+ me,
838
+ {
839
+ title: `场景实例: ${c == null ? void 0 : c.code}`,
840
+ open: a,
841
+ onCancel: () => y(!1),
842
+ footer: /* @__PURE__ */ e(_, { onClick: () => y(!1), children: "关闭" }),
843
+ size: "large",
844
+ children: c && /* @__PURE__ */ e(
845
+ Q,
846
+ {
847
+ dataSource: Array.isArray(c.list) ? c.list : [],
848
+ columns: [
849
+ { title: "实例标识", dataIndex: "instance_key", key: "instance_key" },
850
+ {
851
+ title: "当前状态",
852
+ dataIndex: "current_state",
853
+ key: "current_state",
854
+ render: (l) => /* @__PURE__ */ e(w, { color: "blue", children: l })
855
+ },
856
+ { title: "最后变更", dataIndex: "update_time", key: "update_time" }
857
+ ],
858
+ rowKey: (l, d) => l.instance_key || d,
859
+ pagination: !1,
860
+ size: "small"
861
+ }
862
+ )
863
+ }
864
+ )
865
+ ] });
866
+ }
867
+ const { Text: se } = le, Me = { PASS: "green", FAIL: "red", SKIP: "default" }, gr = { P0: "red", P1: "orange", P2: "blue", P3: "default" };
868
+ function fr() {
869
+ const [t, s] = m([]), [n, k] = m(!1), [a, y] = m([]), [c, f] = m(!1), [x, T] = m(null), [A, p] = m(null), [l, d] = m(!1);
870
+ U(() => {
871
+ g();
872
+ }, []);
873
+ const g = async () => {
874
+ k(!0);
875
+ try {
876
+ const u = await q.cases.list();
877
+ s(Array.isArray(u) ? u : []);
878
+ } catch {
879
+ b.warning("加载用例列表失败");
880
+ } finally {
881
+ k(!1);
882
+ }
883
+ }, v = async (u) => {
884
+ try {
885
+ const i = await q.cases.run(u.case_code);
886
+ T(i), f(!0), (i == null ? void 0 : i.status) === "PASS" ? b.success("用例通过") : b.error("用例失败: " + ((i == null ? void 0 : i.error) || (i == null ? void 0 : i.actualStatus))), g();
887
+ } catch (i) {
888
+ b.error("执行失败: " + (i == null ? void 0 : i.message));
889
+ }
890
+ }, $ = async () => {
891
+ if (a.length === 0) {
892
+ b.warning("请先选择用例");
893
+ return;
894
+ }
895
+ try {
896
+ const u = await q.cases.runBatch(a);
897
+ p(u), d(!0), b.success(`批量执行完成: ${u == null ? void 0 : u.pass} 通过, ${u == null ? void 0 : u.fail} 失败`), g();
898
+ } catch {
899
+ b.error("批量执行失败");
900
+ }
901
+ }, C = [
902
+ {
903
+ title: "用例编码",
904
+ dataIndex: "case_code",
905
+ key: "case_code",
906
+ width: 180,
907
+ render: (u) => /* @__PURE__ */ e(se, { code: !0, children: u })
908
+ },
909
+ { title: "名称", dataIndex: "case_name", key: "case_name", width: 220 },
910
+ {
911
+ title: "分组",
912
+ dataIndex: "case_group",
913
+ key: "case_group",
914
+ width: 130,
915
+ render: (u) => u ? /* @__PURE__ */ e(w, { children: u }) : "-"
916
+ },
917
+ {
918
+ title: "方法",
919
+ dataIndex: "request_method",
920
+ key: "request_method",
921
+ width: 80,
922
+ render: (u) => /* @__PURE__ */ e(w, { color: "blue", children: u })
923
+ },
924
+ {
925
+ title: "路径",
926
+ dataIndex: "request_url",
927
+ key: "request_url",
928
+ ellipsis: !0,
929
+ render: (u) => /* @__PURE__ */ e(se, { code: !0, children: u })
930
+ },
931
+ {
932
+ title: "优先级",
933
+ dataIndex: "priority",
934
+ key: "priority",
935
+ width: 80,
936
+ align: "center",
937
+ render: (u) => /* @__PURE__ */ e(w, { color: gr[u], children: u || "P1" })
938
+ },
939
+ {
940
+ title: "上次结果",
941
+ dataIndex: "last_run_result",
942
+ key: "last_run_result",
943
+ width: 100,
944
+ align: "center",
945
+ render: (u) => u ? /* @__PURE__ */ e(w, { color: Me[u], children: u }) : "-"
946
+ },
947
+ {
948
+ title: "统计",
949
+ key: "stats",
950
+ width: 130,
951
+ align: "center",
952
+ render: (u, i) => /* @__PURE__ */ r(P, { size: "small", children: [
953
+ /* @__PURE__ */ e(se, { type: "success", children: i.pass_count || 0 }),
954
+ "/",
955
+ /* @__PURE__ */ e(se, { type: "danger", children: i.fail_count || 0 }),
956
+ /* @__PURE__ */ r(se, { type: "secondary", children: [
957
+ "(",
958
+ i.run_count || 0,
959
+ ")"
960
+ ] })
961
+ ] })
962
+ },
963
+ {
964
+ title: "操作",
965
+ key: "action",
966
+ width: 120,
967
+ fixed: "right",
968
+ render: (u, i) => /* @__PURE__ */ e(P, { size: "small", children: /* @__PURE__ */ e(
969
+ _,
970
+ {
971
+ size: "small",
972
+ type: "link",
973
+ icon: /* @__PURE__ */ e(Pe, {}),
974
+ onClick: () => v(i),
975
+ children: "运行"
976
+ }
977
+ ) })
978
+ }
979
+ ];
980
+ return /* @__PURE__ */ r("div", { children: [
981
+ /* @__PURE__ */ e(
982
+ V,
983
+ {
984
+ type: "info",
985
+ showIcon: !0,
986
+ style: { marginBottom: 16 },
987
+ title: "测试用例库",
988
+ description: "对 Mock 接口进行断言验证。支持 7 种断言类型:STATUS / HEADER / BODY / JSON_PATH / REGEX / SCHEMA / RESPONSE_TIME。支持单条运行与批量运行,自动统计通过/失败次数。"
989
+ }
990
+ ),
991
+ /* @__PURE__ */ r(P, { style: { marginBottom: 16 }, children: [
992
+ /* @__PURE__ */ e(_, { icon: /* @__PURE__ */ e(ee, {}), onClick: g, children: "刷新" }),
993
+ /* @__PURE__ */ r(
994
+ _,
995
+ {
996
+ type: "primary",
997
+ icon: /* @__PURE__ */ e(Pe, {}),
998
+ onClick: $,
999
+ disabled: a.length === 0,
1000
+ children: [
1001
+ "批量运行 (",
1002
+ a.length,
1003
+ ")"
1004
+ ]
1005
+ }
1006
+ )
1007
+ ] }),
1008
+ /* @__PURE__ */ e(
1009
+ Q,
1010
+ {
1011
+ dataSource: t,
1012
+ columns: C,
1013
+ rowKey: "id",
1014
+ loading: n,
1015
+ rowSelection: {
1016
+ selectedRowKeys: a,
1017
+ // 批量执行收的是 **case_code 列表**(后端按 case_code 查行),
1018
+ // 原来这里存的是 rowKey(=id) ⇒ 批量执行永远查不到行。
1019
+ onChange: (u, i) => y(i.map((S) => S.case_code))
1020
+ },
1021
+ pagination: { pageSize: 10 },
1022
+ scroll: { x: 1300 },
1023
+ size: "small"
1024
+ }
1025
+ ),
1026
+ /* @__PURE__ */ e(
1027
+ we,
1028
+ {
1029
+ title: /* @__PURE__ */ r(P, { children: [
1030
+ /* @__PURE__ */ e(Ot, {}),
1031
+ "用例执行结果"
1032
+ ] }),
1033
+ open: c,
1034
+ onClose: () => f(!1),
1035
+ size: "large",
1036
+ children: x && /* @__PURE__ */ r("div", { children: [
1037
+ /* @__PURE__ */ r(Y, { gutter: 16, style: { marginBottom: 16 }, children: [
1038
+ /* @__PURE__ */ e(z, { span: 8, children: /* @__PURE__ */ e(M, { children: /* @__PURE__ */ e(
1039
+ K,
1040
+ {
1041
+ title: "结果",
1042
+ value: x.status,
1043
+ styles: { content: { color: Me[x.status] === "green" ? "#52c41a" : "#ff4d4f" } }
1044
+ }
1045
+ ) }) }),
1046
+ /* @__PURE__ */ e(z, { span: 8, children: /* @__PURE__ */ e(M, { children: /* @__PURE__ */ e(K, { title: "实际状态码", value: x.actualStatus || "-" }) }) }),
1047
+ /* @__PURE__ */ e(z, { span: 8, children: /* @__PURE__ */ e(M, { children: /* @__PURE__ */ e(K, { title: "耗时(ms)", value: x.durationMs || 0 }) }) })
1048
+ ] }),
1049
+ /* @__PURE__ */ r(R, { column: 1, size: "small", bordered: !0, style: { marginBottom: 16 }, children: [
1050
+ /* @__PURE__ */ e(R.Item, { label: "用例编码", children: x.caseCode }),
1051
+ /* @__PURE__ */ e(R.Item, { label: "用例名称", children: x.caseName }),
1052
+ /* @__PURE__ */ e(R.Item, { label: "错误信息", children: x.error || "-" })
1053
+ ] }),
1054
+ x.assertionResults && /* @__PURE__ */ r(Le, { children: [
1055
+ /* @__PURE__ */ e(se, { strong: !0, children: "断言详情:" }),
1056
+ /* @__PURE__ */ e(
1057
+ Q,
1058
+ {
1059
+ style: { marginTop: 8 },
1060
+ dataSource: x.assertionResults,
1061
+ columns: [
1062
+ { title: "断言类型", dataIndex: "type", key: "type", width: 110 },
1063
+ { title: "表达式", dataIndex: "expression", key: "expression" },
1064
+ { title: "期望值", dataIndex: "expected", key: "expected" },
1065
+ { title: "实际值", dataIndex: "actual", key: "actual" },
1066
+ {
1067
+ title: "结果",
1068
+ dataIndex: "passed",
1069
+ key: "passed",
1070
+ width: 80,
1071
+ render: (u) => u ? /* @__PURE__ */ e(w, { color: "green", children: "PASS" }) : /* @__PURE__ */ e(w, { color: "red", children: "FAIL" })
1072
+ }
1073
+ ],
1074
+ pagination: !1,
1075
+ size: "small"
1076
+ }
1077
+ )
1078
+ ] }),
1079
+ /* @__PURE__ */ e(se, { strong: !0, style: { marginTop: 16, display: "block" }, children: "响应体:" }),
1080
+ /* @__PURE__ */ e("pre", { style: {
1081
+ background: "#f5f5f5",
1082
+ padding: 12,
1083
+ borderRadius: 4,
1084
+ maxHeight: 250,
1085
+ overflow: "auto",
1086
+ fontSize: 12,
1087
+ fontFamily: "monospace",
1088
+ whiteSpace: "pre-wrap",
1089
+ wordBreak: "break-all"
1090
+ }, children: x.responseBody || "(empty)" })
1091
+ ] })
1092
+ }
1093
+ ),
1094
+ /* @__PURE__ */ e(
1095
+ me,
1096
+ {
1097
+ title: `批量执行结果 (${(A == null ? void 0 : A.total) || 0} 条)`,
1098
+ open: l,
1099
+ onCancel: () => d(!1),
1100
+ footer: /* @__PURE__ */ e(_, { onClick: () => d(!1), children: "关闭" }),
1101
+ size: "large",
1102
+ children: A && /* @__PURE__ */ r(Le, { children: [
1103
+ /* @__PURE__ */ r(Y, { gutter: 16, style: { marginBottom: 16 }, children: [
1104
+ /* @__PURE__ */ e(z, { span: 6, children: /* @__PURE__ */ e(M, { children: /* @__PURE__ */ e(K, { title: "总数", value: A.total }) }) }),
1105
+ /* @__PURE__ */ e(z, { span: 6, children: /* @__PURE__ */ e(M, { children: /* @__PURE__ */ e(
1106
+ K,
1107
+ {
1108
+ title: "通过",
1109
+ value: A.pass,
1110
+ styles: { content: { color: "#52c41a" } }
1111
+ }
1112
+ ) }) }),
1113
+ /* @__PURE__ */ e(z, { span: 6, children: /* @__PURE__ */ e(M, { children: /* @__PURE__ */ e(
1114
+ K,
1115
+ {
1116
+ title: "失败",
1117
+ value: A.fail,
1118
+ styles: { content: { color: "#ff4d4f" } }
1119
+ }
1120
+ ) }) }),
1121
+ /* @__PURE__ */ e(z, { span: 6, children: /* @__PURE__ */ e(M, { children: /* @__PURE__ */ e(
1122
+ K,
1123
+ {
1124
+ title: "通过率",
1125
+ value: `${A.total > 0 ? Math.round(A.pass / A.total * 100) : 0}%`
1126
+ }
1127
+ ) }) })
1128
+ ] }),
1129
+ /* @__PURE__ */ e(
1130
+ Q,
1131
+ {
1132
+ dataSource: A.results || [],
1133
+ columns: [
1134
+ { title: "编码", dataIndex: "caseCode", key: "caseCode", width: 180 },
1135
+ { title: "名称", dataIndex: "caseName", key: "caseName" },
1136
+ {
1137
+ title: "结果",
1138
+ dataIndex: "status",
1139
+ key: "status",
1140
+ width: 80,
1141
+ render: (u) => /* @__PURE__ */ e(w, { color: Me[u], children: u })
1142
+ },
1143
+ { title: "耗时", dataIndex: "durationMs", key: "durationMs", width: 80, align: "center" },
1144
+ { title: "错误", dataIndex: "error", key: "error", ellipsis: !0 }
1145
+ ],
1146
+ pagination: !1,
1147
+ size: "small",
1148
+ rowKey: "caseCode"
1149
+ }
1150
+ )
1151
+ ] })
1152
+ }
1153
+ )
1154
+ ] });
1155
+ }
1156
+ const { Text: de } = le, Qe = {
1157
+ IDLE: "default",
1158
+ RECORDING: "red",
1159
+ STOPPED: "green",
1160
+ EXPIRED: "gray"
1161
+ };
1162
+ function br() {
1163
+ const [t, s] = m([]), [n, k] = m(!1), [a, y] = m(!1), [c, f] = m(null), [x, T] = m([]);
1164
+ U(() => {
1165
+ A();
1166
+ }, []);
1167
+ const A = async () => {
1168
+ k(!0);
1169
+ try {
1170
+ const d = await q.recordings.list();
1171
+ s(Array.isArray(d) ? d : []);
1172
+ } catch {
1173
+ b.warning("加载录制列表失败");
1174
+ } finally {
1175
+ k(!1);
1176
+ }
1177
+ }, p = async (d) => {
1178
+ try {
1179
+ const g = await q.recordings.requests(d.recording_code);
1180
+ f(d), T(Array.isArray(g) ? g : []), y(!0);
1181
+ } catch {
1182
+ b.error("加载失败");
1183
+ }
1184
+ };
1185
+ return /* @__PURE__ */ r("div", { children: [
1186
+ /* @__PURE__ */ e(
1187
+ V,
1188
+ {
1189
+ type: "info",
1190
+ showIcon: !0,
1191
+ style: { marginBottom: 16 },
1192
+ message: "流量录制与回放",
1193
+ description: /* @__PURE__ */ r("div", { children: [
1194
+ /* @__PURE__ */ r("div", { children: [
1195
+ "• 开启录制后,所有 ",
1196
+ /* @__PURE__ */ e(de, { code: !0, children: "/api/mock/{envCode}/**" }),
1197
+ " 请求会被捕获到数据库"
1198
+ ] }),
1199
+ /* @__PURE__ */ e("div", { children: "• 停止录制后,可一键转为 Mock endpoints(用于离线测试)" }),
1200
+ /* @__PURE__ */ e("div", { children: "• 支持回放录制到目标服务(验证录制有效 / 跨环境验证)" })
1201
+ ] })
1202
+ }
1203
+ ),
1204
+ /* @__PURE__ */ e(P, { style: { marginBottom: 16 }, children: /* @__PURE__ */ e(_, { icon: /* @__PURE__ */ e(ee, {}), onClick: A, children: "刷新" }) }),
1205
+ /* @__PURE__ */ e(
1206
+ Q,
1207
+ {
1208
+ dataSource: t,
1209
+ columns: [
1210
+ {
1211
+ title: "编码",
1212
+ dataIndex: "recording_code",
1213
+ key: "recording_code",
1214
+ width: 180,
1215
+ render: (d) => /* @__PURE__ */ e(de, { code: !0, children: d })
1216
+ },
1217
+ { title: "名称", dataIndex: "recording_name", key: "recording_name", width: 200 },
1218
+ {
1219
+ title: "状态",
1220
+ dataIndex: "record_status",
1221
+ key: "record_status",
1222
+ width: 110,
1223
+ render: (d) => /* @__PURE__ */ e(w, { color: Qe[d], children: d })
1224
+ },
1225
+ {
1226
+ title: "请求数",
1227
+ dataIndex: "total_requests",
1228
+ key: "total_requests",
1229
+ width: 90,
1230
+ align: "center"
1231
+ },
1232
+ {
1233
+ title: "目标 URL",
1234
+ dataIndex: "target_url",
1235
+ key: "target_url",
1236
+ ellipsis: !0,
1237
+ render: (d) => d ? /* @__PURE__ */ e(de, { copyable: { text: d }, children: d }) : "-"
1238
+ },
1239
+ { title: "开始时间", dataIndex: "start_time", key: "start_time", width: 170 },
1240
+ { title: "结束时间", dataIndex: "end_time", key: "end_time", width: 170 },
1241
+ {
1242
+ title: "操作",
1243
+ key: "action",
1244
+ width: 120,
1245
+ fixed: "right",
1246
+ render: (d, g) => /* @__PURE__ */ e(P, { size: "small", children: /* @__PURE__ */ e(
1247
+ _,
1248
+ {
1249
+ size: "small",
1250
+ type: "link",
1251
+ icon: /* @__PURE__ */ e(Je, {}),
1252
+ onClick: () => p(g),
1253
+ children: "详情"
1254
+ }
1255
+ ) })
1256
+ }
1257
+ ],
1258
+ rowKey: "id",
1259
+ loading: n,
1260
+ pagination: { pageSize: 10 },
1261
+ scroll: { x: 1300 },
1262
+ size: "small"
1263
+ }
1264
+ ),
1265
+ /* @__PURE__ */ e(
1266
+ we,
1267
+ {
1268
+ title: /* @__PURE__ */ r(P, { children: [
1269
+ /* @__PURE__ */ e(Je, {}),
1270
+ "录制详情: ",
1271
+ c == null ? void 0 : c.recording_code
1272
+ ] }),
1273
+ open: a,
1274
+ onClose: () => y(!1),
1275
+ size: "large",
1276
+ children: c && /* @__PURE__ */ r("div", { children: [
1277
+ /* @__PURE__ */ r(R, { column: 2, size: "small", bordered: !0, style: { marginBottom: 16 }, children: [
1278
+ /* @__PURE__ */ e(R.Item, { label: "编码", children: c.recording_code }),
1279
+ /* @__PURE__ */ e(R.Item, { label: "名称", children: c.recording_name }),
1280
+ /* @__PURE__ */ e(R.Item, { label: "状态", children: /* @__PURE__ */ e(w, { color: Qe[c.record_status], children: c.record_status }) }),
1281
+ /* @__PURE__ */ e(R.Item, { label: "请求数", children: c.total_requests }),
1282
+ /* @__PURE__ */ e(R.Item, { label: "目标 URL", span: 2, children: /* @__PURE__ */ e(de, { copyable: !0, children: c.target_url }) }),
1283
+ /* @__PURE__ */ e(R.Item, { label: "开始", children: c.start_time }),
1284
+ /* @__PURE__ */ e(R.Item, { label: "结束", children: c.end_time || "(录制中)" })
1285
+ ] }),
1286
+ /* @__PURE__ */ r(de, { strong: !0, children: [
1287
+ "请求列表 (共 ",
1288
+ x.length,
1289
+ " 条):"
1290
+ ] }),
1291
+ /* @__PURE__ */ e(
1292
+ Q,
1293
+ {
1294
+ style: { marginTop: 8 },
1295
+ dataSource: x,
1296
+ columns: [
1297
+ { title: "#", dataIndex: "sequence", key: "sequence", width: 50 },
1298
+ {
1299
+ title: "方法",
1300
+ dataIndex: "request_method",
1301
+ key: "request_method",
1302
+ width: 80,
1303
+ render: (d) => /* @__PURE__ */ e(w, { color: "blue", children: d })
1304
+ },
1305
+ {
1306
+ title: "URL",
1307
+ dataIndex: "request_url",
1308
+ key: "request_url",
1309
+ ellipsis: !0,
1310
+ render: (d) => /* @__PURE__ */ e(de, { code: !0, children: d })
1311
+ },
1312
+ {
1313
+ title: "响应",
1314
+ dataIndex: "response_status",
1315
+ key: "response_status",
1316
+ width: 80,
1317
+ render: (d) => /* @__PURE__ */ e(w, { color: d >= 400 ? "red" : "green", children: d })
1318
+ },
1319
+ {
1320
+ title: "耗时",
1321
+ dataIndex: "response_time",
1322
+ key: "response_time",
1323
+ width: 80,
1324
+ render: (d) => `${d || 0}ms`
1325
+ }
1326
+ ],
1327
+ pagination: { pageSize: 10 },
1328
+ size: "small",
1329
+ rowKey: "id"
1330
+ }
1331
+ )
1332
+ ] })
1333
+ }
1334
+ )
1335
+ ] });
1336
+ }
1337
+ const { Text: ue } = le, xr = { MOCK: "green", PROXY: "blue", 404: "red", 502: "orange" };
1338
+ function wr() {
1339
+ const [t, s] = m([]), [n, k] = m(null), [a, y] = m(!1), [c, f] = m(null), [x, T] = m(!1), [A, p] = m(""), [l, d] = m();
1340
+ U(() => {
1341
+ g();
1342
+ }, []);
1343
+ const g = async () => {
1344
+ y(!0);
1345
+ try {
1346
+ const [C, u] = await Promise.all([
1347
+ q.requestLogs.list({
1348
+ path: A || void 0,
1349
+ matched: l,
1350
+ limit: 100
1351
+ }),
1352
+ q.requestLogs.stats().catch(() => null)
1353
+ ]);
1354
+ s(Array.isArray(C) ? C : []), k(u);
1355
+ } catch {
1356
+ b.warning("加载失败");
1357
+ } finally {
1358
+ y(!1);
1359
+ }
1360
+ }, v = (C) => {
1361
+ f(C), T(!0);
1362
+ }, $ = [
1363
+ {
1364
+ title: "时间",
1365
+ dataIndex: "create_time",
1366
+ key: "create_time",
1367
+ width: 170,
1368
+ render: (C) => C ? new Date(C).toLocaleString() : "-"
1369
+ },
1370
+ {
1371
+ title: "环境",
1372
+ dataIndex: "env_code",
1373
+ key: "env_code",
1374
+ width: 100,
1375
+ render: (C) => /* @__PURE__ */ e(w, { children: C })
1376
+ },
1377
+ {
1378
+ title: "方法",
1379
+ dataIndex: "request_method",
1380
+ key: "request_method",
1381
+ width: 80,
1382
+ render: (C) => /* @__PURE__ */ e(w, { color: "blue", children: C })
1383
+ },
1384
+ {
1385
+ title: "路径",
1386
+ dataIndex: "request_path",
1387
+ key: "request_path",
1388
+ ellipsis: !0,
1389
+ render: (C) => /* @__PURE__ */ e(ue, { code: !0, children: C })
1390
+ },
1391
+ {
1392
+ title: "状态",
1393
+ dataIndex: "response_status",
1394
+ key: "response_status",
1395
+ width: 90,
1396
+ align: "center",
1397
+ render: (C) => C ? /* @__PURE__ */ e(w, { color: C >= 400 ? "red" : "green", children: C }) : "-"
1398
+ },
1399
+ {
1400
+ title: "匹配",
1401
+ dataIndex: "matched",
1402
+ key: "matched",
1403
+ width: 90,
1404
+ align: "center",
1405
+ render: (C) => C === 1 ? /* @__PURE__ */ e(w, { color: "green", children: "命中" }) : /* @__PURE__ */ e(w, { color: "red", children: "未匹配" })
1406
+ },
1407
+ {
1408
+ title: "回退",
1409
+ dataIndex: "fallback_type",
1410
+ key: "fallback_type",
1411
+ width: 100,
1412
+ render: (C) => C ? /* @__PURE__ */ e(w, { color: xr[C], children: C }) : "-"
1413
+ },
1414
+ {
1415
+ title: "耗时",
1416
+ dataIndex: "duration_ms",
1417
+ key: "duration_ms",
1418
+ width: 80,
1419
+ align: "center",
1420
+ render: (C) => `${C || 0}ms`
1421
+ },
1422
+ {
1423
+ title: "Mock",
1424
+ dataIndex: "mock_code",
1425
+ key: "mock_code",
1426
+ width: 160,
1427
+ ellipsis: !0,
1428
+ render: (C) => C ? /* @__PURE__ */ e(ue, { code: !0, children: C }) : "-"
1429
+ },
1430
+ {
1431
+ title: "操作",
1432
+ key: "action",
1433
+ width: 80,
1434
+ render: (C, u) => /* @__PURE__ */ e(
1435
+ _,
1436
+ {
1437
+ size: "small",
1438
+ type: "link",
1439
+ icon: /* @__PURE__ */ e(zt, {}),
1440
+ onClick: () => v(u),
1441
+ children: "详情"
1442
+ }
1443
+ )
1444
+ }
1445
+ ];
1446
+ return /* @__PURE__ */ r("div", { children: [
1447
+ /* @__PURE__ */ e(
1448
+ V,
1449
+ {
1450
+ type: "info",
1451
+ showIcon: !0,
1452
+ style: { marginBottom: 16 },
1453
+ title: "Mock 请求日志 - 排查未匹配请求",
1454
+ description: "每一次请求都会留痕。包括请求/响应体、是否匹配 Mock、回退类型、耗时、场景状态等。便于排查“为什么这个请求没有 Mock 命中”问题。"
1455
+ }
1456
+ ),
1457
+ n && /* @__PURE__ */ r(Y, { gutter: 16, style: { marginBottom: 16 }, children: [
1458
+ /* @__PURE__ */ e(z, { span: 6, children: /* @__PURE__ */ e(M, { children: /* @__PURE__ */ e(K, { title: "总请求数", value: n.total || 0 }) }) }),
1459
+ /* @__PURE__ */ e(z, { span: 6, children: /* @__PURE__ */ e(M, { children: /* @__PURE__ */ e(
1460
+ K,
1461
+ {
1462
+ title: "Mock 命中",
1463
+ value: n.matched || 0,
1464
+ styles: { content: { color: "#52c41a" } }
1465
+ }
1466
+ ) }) }),
1467
+ /* @__PURE__ */ e(z, { span: 6, children: /* @__PURE__ */ e(M, { children: /* @__PURE__ */ e(
1468
+ K,
1469
+ {
1470
+ title: "未匹配",
1471
+ value: n.unmatched || 0,
1472
+ styles: { content: { color: "#ff4d4f" } }
1473
+ }
1474
+ ) }) }),
1475
+ /* @__PURE__ */ e(z, { span: 6, children: /* @__PURE__ */ e(M, { children: /* @__PURE__ */ e(
1476
+ K,
1477
+ {
1478
+ title: "命中率",
1479
+ value: `${n.total > 0 ? Math.round(n.matched / n.total * 100) : 0}%`
1480
+ }
1481
+ ) }) })
1482
+ ] }),
1483
+ /* @__PURE__ */ r(P, { style: { marginBottom: 16 }, children: [
1484
+ /* @__PURE__ */ e(
1485
+ B,
1486
+ {
1487
+ placeholder: "搜索路径",
1488
+ prefix: /* @__PURE__ */ e(mt, {}),
1489
+ allowClear: !0,
1490
+ style: { width: 240 },
1491
+ value: A,
1492
+ onChange: (C) => p(C.target.value),
1493
+ onPressEnter: g
1494
+ }
1495
+ ),
1496
+ /* @__PURE__ */ e(
1497
+ X,
1498
+ {
1499
+ placeholder: "匹配状态",
1500
+ allowClear: !0,
1501
+ style: { width: 140 },
1502
+ value: l,
1503
+ onChange: d,
1504
+ options: [
1505
+ { value: 1, label: "已命中" },
1506
+ { value: 0, label: "未匹配" }
1507
+ ]
1508
+ }
1509
+ ),
1510
+ /* @__PURE__ */ e(_, { icon: /* @__PURE__ */ e(ee, {}), onClick: g, children: "查询" })
1511
+ ] }),
1512
+ /* @__PURE__ */ e(
1513
+ Q,
1514
+ {
1515
+ dataSource: t,
1516
+ columns: $,
1517
+ rowKey: "id",
1518
+ loading: a,
1519
+ pagination: { pageSize: 20 },
1520
+ scroll: { x: 1300 },
1521
+ size: "small"
1522
+ }
1523
+ ),
1524
+ /* @__PURE__ */ e(
1525
+ we,
1526
+ {
1527
+ title: "请求详情",
1528
+ open: x,
1529
+ onClose: () => T(!1),
1530
+ size: "large",
1531
+ children: c && /* @__PURE__ */ r("div", { children: [
1532
+ /* @__PURE__ */ r(R, { column: 2, size: "small", bordered: !0, style: { marginBottom: 16 }, children: [
1533
+ /* @__PURE__ */ e(R.Item, { label: "环境", children: c.env_code }),
1534
+ /* @__PURE__ */ e(R.Item, { label: "方法", children: /* @__PURE__ */ e(
1535
+ w,
1536
+ {
1537
+ color: "blue",
1538
+ children: c.request_method
1539
+ }
1540
+ ) }),
1541
+ /* @__PURE__ */ e(R.Item, { label: "路径", span: 2, children: /* @__PURE__ */ e(
1542
+ ue,
1543
+ {
1544
+ code: !0,
1545
+ children: c.request_path
1546
+ }
1547
+ ) }),
1548
+ /* @__PURE__ */ e(R.Item, { label: "状态码", children: /* @__PURE__ */ e(
1549
+ w,
1550
+ {
1551
+ color: c.response_status >= 400 ? "red" : "green",
1552
+ children: c.response_status
1553
+ }
1554
+ ) }),
1555
+ /* @__PURE__ */ r(R.Item, { label: "耗时", children: [
1556
+ c.duration_ms,
1557
+ "ms"
1558
+ ] }),
1559
+ /* @__PURE__ */ e(R.Item, { label: "匹配", children: c.matched === 1 ? /* @__PURE__ */ e(w, { color: "green", children: "命中" }) : /* @__PURE__ */ e(w, { color: "red", children: "未匹配" }) }),
1560
+ /* @__PURE__ */ e(R.Item, { label: "回退", children: c.fallback_type || "-" }),
1561
+ /* @__PURE__ */ e(R.Item, { label: "Mock", span: 2, children: c.mock_code || "-" }),
1562
+ /* @__PURE__ */ e(
1563
+ R.Item,
1564
+ {
1565
+ label: "场景状态",
1566
+ span: 2,
1567
+ children: c.scenario_state || "-"
1568
+ }
1569
+ ),
1570
+ /* @__PURE__ */ e(R.Item, { label: "客户端 IP", children: c.client_ip || "-" }),
1571
+ /* @__PURE__ */ e(R.Item, { label: "User-Agent", ellipsis: !0, children: c.user_agent || "-" }),
1572
+ /* @__PURE__ */ e(R.Item, { label: "时间", span: 2, children: c.create_time ? new Date(c.create_time).toLocaleString() : "-" })
1573
+ ] }),
1574
+ /* @__PURE__ */ e(ue, { strong: !0, children: "请求头:" }),
1575
+ /* @__PURE__ */ e("pre", { style: {
1576
+ background: "#f5f5f5",
1577
+ padding: 12,
1578
+ borderRadius: 4,
1579
+ maxHeight: 150,
1580
+ overflow: "auto",
1581
+ fontSize: 12,
1582
+ fontFamily: "monospace",
1583
+ whiteSpace: "pre-wrap"
1584
+ }, children: c.request_headers || "(无)" }),
1585
+ /* @__PURE__ */ e(ue, { strong: !0, style: { marginTop: 12, display: "block" }, children: "请求体:" }),
1586
+ /* @__PURE__ */ e("pre", { style: {
1587
+ background: "#f5f5f5",
1588
+ padding: 12,
1589
+ borderRadius: 4,
1590
+ maxHeight: 200,
1591
+ overflow: "auto",
1592
+ fontSize: 12,
1593
+ fontFamily: "monospace",
1594
+ whiteSpace: "pre-wrap",
1595
+ wordBreak: "break-all"
1596
+ }, children: c.request_body || "(无)" }),
1597
+ /* @__PURE__ */ e(ue, { strong: !0, style: { marginTop: 12, display: "block" }, children: "响应体:" }),
1598
+ /* @__PURE__ */ e("pre", { style: {
1599
+ background: "#f5f5f5",
1600
+ padding: 12,
1601
+ borderRadius: 4,
1602
+ maxHeight: 300,
1603
+ overflow: "auto",
1604
+ fontSize: 12,
1605
+ fontFamily: "monospace",
1606
+ whiteSpace: "pre-wrap",
1607
+ wordBreak: "break-all"
1608
+ }, children: c.response_body || "(无)" })
1609
+ ] })
1610
+ }
1611
+ )
1612
+ ] });
1613
+ }
1614
+ const { Text: te } = le, et = [
1615
+ { key: "endpoints", label: "Mock 端点", component: Be },
1616
+ { key: "environments", label: "环境 (MOCK/REAL/MIXED)", component: qe },
1617
+ { key: "scenarios", label: "场景状态机", component: yr },
1618
+ { key: "cases", label: "测试用例", component: fr },
1619
+ { key: "recordings", label: "录制回放", component: br },
1620
+ { key: "request-logs", label: "请求日志", component: wr }
1621
+ ];
1622
+ function Ir() {
1623
+ var A;
1624
+ const [t, s] = m("endpoints"), [n, k] = m([]), [a, y] = m("default"), [c, f] = m(null);
1625
+ U(() => {
1626
+ x(), T();
1627
+ }, []);
1628
+ const x = async () => {
1629
+ try {
1630
+ const p = await q.environments.list(), l = Array.isArray(p) ? p : [];
1631
+ if (k(l), l.length > 0 && !l.find((d) => d.env_code === a)) {
1632
+ const d = l.find((g) => g.is_default === 1) || l[0];
1633
+ y(d.env_code);
1634
+ }
1635
+ } catch {
1636
+ }
1637
+ }, T = async () => {
1638
+ try {
1639
+ const p = await q.stats();
1640
+ f(p);
1641
+ } catch {
1642
+ }
1643
+ };
1644
+ return (A = et.find((p) => p.key === t)) == null || A.component, /* @__PURE__ */ r("div", { children: [
1645
+ /* @__PURE__ */ e(
1646
+ ye,
1647
+ {
1648
+ title: "Mock 平台",
1649
+ subtitle: "WireMock 级 · Mock 端点管理、环境隔离、场景状态机、测试用例库、录制回放、请求日志"
1650
+ }
1651
+ ),
1652
+ /* @__PURE__ */ e(
1653
+ Ie,
1654
+ {
1655
+ activeKey: t,
1656
+ onChange: s,
1657
+ type: "card",
1658
+ tabBarExtraContent: /* @__PURE__ */ r(P, { size: "large", wrap: !0, children: [
1659
+ /* @__PURE__ */ r(P, { children: [
1660
+ /* @__PURE__ */ e(pt, {}),
1661
+ /* @__PURE__ */ e(te, { children: "当前环境:" }),
1662
+ /* @__PURE__ */ e(
1663
+ X,
1664
+ {
1665
+ value: a,
1666
+ onChange: y,
1667
+ style: { width: 200 },
1668
+ options: n.map((p) => ({
1669
+ value: p.env_code,
1670
+ label: `${p.env_name || p.env_code} (${p.env_type})`
1671
+ }))
1672
+ }
1673
+ )
1674
+ ] }),
1675
+ c && /* @__PURE__ */ r(P, { size: "large", children: [
1676
+ /* @__PURE__ */ r(te, { type: "secondary", children: [
1677
+ "端点: ",
1678
+ /* @__PURE__ */ e(te, { strong: !0, children: c.totalEndpoints })
1679
+ ] }),
1680
+ /* @__PURE__ */ r(te, { type: "secondary", children: [
1681
+ "启用: ",
1682
+ /* @__PURE__ */ e(
1683
+ te,
1684
+ {
1685
+ strong: !0,
1686
+ style: { color: "#52c41a" },
1687
+ children: c.activeEndpoints
1688
+ }
1689
+ )
1690
+ ] }),
1691
+ /* @__PURE__ */ r(te, { type: "secondary", children: [
1692
+ "场景: ",
1693
+ /* @__PURE__ */ e(te, { strong: !0, children: c.totalScenarios })
1694
+ ] }),
1695
+ /* @__PURE__ */ r(te, { type: "secondary", children: [
1696
+ "用例: ",
1697
+ /* @__PURE__ */ e(te, { strong: !0, children: c.totalCases })
1698
+ ] })
1699
+ ] }),
1700
+ /* @__PURE__ */ e(_, { icon: /* @__PURE__ */ e(ee, {}), onClick: () => {
1701
+ x(), T();
1702
+ }, children: "刷新" })
1703
+ ] }),
1704
+ items: et.map((p) => ({
1705
+ key: p.key,
1706
+ label: p.label,
1707
+ children: p.component === Be ? /* @__PURE__ */ e(Be, { activeEnvCode: a }) : p.component === qe ? /* @__PURE__ */ e(qe, { onEnvChange: (l) => {
1708
+ y(l), b.success(`已切换到环境: ${l}`);
1709
+ } }) : /* @__PURE__ */ e(p.component, {})
1710
+ }))
1711
+ }
1712
+ )
1713
+ ] });
1714
+ }
1715
+ const Qr = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1716
+ __proto__: null,
1717
+ default: Ir
1718
+ }, Symbol.toStringTag, { value: "Module" })), { Text: ge, Paragraph: en } = le, tt = [
1719
+ {
1720
+ group: "基础数据",
1721
+ icon: /* @__PURE__ */ e(fe, {}),
1722
+ items: [
1723
+ { syntax: "@uuid", desc: "随机 UUID", example: "a3f2e1b7-8c4d-4e6f-9a1b-2c3d4e5f6a7b" },
1724
+ { syntax: "@int(1, 100)", desc: "随机整数(含边界)", example: "42" },
1725
+ { syntax: "@int", desc: "随机整数(0-1000)", example: "731" },
1726
+ { syntax: "@boolean", desc: "随机布尔", example: "true" },
1727
+ { syntax: '@pick("a","b","c")', desc: "从列表随机取一项", example: '"b"' }
1728
+ ]
1729
+ },
1730
+ {
1731
+ group: "时间相关",
1732
+ icon: /* @__PURE__ */ e(ke, {}),
1733
+ items: [
1734
+ { syntax: "@datetime", desc: "当前时间 (yyyy-MM-dd HH:mm:ss)", example: "2026-06-17 22:30:15" },
1735
+ { syntax: "@date", desc: "当前日期 (yyyy-MM-dd)", example: "2026-06-17" },
1736
+ { syntax: "@time", desc: "当前时间戳 (毫秒)", example: "1718639415000" },
1737
+ { syntax: "@timestamp", desc: "Unix 秒级时间戳", example: "1718639415" }
1738
+ ]
1739
+ },
1740
+ {
1741
+ group: "文本生成",
1742
+ icon: /* @__PURE__ */ e(ke, {}),
1743
+ items: [
1744
+ { syntax: "@name", desc: "随机中文姓名", example: "张伟" },
1745
+ { syntax: "@firstName", desc: "随机名", example: "伟" },
1746
+ { syntax: "@lastName", desc: "随机姓", example: "张" },
1747
+ { syntax: "@email", desc: "随机邮箱", example: "zhangwei@example.com" },
1748
+ { syntax: "@phone", desc: "随机手机号(中国)", example: "13812345678" },
1749
+ { syntax: "@idCard", desc: "随机身份证号", example: "110101199003078234" },
1750
+ { syntax: "@word", desc: "随机英文单词", example: "horizon" },
1751
+ { syntax: "@sentence(5, 10)", desc: "随机句子 (5-10 词)", example: "The quick brown fox jumps." },
1752
+ { syntax: "@paragraph(3, 5)", desc: "随机段落 (3-5 句)", example: "..." }
1753
+ ]
1754
+ },
1755
+ {
1756
+ group: "序列与状态",
1757
+ icon: /* @__PURE__ */ e(ke, {}),
1758
+ items: [
1759
+ { syntax: "@sequence(1)", desc: "自增序号(每次调用 +1,1 起始)", example: "1, 2, 3, ..." },
1760
+ { syntax: "@sequence(100, 5)", desc: "自增序号(100 起始,步长 5)", example: "100, 105, 110, ..." }
1761
+ ]
1762
+ },
1763
+ {
1764
+ group: "请求上下文",
1765
+ icon: /* @__PURE__ */ e(ke, {}),
1766
+ items: [
1767
+ { syntax: "#path.id", desc: "从 URL 路径取值 /users/123 → 123", example: "123" },
1768
+ { syntax: "#query.page", desc: "从 query string 取值 ?page=2", example: "2" },
1769
+ { syntax: "#header.X-Token", desc: "从请求头取值", example: "abc.def.ghi" },
1770
+ { syntax: "#body.username", desc: "从请求体 JSON 取值", example: '"alice"' }
1771
+ ]
1772
+ }
1773
+ ];
1774
+ function tn({ onInsert: t, form: s, formField: n = "responseTemplate" }) {
1775
+ const [k, a] = m(""), y = (p) => {
1776
+ var l;
1777
+ try {
1778
+ (l = navigator.clipboard) == null || l.writeText(p);
1779
+ } catch {
1780
+ }
1781
+ if (t)
1782
+ t(p);
1783
+ else if (s) {
1784
+ const d = s.getFieldValue(n) || "";
1785
+ s.setFieldsValue({ [n]: d + (d.endsWith(`
1786
+ `) || !d ? "" : " ") + p });
1787
+ }
1788
+ b.success(`已插入: ${p}`);
1789
+ }, c = (p) => {
1790
+ var l;
1791
+ try {
1792
+ (l = navigator.clipboard) == null || l.writeText(p), b.success("已复制到剪贴板");
1793
+ } catch {
1794
+ b.warning("复制失败,请手动选择");
1795
+ }
1796
+ }, f = k.toLowerCase(), x = tt.map((p) => ({
1797
+ ...p,
1798
+ items: p.items.filter(
1799
+ (l) => !f || l.syntax.toLowerCase().includes(f) || l.desc.toLowerCase().includes(f) || l.example.toLowerCase().includes(f)
1800
+ )
1801
+ })).filter((p) => p.items.length > 0), T = tt.reduce((p, l) => p + l.items.length, 0), A = x.reduce((p, l) => p + l.items.length, 0);
1802
+ return /* @__PURE__ */ r(
1803
+ M,
1804
+ {
1805
+ size: "small",
1806
+ title: /* @__PURE__ */ r(P, { children: [
1807
+ /* @__PURE__ */ e(fe, {}),
1808
+ /* @__PURE__ */ e(ge, { strong: !0, children: "模板表达式" }),
1809
+ /* @__PURE__ */ r(w, { color: "blue", children: [
1810
+ A,
1811
+ "/",
1812
+ T
1813
+ ] }),
1814
+ /* @__PURE__ */ e(pe, { title: "点击按钮即可插入到上方响应模板;点击 syntax 文本可复制", children: /* @__PURE__ */ e(Mt, { style: { color: "#999" } }) })
1815
+ ] }),
1816
+ extra: /* @__PURE__ */ e(
1817
+ B,
1818
+ {
1819
+ size: "small",
1820
+ placeholder: "搜索 @ 表达式",
1821
+ prefix: /* @__PURE__ */ e(mt, {}),
1822
+ value: k,
1823
+ onChange: (p) => a(p.target.value),
1824
+ style: { width: 180 },
1825
+ allowClear: !0
1826
+ }
1827
+ ),
1828
+ style: { marginTop: 8, background: "#fafafa" },
1829
+ styles: { body: { padding: 12, maxHeight: 320, overflow: "auto" } },
1830
+ children: [
1831
+ x.length === 0 && /* @__PURE__ */ e(ge, { type: "secondary", style: { display: "block", textAlign: "center", padding: 16 }, children: "没有匹配的表达式" }),
1832
+ x.map((p) => /* @__PURE__ */ r("div", { style: { marginBottom: 12 }, children: [
1833
+ /* @__PURE__ */ r(P, { size: 4, style: { marginBottom: 6 }, children: [
1834
+ p.icon,
1835
+ /* @__PURE__ */ e(ge, { strong: !0, style: { fontSize: 13 }, children: p.group }),
1836
+ /* @__PURE__ */ e(w, { children: p.items.length })
1837
+ ] }),
1838
+ /* @__PURE__ */ e(Y, { gutter: [8, 8], children: p.items.map((l) => /* @__PURE__ */ e(z, { span: 24, children: /* @__PURE__ */ r(
1839
+ "div",
1840
+ {
1841
+ style: {
1842
+ display: "flex",
1843
+ alignItems: "center",
1844
+ padding: "6px 8px",
1845
+ background: "#fff",
1846
+ border: "1px solid #f0f0f0",
1847
+ borderRadius: 4,
1848
+ gap: 8
1849
+ },
1850
+ children: [
1851
+ /* @__PURE__ */ e(pe, { title: "点击复制", children: /* @__PURE__ */ e(
1852
+ ge,
1853
+ {
1854
+ code: !0,
1855
+ style: { cursor: "pointer", minWidth: 140, fontSize: 12 },
1856
+ onClick: () => c(l.syntax),
1857
+ children: l.syntax
1858
+ }
1859
+ ) }),
1860
+ /* @__PURE__ */ e(ge, { type: "secondary", style: { fontSize: 12, flex: 1 }, children: l.desc }),
1861
+ /* @__PURE__ */ e(w, { color: "default", style: { margin: 0, fontFamily: "monospace" }, children: l.example }),
1862
+ /* @__PURE__ */ e(pe, { title: "插入到响应模板", children: /* @__PURE__ */ e(
1863
+ _,
1864
+ {
1865
+ size: "small",
1866
+ type: "text",
1867
+ icon: /* @__PURE__ */ e(ht, {}),
1868
+ onClick: () => y(l.syntax)
1869
+ }
1870
+ ) })
1871
+ ]
1872
+ }
1873
+ ) }, l.syntax)) })
1874
+ ] }, p.group))
1875
+ ]
1876
+ }
1877
+ );
1878
+ }
1879
+ const { TextArea: rt } = B, { Text: he, Paragraph: Sr } = le;
1880
+ function rn({ open: t, onClose: s, onSuccess: n, envOptions: k = [] }) {
1881
+ const [a, y] = m(""), [c, f] = m(null), [x, T] = m(null), [A, p] = m(!1), [l, d] = m(null), [g, v] = m(!1), [$, C] = m("import"), [u] = E.useForm(), [i] = E.useForm(), S = () => {
1882
+ y(""), f(null), T(null), d(null), u.resetFields(), i.resetFields();
1883
+ }, L = () => {
1884
+ S(), s();
1885
+ }, J = async () => {
1886
+ var O, I, D, W;
1887
+ if (!a.trim()) {
1888
+ b.warning("请先粘贴 curl 命令");
1889
+ return;
1890
+ }
1891
+ T(null), f(null), d(null);
1892
+ try {
1893
+ const j = await q.curl.parse(a);
1894
+ j.success ? (f(j.data), u.setFieldsValue({
1895
+ caseName: `from-curl-${((O = j.data) == null ? void 0 : O.method) || "GET"}-${(((I = j.data) == null ? void 0 : I.path) || "").replace(/\W+/g, "-")}`,
1896
+ caseGroup: "imported",
1897
+ envCode: k[0] || "default"
1898
+ }), i.setFieldsValue({
1899
+ mockName: `mock-${((D = j.data) == null ? void 0 : D.method) || "GET"}-${(((W = j.data) == null ? void 0 : W.path) || "").replace(/\W+/g, "-")}`,
1900
+ envCode: k[0] || "default",
1901
+ projectCode: "default",
1902
+ responseTemplate: `{
1903
+ "code": 0,
1904
+ "message": "ok",
1905
+ "data": {}
1906
+ }`
1907
+ })) : T(j.message || "解析失败");
1908
+ } catch (j) {
1909
+ T(String((j == null ? void 0 : j.message) || j));
1910
+ }
1911
+ }, H = async () => {
1912
+ if (!a.trim()) {
1913
+ b.warning("请先粘贴 curl 命令");
1914
+ return;
1915
+ }
1916
+ p(!0), d(null);
1917
+ try {
1918
+ const O = await q.curl.run(a);
1919
+ d(O);
1920
+ } catch (O) {
1921
+ d({ success: !1, error: String((O == null ? void 0 : O.message) || O) });
1922
+ } finally {
1923
+ p(!1);
1924
+ }
1925
+ }, h = async () => {
1926
+ if (!c) {
1927
+ b.warning("请先解析");
1928
+ return;
1929
+ }
1930
+ let O;
1931
+ try {
1932
+ O = await u.validateFields();
1933
+ } catch {
1934
+ return;
1935
+ }
1936
+ v(!0);
1937
+ try {
1938
+ const I = await q.curl.importAsCase({
1939
+ curl: a,
1940
+ caseName: O.caseName,
1941
+ caseGroup: O.caseGroup,
1942
+ envCode: O.envCode
1943
+ });
1944
+ I.success ? (b.success(`已导入测试用例: ${I.caseCode}`), n && n("case", I), L()) : b.error(I.message || "导入失败");
1945
+ } catch (I) {
1946
+ b.error(String((I == null ? void 0 : I.message) || I));
1947
+ } finally {
1948
+ v(!1);
1949
+ }
1950
+ }, o = async () => {
1951
+ if (!c) {
1952
+ b.warning("请先解析");
1953
+ return;
1954
+ }
1955
+ let O;
1956
+ try {
1957
+ O = await i.validateFields();
1958
+ } catch {
1959
+ return;
1960
+ }
1961
+ v(!0);
1962
+ try {
1963
+ const I = await q.curl.importAsEndpoint({
1964
+ curl: a,
1965
+ mockName: O.mockName,
1966
+ envCode: O.envCode,
1967
+ projectCode: O.projectCode,
1968
+ responseTemplate: O.responseTemplate
1969
+ });
1970
+ I.success ? (b.success(`已导入 Mock 端点: ${I.mockCode}`), n && n("endpoint", I), L()) : b.error(I.message || "导入失败");
1971
+ } catch (I) {
1972
+ b.error(String((I == null ? void 0 : I.message) || I));
1973
+ } finally {
1974
+ v(!1);
1975
+ }
1976
+ };
1977
+ return /* @__PURE__ */ r(
1978
+ me,
1979
+ {
1980
+ title: /* @__PURE__ */ r(P, { children: [
1981
+ /* @__PURE__ */ e(fe, {}),
1982
+ " 粘贴 curl 一键导入"
1983
+ ] }),
1984
+ open: t,
1985
+ onCancel: L,
1986
+ footer: null,
1987
+ size: "large",
1988
+ destroyOnHidden: !0,
1989
+ children: [
1990
+ /* @__PURE__ */ e(Sr, { type: "secondary", style: { marginBottom: 12 }, children: "从浏览器 DevTools / Postman / 终端复制 curl 命令,粘贴到下方即可解析、试跑、入库。" }),
1991
+ /* @__PURE__ */ e(
1992
+ rt,
1993
+ {
1994
+ value: a,
1995
+ onChange: (O) => y(O.target.value),
1996
+ placeholder: `curl -X POST 'https://api.example.com/v1/users/login' \\
1997
+ -H 'Content-Type: application/json' \\
1998
+ -H 'Authorization: Bearer xxx' \\
1999
+ -d '{"username":"alice","password":"123456"}'`,
2000
+ autoSize: { minRows: 4, maxRows: 10 },
2001
+ style: { fontFamily: "Menlo, Monaco, monospace", fontSize: 12 }
2002
+ }
2003
+ ),
2004
+ /* @__PURE__ */ r(P, { style: { marginTop: 12 }, children: [
2005
+ /* @__PURE__ */ e(_, { icon: /* @__PURE__ */ e(Ke, {}), onClick: J, type: "primary", ghost: !0, children: "解析" }),
2006
+ /* @__PURE__ */ e(_, { icon: /* @__PURE__ */ e(be, {}), onClick: H, loading: A, children: "直接执行(试跑)" })
2007
+ ] }),
2008
+ x && /* @__PURE__ */ e(V, { type: "error", showIcon: !0, style: { marginTop: 12 }, title: "解析失败", description: x }),
2009
+ c && /* @__PURE__ */ e(M, { size: "small", style: { marginTop: 16 }, title: "解析结果", children: /* @__PURE__ */ r(R, { column: 1, size: "small", bordered: !0, children: [
2010
+ /* @__PURE__ */ e(R.Item, { label: "Method", children: /* @__PURE__ */ e(w, { color: kr(c.method), children: c.method }) }),
2011
+ /* @__PURE__ */ e(R.Item, { label: "URL", children: /* @__PURE__ */ e(he, { code: !0, copyable: !0, children: c.url }) }),
2012
+ /* @__PURE__ */ e(R.Item, { label: "Path", children: /* @__PURE__ */ e(he, { code: !0, children: c.path }) }),
2013
+ c.query && /* @__PURE__ */ e(R.Item, { label: "Query", children: /* @__PURE__ */ e(he, { code: !0, children: c.query }) }),
2014
+ /* @__PURE__ */ e(R.Item, { label: "Headers", children: Object.keys(c.headers || {}).length === 0 ? /* @__PURE__ */ e(he, { type: "secondary", children: "(无)" }) : /* @__PURE__ */ e("div", { children: Object.entries(c.headers).map(([O, I]) => /* @__PURE__ */ r("div", { children: [
2015
+ /* @__PURE__ */ r(he, { strong: !0, children: [
2016
+ O,
2017
+ ":"
2018
+ ] }),
2019
+ " ",
2020
+ /* @__PURE__ */ e(he, { code: !0, children: I })
2021
+ ] }, O)) }) }),
2022
+ c.body && /* @__PURE__ */ e(R.Item, { label: "Body", children: /* @__PURE__ */ e("pre", { style: {
2023
+ background: "#f5f5f5",
2024
+ padding: 8,
2025
+ margin: 0,
2026
+ fontSize: 12,
2027
+ maxHeight: 200,
2028
+ overflow: "auto"
2029
+ }, children: c.body }) })
2030
+ ] }) }),
2031
+ l && /* @__PURE__ */ r(M, { size: "small", style: { marginTop: 16 }, title: /* @__PURE__ */ r(P, { children: [
2032
+ /* @__PURE__ */ e(be, {}),
2033
+ /* @__PURE__ */ e("span", { children: "试跑结果" }),
2034
+ l.success ? /* @__PURE__ */ r(w, { color: "green", children: [
2035
+ l.status,
2036
+ " · ",
2037
+ l.durationMs,
2038
+ "ms · ",
2039
+ l.bodySize,
2040
+ "B"
2041
+ ] }) : /* @__PURE__ */ e(w, { color: "red", children: "FAILED" })
2042
+ ] }), children: [
2043
+ l.error && /* @__PURE__ */ e(V, { type: "error", showIcon: !0, title: l.error }),
2044
+ l.body != null && /* @__PURE__ */ e("pre", { style: {
2045
+ background: "#f5f5f5",
2046
+ padding: 8,
2047
+ margin: 0,
2048
+ fontSize: 12,
2049
+ maxHeight: 240,
2050
+ overflow: "auto"
2051
+ }, children: l.body })
2052
+ ] }),
2053
+ c && /* @__PURE__ */ e(
2054
+ Ie,
2055
+ {
2056
+ activeKey: $,
2057
+ onChange: C,
2058
+ style: { marginTop: 16 },
2059
+ items: [
2060
+ {
2061
+ key: "import",
2062
+ label: /* @__PURE__ */ r("span", { children: [
2063
+ /* @__PURE__ */ e(De, {}),
2064
+ " 导入为测试用例"
2065
+ ] }),
2066
+ children: /* @__PURE__ */ r(E, { form: u, layout: "vertical", children: [
2067
+ /* @__PURE__ */ r(Y, { gutter: 16, children: [
2068
+ /* @__PURE__ */ e(z, { span: 12, children: /* @__PURE__ */ e(E.Item, { name: "caseName", label: "用例名称", rules: [{ required: !0 }], children: /* @__PURE__ */ e(B, {}) }) }),
2069
+ /* @__PURE__ */ e(z, { span: 6, children: /* @__PURE__ */ e(E.Item, { name: "caseGroup", label: "用例分组", children: /* @__PURE__ */ e(B, {}) }) }),
2070
+ /* @__PURE__ */ e(z, { span: 6, children: /* @__PURE__ */ e(E.Item, { name: "envCode", label: "环境", children: k.length > 0 ? /* @__PURE__ */ e(X, { options: k.map((O) => ({ value: O, label: O })) }) : /* @__PURE__ */ e(B, {}) }) })
2071
+ ] }),
2072
+ /* @__PURE__ */ e(
2073
+ _,
2074
+ {
2075
+ type: "primary",
2076
+ onClick: h,
2077
+ loading: g,
2078
+ icon: /* @__PURE__ */ e(De, {}),
2079
+ children: "保存为测试用例"
2080
+ }
2081
+ )
2082
+ ] })
2083
+ },
2084
+ {
2085
+ key: "mock",
2086
+ label: /* @__PURE__ */ r("span", { children: [
2087
+ /* @__PURE__ */ e(fe, {}),
2088
+ " 导入为 Mock 端点"
2089
+ ] }),
2090
+ children: /* @__PURE__ */ r(E, { form: i, layout: "vertical", children: [
2091
+ /* @__PURE__ */ r(Y, { gutter: 16, children: [
2092
+ /* @__PURE__ */ e(z, { span: 12, children: /* @__PURE__ */ e(E.Item, { name: "mockName", label: "Mock 名称", rules: [{ required: !0 }], children: /* @__PURE__ */ e(B, {}) }) }),
2093
+ /* @__PURE__ */ e(z, { span: 6, children: /* @__PURE__ */ e(E.Item, { name: "envCode", label: "环境", children: k.length > 0 ? /* @__PURE__ */ e(X, { options: k.map((O) => ({ value: O, label: O })) }) : /* @__PURE__ */ e(B, {}) }) }),
2094
+ /* @__PURE__ */ e(z, { span: 6, children: /* @__PURE__ */ e(E.Item, { name: "projectCode", label: "项目", children: /* @__PURE__ */ e(B, {}) }) })
2095
+ ] }),
2096
+ /* @__PURE__ */ e(E.Item, { name: "responseTemplate", label: "响应模板 (JSON)", children: /* @__PURE__ */ e(
2097
+ rt,
2098
+ {
2099
+ autoSize: { minRows: 3, maxRows: 8 },
2100
+ style: { fontFamily: "Menlo, Monaco, monospace" }
2101
+ }
2102
+ ) }),
2103
+ /* @__PURE__ */ e(
2104
+ _,
2105
+ {
2106
+ type: "primary",
2107
+ onClick: o,
2108
+ loading: g,
2109
+ icon: /* @__PURE__ */ e(fe, {}),
2110
+ children: "保存为 Mock 端点"
2111
+ }
2112
+ )
2113
+ ] })
2114
+ }
2115
+ ]
2116
+ }
2117
+ )
2118
+ ]
2119
+ }
2120
+ );
2121
+ }
2122
+ function kr(t) {
2123
+ return { GET: "blue", POST: "green", PUT: "orange", DELETE: "red", PATCH: "purple" }[t] || "default";
2124
+ }
2125
+ const { TextArea: nt } = B;
2126
+ function nn({ open: t, onClose: s, onSuccess: n, envOptions: k = [] }) {
2127
+ const [a, y] = m("paste"), [c, f] = m(""), [x, T] = m(null), [A, p] = m(null), [l, d] = m(!1), [g, v] = m([]), [$, C] = m(!1), [u] = E.useForm(), i = st(null), S = () => {
2128
+ f(""), T(null), p(null), v([]), u.resetFields();
2129
+ }, L = () => {
2130
+ S(), s();
2131
+ }, J = async () => {
2132
+ if (!c.trim()) {
2133
+ b.warning("请先粘贴或上传 API 规约");
2134
+ return;
2135
+ }
2136
+ p(null), d(!0);
2137
+ try {
2138
+ const I = await q.openapi.parse(c);
2139
+ I.success ? (T(I), v((I.endpoints || []).map((D, W) => W)), u.setFieldsValue({
2140
+ envCode: k[0] || "default",
2141
+ projectCode: "default",
2142
+ defaultResponse: `{
2143
+ "code": 0,
2144
+ "message": "ok",
2145
+ "data": {}
2146
+ }`,
2147
+ defaultStatus: 200,
2148
+ priority: 5,
2149
+ tagPrefix: "openapi-import"
2150
+ }), b.success(`识别为 ${I.format},共 ${I.count} 个端点`)) : p(I.message || "解析失败");
2151
+ } catch (I) {
2152
+ p(String((I == null ? void 0 : I.message) || I));
2153
+ } finally {
2154
+ d(!1);
2155
+ }
2156
+ }, H = async (I) => {
2157
+ try {
2158
+ const D = await q.openapi.sample(I);
2159
+ D.success && (f(D.content), b.success(`已加载 ${D.format} 示例`));
2160
+ } catch (D) {
2161
+ b.error("加载示例失败: " + D.message);
2162
+ }
2163
+ }, h = (I) => {
2164
+ const D = new FileReader();
2165
+ return D.onload = (W) => {
2166
+ var j;
2167
+ f(String(((j = W.target) == null ? void 0 : j.result) || "")), b.success(`已读取 ${I.name}(${(I.size / 1024).toFixed(1)}KB)`);
2168
+ }, D.onerror = () => b.error("文件读取失败"), D.readAsText(I), !1;
2169
+ }, o = async () => {
2170
+ if (!x) {
2171
+ b.warning("请先解析");
2172
+ return;
2173
+ }
2174
+ let I;
2175
+ try {
2176
+ I = await u.validateFields();
2177
+ } catch {
2178
+ return;
2179
+ }
2180
+ C(!0);
2181
+ try {
2182
+ const D = (x.endpoints || []).map((j, Ve) => ({
2183
+ method: j.method,
2184
+ path: j.path
2185
+ })).filter((j, Ve) => g.includes(Ve)), W = await q.openapi.importBatch({
2186
+ content: c,
2187
+ selected: D,
2188
+ envCode: I.envCode,
2189
+ projectCode: I.projectCode,
2190
+ defaultResponse: I.defaultResponse,
2191
+ defaultStatus: I.defaultStatus,
2192
+ priority: I.priority,
2193
+ tagPrefix: I.tagPrefix
2194
+ });
2195
+ W.success ? (b.success(`已导入 ${W.imported} 个 Mock 端点${W.failed > 0 ? `,失败 ${W.failed}` : ""}`), n && n(W), L()) : b.error(W.message || "导入失败");
2196
+ } catch (D) {
2197
+ b.error(String((D == null ? void 0 : D.message) || D));
2198
+ } finally {
2199
+ C(!1);
2200
+ }
2201
+ }, O = [
2202
+ {
2203
+ title: "Method",
2204
+ dataIndex: "method",
2205
+ width: 90,
2206
+ render: (I) => /* @__PURE__ */ e(w, { color: Cr(I), children: I })
2207
+ },
2208
+ { title: "Path", dataIndex: "path", width: 240, ellipsis: !0 },
2209
+ { title: "Summary", dataIndex: "summary", ellipsis: !0 },
2210
+ {
2211
+ title: "Tags",
2212
+ dataIndex: "tags",
2213
+ width: 160,
2214
+ render: (I) => (I || []).map((D) => /* @__PURE__ */ e(w, { children: D }, D))
2215
+ },
2216
+ {
2217
+ title: "Params",
2218
+ dataIndex: "parameters",
2219
+ width: 80,
2220
+ render: (I) => (I == null ? void 0 : I.length) || 0,
2221
+ align: "center"
2222
+ },
2223
+ {
2224
+ // `ApiSpecParser.ParsedEndpoint` 是 **POJO**(public 字段)⇒ 被全局 SNAKE_CASE 改名
2225
+ title: "示例",
2226
+ dataIndex: "response_example",
2227
+ width: 80,
2228
+ render: (I) => I ? /* @__PURE__ */ e(w, { color: "green", children: "有" }) : /* @__PURE__ */ e(w, { children: "无" })
2229
+ }
2230
+ ];
2231
+ return /* @__PURE__ */ r(
2232
+ me,
2233
+ {
2234
+ title: /* @__PURE__ */ r(P, { children: [
2235
+ /* @__PURE__ */ e(Xe, {}),
2236
+ " 批量导入 API 规约"
2237
+ ] }),
2238
+ open: t,
2239
+ onCancel: L,
2240
+ footer: null,
2241
+ size: "large",
2242
+ destroyOnHidden: !0,
2243
+ children: [
2244
+ /* @__PURE__ */ e(
2245
+ Ie,
2246
+ {
2247
+ activeKey: a,
2248
+ onChange: y,
2249
+ items: [
2250
+ {
2251
+ key: "paste",
2252
+ label: /* @__PURE__ */ r("span", { children: [
2253
+ /* @__PURE__ */ e(Ke, {}),
2254
+ " 粘贴 JSON"
2255
+ ] }),
2256
+ children: /* @__PURE__ */ r("div", { children: [
2257
+ /* @__PURE__ */ e(
2258
+ nt,
2259
+ {
2260
+ value: c,
2261
+ onChange: (I) => f(I.target.value),
2262
+ placeholder: "粘贴 OpenAPI 3.x / Swagger 2.0 / Postman v2.1 JSON 内容…",
2263
+ autoSize: { minRows: 6, maxRows: 16 },
2264
+ style: { fontFamily: "Menlo, Monaco, monospace", fontSize: 12 }
2265
+ }
2266
+ ),
2267
+ /* @__PURE__ */ r(P, { style: { marginTop: 8 }, children: [
2268
+ /* @__PURE__ */ e(_, { size: "small", onClick: () => H("openapi3"), children: "加载 OpenAPI 3 示例" }),
2269
+ /* @__PURE__ */ e(_, { size: "small", onClick: () => H("swagger2"), children: "加载 Swagger 2 示例" }),
2270
+ /* @__PURE__ */ e(_, { size: "small", onClick: () => H("postman"), children: "加载 Postman 示例" })
2271
+ ] })
2272
+ ] })
2273
+ },
2274
+ {
2275
+ key: "upload",
2276
+ label: /* @__PURE__ */ r("span", { children: [
2277
+ /* @__PURE__ */ e(Lt, {}),
2278
+ " 上传文件"
2279
+ ] }),
2280
+ children: /* @__PURE__ */ r(
2281
+ kt.Dragger,
2282
+ {
2283
+ ref: i,
2284
+ accept: ".json,.yaml,.yml,application/json,text/yaml",
2285
+ beforeUpload: h,
2286
+ showUploadList: !1,
2287
+ style: { padding: 24 },
2288
+ children: [
2289
+ /* @__PURE__ */ e("p", { className: "ant-upload-drag-icon", children: /* @__PURE__ */ e(Xe, { style: { fontSize: 48, color: "#1890ff" } }) }),
2290
+ /* @__PURE__ */ e("p", { className: "ant-upload-text", children: "点击或拖拽 JSON / YAML 文件到此处" }),
2291
+ /* @__PURE__ */ e("p", { className: "ant-upload-hint", children: "支持 OpenAPI 3.x / Swagger 2.0 / Postman v2.1" })
2292
+ ]
2293
+ }
2294
+ )
2295
+ }
2296
+ ]
2297
+ }
2298
+ ),
2299
+ /* @__PURE__ */ r(P, { style: { marginTop: 12 }, children: [
2300
+ /* @__PURE__ */ e(_, { type: "primary", icon: /* @__PURE__ */ e(be, {}), onClick: J, loading: l, children: "解析" }),
2301
+ x && /* @__PURE__ */ e(w, { color: "blue", children: x.format }),
2302
+ x && /* @__PURE__ */ r(w, { children: [
2303
+ "共 ",
2304
+ x.count,
2305
+ " 个端点,已选 ",
2306
+ g.length
2307
+ ] })
2308
+ ] }),
2309
+ A && /* @__PURE__ */ e(V, { type: "error", showIcon: !0, style: { marginTop: 12 }, title: "解析失败", description: A }),
2310
+ x && /* 端点预览 —— 走基座 ListTable(lead 008 §2 三件套):
2311
+ 标准分页 + 端侧过滤 + EmptyState。
2312
+ 原来那层 <Card size="small" title="预览(可勾选要导入的)"> 已去掉,
2313
+ 标题落到 ListTable 的 cardTitle,避免卡片套卡片。 */
2314
+ /* @__PURE__ */ e(
2315
+ ie,
2316
+ {
2317
+ cardTitle: "预览(可勾选要导入的)",
2318
+ rows: x.endpoints || [],
2319
+ columns: O,
2320
+ rowKey: (I, D) => D,
2321
+ rowSelection: {
2322
+ selectedRowKeys: g,
2323
+ onChange: v
2324
+ },
2325
+ searchKeys: ["method", "path", "summary"],
2326
+ searchPlaceholder: "按 Method / Path / Summary 过滤",
2327
+ emptyTitle: "没有可导入的端点",
2328
+ emptyDescription: "解析结果里没有端点,换一个 OpenAPI 文档试试。",
2329
+ scroll: { y: 280 },
2330
+ cardProps: { size: "small", style: { marginTop: 16 } }
2331
+ }
2332
+ ),
2333
+ x && /* @__PURE__ */ e(M, { size: "small", style: { marginTop: 16 }, title: "导入配置", children: /* @__PURE__ */ r(E, { form: u, layout: "vertical", children: [
2334
+ /* @__PURE__ */ r(Y, { gutter: 16, children: [
2335
+ /* @__PURE__ */ e(z, { span: 6, children: /* @__PURE__ */ e(E.Item, { name: "envCode", label: "环境", rules: [{ required: !0 }], children: k.length > 0 ? /* @__PURE__ */ e(X, { options: k.map((I) => ({ value: I, label: I })) }) : /* @__PURE__ */ e(B, {}) }) }),
2336
+ /* @__PURE__ */ e(z, { span: 6, children: /* @__PURE__ */ e(E.Item, { name: "projectCode", label: "项目", children: /* @__PURE__ */ e(B, {}) }) }),
2337
+ /* @__PURE__ */ e(z, { span: 4, children: /* @__PURE__ */ e(E.Item, { name: "defaultStatus", label: "默认状态码", children: /* @__PURE__ */ e(B, { type: "number" }) }) }),
2338
+ /* @__PURE__ */ e(z, { span: 4, children: /* @__PURE__ */ e(E.Item, { name: "priority", label: "优先级", children: /* @__PURE__ */ e(B, { type: "number" }) }) }),
2339
+ /* @__PURE__ */ e(z, { span: 4, children: /* @__PURE__ */ e(E.Item, { name: "tagPrefix", label: "Tag 前缀", children: /* @__PURE__ */ e(B, {}) }) })
2340
+ ] }),
2341
+ /* @__PURE__ */ e(E.Item, { name: "defaultResponse", label: "默认响应(无 example 时使用)", children: /* @__PURE__ */ e(
2342
+ nt,
2343
+ {
2344
+ autoSize: { minRows: 3, maxRows: 6 },
2345
+ style: { fontFamily: "Menlo, Monaco, monospace" }
2346
+ }
2347
+ ) }),
2348
+ /* @__PURE__ */ r(
2349
+ _,
2350
+ {
2351
+ type: "primary",
2352
+ size: "large",
2353
+ icon: /* @__PURE__ */ e(De, {}),
2354
+ onClick: o,
2355
+ loading: $,
2356
+ disabled: g.length === 0,
2357
+ children: [
2358
+ "批量导入 ",
2359
+ g.length,
2360
+ " 个端点"
2361
+ ]
2362
+ }
2363
+ )
2364
+ ] }) })
2365
+ ]
2366
+ }
2367
+ );
2368
+ }
2369
+ function Cr(t) {
2370
+ return { GET: "blue", POST: "green", PUT: "orange", DELETE: "red", PATCH: "purple" }[t] || "default";
2371
+ }
2372
+ const Tr = {
2373
+ STANDARD_JSON: { label: "标准 JSON", color: "blue" },
2374
+ RSS_XML: { label: "RSS 2.0", color: "orange" },
2375
+ ATOM_XML: { label: "Atom 1.0", color: "gold" },
2376
+ CUSTOM_SCRIPT: { label: "自定义脚本", color: "purple" },
2377
+ INTERNAL_BEAN: { label: "内部 Bean", color: "cyan" }
2378
+ }, vr = {
2379
+ PENDING_VERIFY: { color: "default", text: "待验证" },
2380
+ VERIFIED: { color: "green", text: "已验证" },
2381
+ INVALID_AUTH: { color: "red", text: "鉴权失败" },
2382
+ FATAL: { color: "red", text: "永久失败" },
2383
+ DISABLED: { color: "default", text: "已停用" }
2384
+ }, lt = {
2385
+ PENDING: { color: "default" },
2386
+ RUNNING: { color: "processing" },
2387
+ SUCCESS: { color: "green" },
2388
+ EMPTY: { color: "default" },
2389
+ FAILED: { color: "red" },
2390
+ FATAL: { color: "red" }
2391
+ };
2392
+ function _r() {
2393
+ const t = xe(), [s, n] = m([]), [k, a] = m(!1), [y, c] = m(null), [f, x] = m([]), [T, A] = m({}), [p, l] = m(null), [d, g] = m([]), v = async () => {
2394
+ a(!0);
2395
+ try {
2396
+ const h = await N.get("/subscribe/subscription/list");
2397
+ h && h.success !== !1 && n(Array.isArray(h.data) ? h.data : Array.isArray(h) ? h : []);
2398
+ } catch (h) {
2399
+ b.error("获取订阅列表失败: " + ((h == null ? void 0 : h.message) || ""));
2400
+ } finally {
2401
+ a(!1);
2402
+ }
2403
+ };
2404
+ U(() => {
2405
+ v();
2406
+ }, []);
2407
+ const $ = (h) => {
2408
+ me.confirm({
2409
+ title: "确认删除",
2410
+ icon: /* @__PURE__ */ e(Bt, {}),
2411
+ content: `确定要删除订阅 "${h.name}" 吗? 运行历史会保留.`,
2412
+ onOk: async () => {
2413
+ try {
2414
+ const o = await N.delete(`/subscribe/subscription/${h.id}`);
2415
+ o && o.success !== !1 ? (b.success("删除成功"), v()) : b.error((o == null ? void 0 : o.message) || "删除失败");
2416
+ } catch (o) {
2417
+ b.error("删除失败: " + ((o == null ? void 0 : o.message) || ""));
2418
+ }
2419
+ }
2420
+ });
2421
+ }, C = async (h) => {
2422
+ try {
2423
+ const o = await N.post(`/subscribe/subscription/${h}/enable`);
2424
+ o && o.success !== !1 ? (b.success("已启用"), v()) : b.error((o == null ? void 0 : o.message) || "启用失败");
2425
+ } catch (o) {
2426
+ b.error("启用失败: " + ((o == null ? void 0 : o.message) || ""));
2427
+ }
2428
+ }, u = async (h) => {
2429
+ try {
2430
+ const o = await N.post(`/subscribe/subscription/${h}/disable`);
2431
+ o && o.success !== !1 ? (b.success("已停用"), v()) : b.error((o == null ? void 0 : o.message) || "停用失败");
2432
+ } catch (o) {
2433
+ b.error("停用失败: " + ((o == null ? void 0 : o.message) || ""));
2434
+ }
2435
+ }, i = async (h) => {
2436
+ me.confirm({
2437
+ title: "手动触发",
2438
+ content: `将立即执行一次 "${h.name}" 的抽取, 同步返回 runId.`,
2439
+ onOk: async () => {
2440
+ try {
2441
+ const o = await N.post(`/subscribe/subscription/${h.id}/trigger?triggerBy=ceo`);
2442
+ if (o && (o.data !== void 0 || o.success !== !1)) {
2443
+ const O = o.data ?? o;
2444
+ b.success(`已触发, runId = ${O}`), L(h);
2445
+ } else
2446
+ b.error((o == null ? void 0 : o.message) || "触发失败");
2447
+ } catch (o) {
2448
+ b.error("触发失败: " + ((o == null ? void 0 : o.message) || ""));
2449
+ }
2450
+ }
2451
+ });
2452
+ }, S = async (h) => {
2453
+ try {
2454
+ const o = await N.post(`/subscribe/subscription/${h.id}/dry-run`);
2455
+ c({ sub: h, result: (o == null ? void 0 : o.data) ?? o });
2456
+ } catch (o) {
2457
+ c({ sub: h, result: { success: !1, errorMessage: (o == null ? void 0 : o.message) || "请求失败" } });
2458
+ }
2459
+ }, L = async (h) => {
2460
+ try {
2461
+ const o = await N.get(`/subscribe/run/list?subscriptionId=${h.id}&limit=20`), O = (o == null ? void 0 : o.data) ?? o ?? [];
2462
+ x(Array.isArray(O) ? O : []), l(null), A({}), g([]), c({ sub: h, tab: "runs" });
2463
+ } catch {
2464
+ b.error("获取运行历史失败");
2465
+ }
2466
+ }, J = async (h) => {
2467
+ if (T[h]) {
2468
+ l(h);
2469
+ return;
2470
+ }
2471
+ try {
2472
+ const o = await N.get(`/subscribe/run/${h}/items?limit=200`), O = (o == null ? void 0 : o.data) ?? o ?? [];
2473
+ A((I) => ({ ...I, [h]: Array.isArray(O) ? O : [] })), l(h);
2474
+ } catch {
2475
+ b.error("获取抽取项失败");
2476
+ }
2477
+ };
2478
+ return /* @__PURE__ */ r("div", { children: [
2479
+ /* @__PURE__ */ e(
2480
+ ye,
2481
+ {
2482
+ title: "订阅中心 - 数据源订阅",
2483
+ subtitle: "负责把三方 / 内部 / RSS 等数据源按 Cron 定时抽取, 归一化后落到本地"
2484
+ }
2485
+ ),
2486
+ /* @__PURE__ */ e(
2487
+ V,
2488
+ {
2489
+ type: "info",
2490
+ showIcon: !0,
2491
+ style: { marginBottom: 16 },
2492
+ message: "订阅中心负责把三方 / 内部 / RSS 等数据源按 Cron 定时抽取, 归一化后落到本地, 供 CEO 立项和 Agent 协作使用."
2493
+ }
2494
+ ),
2495
+ /* @__PURE__ */ e(
2496
+ ie,
2497
+ {
2498
+ rows: s,
2499
+ columns: [
2500
+ {
2501
+ title: "ID",
2502
+ dataIndex: "id",
2503
+ width: 70
2504
+ },
2505
+ {
2506
+ title: "名称",
2507
+ dataIndex: "name",
2508
+ render: (h, o) => /* @__PURE__ */ r(P, { orientation: "vertical", size: 0, children: [
2509
+ /* @__PURE__ */ e("span", { style: { fontWeight: 500 }, children: h }),
2510
+ o.description && /* @__PURE__ */ e("span", { style: { color: "#999", fontSize: 12 }, children: o.description })
2511
+ ] })
2512
+ },
2513
+ {
2514
+ title: "数据源",
2515
+ dataIndex: "sourceType",
2516
+ width: 90,
2517
+ render: (h) => /* @__PURE__ */ e(w, { children: h })
2518
+ },
2519
+ {
2520
+ title: "抽取器",
2521
+ dataIndex: "extractorType",
2522
+ width: 140,
2523
+ render: (h) => {
2524
+ const o = Tr[h] || { label: h, color: "default" };
2525
+ return /* @__PURE__ */ e(w, { color: o.color, children: o.label });
2526
+ }
2527
+ },
2528
+ {
2529
+ title: "Cron",
2530
+ dataIndex: "cronExpr",
2531
+ width: 150,
2532
+ render: (h) => /* @__PURE__ */ e("code", { style: { fontSize: 12 }, children: h })
2533
+ },
2534
+ {
2535
+ title: "状态",
2536
+ dataIndex: "status",
2537
+ width: 110,
2538
+ render: (h) => {
2539
+ const o = vr[h] || { color: "default", text: h };
2540
+ return /* @__PURE__ */ e(w, { color: o.color, children: o.text });
2541
+ }
2542
+ },
2543
+ {
2544
+ title: "启用",
2545
+ dataIndex: "enabled",
2546
+ width: 80,
2547
+ render: (h, o) => h ? /* @__PURE__ */ e(w, { color: "green", children: "是" }) : /* @__PURE__ */ e(w, { children: "否" })
2548
+ },
2549
+ {
2550
+ title: "最近 run",
2551
+ dataIndex: "lastStatus",
2552
+ width: 110,
2553
+ render: (h, o) => {
2554
+ var O;
2555
+ return h ? /* @__PURE__ */ e(pe, { title: o.lastError || "", children: /* @__PURE__ */ e(w, { color: ((O = lt[h]) == null ? void 0 : O.color) || "default", children: h }) }) : /* @__PURE__ */ e("span", { style: { color: "#ccc" }, children: "-" });
2556
+ }
2557
+ },
2558
+ {
2559
+ title: "累计",
2560
+ width: 130,
2561
+ render: (h, o) => /* @__PURE__ */ r(P, { size: 4, children: [
2562
+ /* @__PURE__ */ r(w, { color: "green", children: [
2563
+ "✓ ",
2564
+ o.successCountTotal || 0
2565
+ ] }),
2566
+ /* @__PURE__ */ r(w, { color: "red", children: [
2567
+ "✗ ",
2568
+ o.failCountTotal || 0
2569
+ ] })
2570
+ ] })
2571
+ },
2572
+ {
2573
+ title: "操作",
2574
+ width: 280,
2575
+ fixed: "right",
2576
+ render: (h, o) => /* @__PURE__ */ r(P, { size: 4, wrap: !0, children: [
2577
+ /* @__PURE__ */ e(
2578
+ _,
2579
+ {
2580
+ type: "link",
2581
+ size: "small",
2582
+ icon: /* @__PURE__ */ e($t, {}),
2583
+ onClick: () => t(`/subscribe/edit/${o.id}`),
2584
+ children: "编辑"
2585
+ }
2586
+ ),
2587
+ /* @__PURE__ */ e(
2588
+ _,
2589
+ {
2590
+ type: "link",
2591
+ size: "small",
2592
+ icon: /* @__PURE__ */ e(be, {}),
2593
+ onClick: () => S(o),
2594
+ children: "试运行"
2595
+ }
2596
+ ),
2597
+ /* @__PURE__ */ e(
2598
+ _,
2599
+ {
2600
+ type: "link",
2601
+ size: "small",
2602
+ icon: /* @__PURE__ */ e(Pe, {}),
2603
+ onClick: () => i(o),
2604
+ children: "触发"
2605
+ }
2606
+ ),
2607
+ /* @__PURE__ */ e(
2608
+ _,
2609
+ {
2610
+ type: "link",
2611
+ size: "small",
2612
+ onClick: () => L(o),
2613
+ children: "历史"
2614
+ }
2615
+ ),
2616
+ o.enabled ? /* @__PURE__ */ e(
2617
+ _,
2618
+ {
2619
+ type: "link",
2620
+ size: "small",
2621
+ icon: /* @__PURE__ */ e(Nt, {}),
2622
+ onClick: () => u(o.id),
2623
+ children: "停用"
2624
+ }
2625
+ ) : /* @__PURE__ */ e(
2626
+ _,
2627
+ {
2628
+ type: "link",
2629
+ size: "small",
2630
+ icon: /* @__PURE__ */ e(Ue, {}),
2631
+ onClick: () => C(o.id),
2632
+ children: "启用"
2633
+ }
2634
+ ),
2635
+ /* @__PURE__ */ e(je, { title: "确认删除?", onConfirm: () => $(o), okText: "删除", cancelText: "取消", children: /* @__PURE__ */ e(_, { type: "link", size: "small", danger: !0, icon: /* @__PURE__ */ e(Dt, {}), children: "删除" }) })
2636
+ ] })
2637
+ }
2638
+ ],
2639
+ rowKey: "id",
2640
+ loading: k,
2641
+ scroll: { x: 1400 },
2642
+ tableProps: { size: "middle" },
2643
+ searchKeys: ["name", "id", "sourceType"],
2644
+ searchPlaceholder: "按订阅名称 / ID / 数据源类型过滤",
2645
+ emptyTitle: "暂无订阅",
2646
+ emptyDescription: "订阅负责把三方数据源按 Cron 定时抽取归一化,先建一个订阅试试。",
2647
+ cardExtra: /* @__PURE__ */ r(P, { children: [
2648
+ /* @__PURE__ */ e(_, { icon: /* @__PURE__ */ e(ee, {}), onClick: v, children: "刷新" }),
2649
+ /* @__PURE__ */ e(
2650
+ _,
2651
+ {
2652
+ type: "primary",
2653
+ icon: /* @__PURE__ */ e(yt, {}),
2654
+ onClick: () => t("/subscribe/new"),
2655
+ children: "新建订阅"
2656
+ }
2657
+ )
2658
+ ] })
2659
+ }
2660
+ ),
2661
+ /* @__PURE__ */ e(
2662
+ we,
2663
+ {
2664
+ title: y != null && y.sub ? `试运行 - ${y.sub.name}` : "运行历史",
2665
+ open: !!y,
2666
+ onClose: () => c(null),
2667
+ size: "large",
2668
+ children: (y == null ? void 0 : y.tab) === "runs" ? /* @__PURE__ */ e(
2669
+ Ie,
2670
+ {
2671
+ activeKey: p ? "items" : "list",
2672
+ onChange: (h) => h === "list" && l(null),
2673
+ items: [
2674
+ {
2675
+ key: "list",
2676
+ label: `运行列表 (${f.length})`,
2677
+ children: (
2678
+ /* 运行列表 —— 走基座 ListTable(lead 008 §2 三件套)。
2679
+ 原来 pagination={false}(不分页),改用基座标准分页:
2680
+ 行数由订阅的运行次数决定,会增长,不适合按「≤10 且不变」豁免。
2681
+ Drawer 里没有外层卡片,故用 borderless 让它与抽屉融成一块。 */
2682
+ /* @__PURE__ */ e(
2683
+ ie,
2684
+ {
2685
+ rows: f,
2686
+ rowKey: "id",
2687
+ searchKeys: ["id", "status"],
2688
+ searchPlaceholder: "按 run ID / 状态过滤",
2689
+ emptyTitle: "暂无运行记录",
2690
+ emptyDescription: "该订阅还没有运行过。",
2691
+ cardProps: { variant: "borderless", styles: { body: { padding: 0 } } },
2692
+ onRow: (h) => ({ onClick: () => J(h.id) }),
2693
+ columns: [
2694
+ { title: "runId", dataIndex: "id", width: 70 },
2695
+ {
2696
+ title: "计划",
2697
+ dataIndex: "scheduledAt",
2698
+ width: 160,
2699
+ render: (h) => h ? new Date(h).toLocaleString() : "-"
2700
+ },
2701
+ { title: "耗时(ms)", dataIndex: "durationMs", width: 90 },
2702
+ {
2703
+ title: "状态",
2704
+ dataIndex: "status",
2705
+ width: 90,
2706
+ render: (h) => {
2707
+ var o;
2708
+ return /* @__PURE__ */ e(w, { color: (o = lt[h]) == null ? void 0 : o.color, children: h });
2709
+ }
2710
+ },
2711
+ {
2712
+ title: "拉取/成功/重复/死信",
2713
+ width: 200,
2714
+ render: (h, o) => `${o.fetchedCount} / ${o.successCount} / ${o.duplicateCount || 0} / ${o.deadLetterCount}`
2715
+ },
2716
+ {
2717
+ title: "错误",
2718
+ dataIndex: "errorMessage",
2719
+ render: (h) => h ? /* @__PURE__ */ e("span", { style: { color: "#cf1322", fontSize: 12 }, children: h }) : "-"
2720
+ }
2721
+ ]
2722
+ }
2723
+ )
2724
+ )
2725
+ },
2726
+ {
2727
+ key: "items",
2728
+ label: p ? `run#${p} 抽取项` : "抽取项",
2729
+ disabled: !p,
2730
+ children: /* @__PURE__ */ r(P, { orientation: "vertical", style: { width: "100%" }, children: [
2731
+ /* @__PURE__ */ r(P, { children: [
2732
+ /* @__PURE__ */ r(w, { color: "blue", children: [
2733
+ "已选 ",
2734
+ d.length,
2735
+ " 条"
2736
+ ] }),
2737
+ /* @__PURE__ */ r(
2738
+ _,
2739
+ {
2740
+ size: "small",
2741
+ type: "primary",
2742
+ icon: /* @__PURE__ */ e(Ee, {}),
2743
+ disabled: d.length === 0,
2744
+ onClick: () => {
2745
+ const h = d.join(",");
2746
+ t(`/project/new?subscriptionId=${y.sub.id}&itemIds=${h}`);
2747
+ },
2748
+ children: [
2749
+ "用所选 ",
2750
+ d.length,
2751
+ " 条立项"
2752
+ ]
2753
+ }
2754
+ )
2755
+ ] }),
2756
+ /* @__PURE__ */ e(
2757
+ ie,
2758
+ {
2759
+ rows: T[p] || [],
2760
+ rowKey: "id",
2761
+ rowSelection: {
2762
+ selectedRowKeys: d,
2763
+ onChange: g
2764
+ },
2765
+ searchKeys: ["dedupKey", "status"],
2766
+ searchPlaceholder: "按 dedupKey / 状态过滤",
2767
+ emptyTitle: "暂无抽取项",
2768
+ emptyDescription: "这次运行没有产生抽取项。",
2769
+ cardProps: { variant: "borderless", styles: { body: { padding: 0 } } },
2770
+ columns: [
2771
+ { title: "id", dataIndex: "dedupKey", width: 180, ellipsis: !0 },
2772
+ {
2773
+ title: "title",
2774
+ dataIndex: "normalized",
2775
+ render: (h) => {
2776
+ try {
2777
+ return JSON.parse(h).title || "(无标题)";
2778
+ } catch {
2779
+ return h;
2780
+ }
2781
+ }
2782
+ },
2783
+ {
2784
+ title: "link",
2785
+ dataIndex: "normalized",
2786
+ render: (h) => {
2787
+ try {
2788
+ const o = JSON.parse(h);
2789
+ return o.link ? /* @__PURE__ */ e("a", { href: o.link, target: "_blank", children: "↗" }) : "-";
2790
+ } catch {
2791
+ return "-";
2792
+ }
2793
+ }
2794
+ },
2795
+ {
2796
+ title: "状态",
2797
+ dataIndex: "status",
2798
+ width: 110,
2799
+ render: (h) => /* @__PURE__ */ e(w, { children: h })
2800
+ }
2801
+ ]
2802
+ }
2803
+ )
2804
+ ] })
2805
+ }
2806
+ ]
2807
+ }
2808
+ ) : /* @__PURE__ */ e(Ar, { result: y == null ? void 0 : y.result })
2809
+ }
2810
+ )
2811
+ ] });
2812
+ }
2813
+ function Ar({ result: t }) {
2814
+ return t ? t.success ? /* @__PURE__ */ r(P, { orientation: "vertical", style: { width: "100%" }, size: "middle", children: [
2815
+ /* @__PURE__ */ e(M, { size: "small", title: "调用结果", children: /* @__PURE__ */ r(P, { size: "large", wrap: !0, children: [
2816
+ /* @__PURE__ */ r("span", { children: [
2817
+ /* @__PURE__ */ e("b", { children: "HTTP:" }),
2818
+ " ",
2819
+ t.httpStatus || "-"
2820
+ ] }),
2821
+ /* @__PURE__ */ r("span", { children: [
2822
+ /* @__PURE__ */ e("b", { children: "耗时:" }),
2823
+ " ",
2824
+ t.latencyMs,
2825
+ "ms"
2826
+ ] }),
2827
+ /* @__PURE__ */ r("span", { children: [
2828
+ /* @__PURE__ */ e("b", { children: "大小:" }),
2829
+ " ",
2830
+ t.responseSize,
2831
+ "B"
2832
+ ] }),
2833
+ /* @__PURE__ */ r("span", { children: [
2834
+ /* @__PURE__ */ e("b", { children: "样本:" }),
2835
+ " ",
2836
+ t.sampleCount,
2837
+ " 条"
2838
+ ] })
2839
+ ] }) }),
2840
+ t.firstItem && /* @__PURE__ */ e(M, { size: "small", title: "第一条样本 (归一化后)", children: /* @__PURE__ */ e(
2841
+ "pre",
2842
+ {
2843
+ style: { background: "#f5f5f5", padding: 12, borderRadius: 4, maxHeight: 300, overflow: "auto" },
2844
+ children: JSON.stringify(t.firstItem, null, 2)
2845
+ }
2846
+ ) }),
2847
+ t.responsePreview && /* @__PURE__ */ e(M, { size: "small", title: "响应预览 (前 4KB)", children: /* @__PURE__ */ e("pre", { style: {
2848
+ background: "#f5f5f5",
2849
+ padding: 12,
2850
+ borderRadius: 4,
2851
+ maxHeight: 300,
2852
+ overflow: "auto",
2853
+ fontSize: 12
2854
+ }, children: t.responsePreview }) }),
2855
+ t.fieldErrors && t.fieldErrors.length > 0 && /* @__PURE__ */ e(V, { type: "warning", showIcon: !0, message: "字段问题", description: /* @__PURE__ */ e("ul", { children: t.fieldErrors.map((s, n) => /* @__PURE__ */ e("li", { children: s }, n)) }) })
2856
+ ] }) : /* @__PURE__ */ e(V, { type: "error", showIcon: !0, title: "试运行失败", description: t.errorMessage || "未知错误" }) : null;
2857
+ }
2858
+ const Er = [
2859
+ { value: "STANDARD_JSON", label: "标准 JSON (按统一契约返回的 JSON)" },
2860
+ { value: "RSS_XML", label: "RSS 2.0 (XML feed)" },
2861
+ { value: "ATOM_XML", label: "Atom 1.0 (XML feed)" },
2862
+ { value: "CUSTOM_SCRIPT", label: "自定义脚本 (z-script 平台)" },
2863
+ { value: "INTERNAL_BEAN", label: "内部 Bean (我们自己的模块, 暂未启用)" }
2864
+ ], Pr = [
2865
+ { value: "NONE", label: "无鉴权" },
2866
+ { value: "BEARER", label: "Bearer (Authorization: Bearer xxx)" },
2867
+ { value: "API_KEY", label: "API Key (Authorization: xxx)" },
2868
+ { value: "BASIC", label: "Basic (user:password base64)" }
2869
+ ], Rr = [
2870
+ { label: "每 5 分钟", value: "0 */5 * * * ?" },
2871
+ { label: "每 15 分钟", value: "0 */15 * * * ?" },
2872
+ { label: "每小时", value: "0 0 * * * ?" },
2873
+ { label: "每 6 小时", value: "0 0 */6 * * ?" },
2874
+ { label: "每天 8 点", value: "0 0 8 * * ?" }
2875
+ ];
2876
+ function at() {
2877
+ const { id: t } = ot(), s = xe(), n = !!t, [k] = E.useForm(), [a, y] = m(!1), [c, f] = m(!1), [x, T] = m([]), [A, p] = m([]), l = E.useWatch("sourceType", k), d = E.useWatch("extractorType", k), g = E.useWatch("authType", k);
2878
+ U(() => {
2879
+ v(), $(), n && C();
2880
+ }, [t]);
2881
+ const v = async () => {
2882
+ try {
2883
+ const i = await N.get("/secret/list"), S = (i == null ? void 0 : i.data) ?? i ?? [];
2884
+ T(Array.isArray(S) ? S : []);
2885
+ } catch {
2886
+ }
2887
+ }, $ = async () => {
2888
+ try {
2889
+ const i = await N.get("/script/list"), S = (i == null ? void 0 : i.data) ?? i ?? [];
2890
+ p(Array.isArray(S) ? S.filter((L) => L.status === 1) : []);
2891
+ } catch {
2892
+ }
2893
+ }, C = async () => {
2894
+ y(!0);
2895
+ try {
2896
+ const i = await N.get(`/subscribe/subscription/${t}`), S = (i == null ? void 0 : i.data) ?? i;
2897
+ S && k.setFieldsValue({
2898
+ ...S,
2899
+ enabled: S.enabled === 1 || S.enabled === !0
2900
+ });
2901
+ } catch (i) {
2902
+ b.error("加载订阅失败: " + ((i == null ? void 0 : i.message) || ""));
2903
+ } finally {
2904
+ y(!1);
2905
+ }
2906
+ }, u = async () => {
2907
+ try {
2908
+ const i = await k.validateFields();
2909
+ f(!0);
2910
+ const S = {
2911
+ ...i,
2912
+ enabled: i.enabled ? 1 : 0
2913
+ };
2914
+ let L;
2915
+ if (n ? L = await N.put("/subscribe/subscription", S) : L = await N.post("/subscribe/subscription", S), L && L.success === !1) {
2916
+ b.error(L.message || "保存失败");
2917
+ return;
2918
+ }
2919
+ b.success(n ? "已更新 (注意: 修改 cron / url / 抽取器后会自动重置为 PENDING_VERIFY)" : "已创建, 已自动验证"), s("/subscribe/list");
2920
+ } catch (i) {
2921
+ i != null && i.errorFields ? b.warning("请检查表单") : b.error("保存失败: " + ((i == null ? void 0 : i.message) || ""));
2922
+ } finally {
2923
+ f(!1);
2924
+ }
2925
+ };
2926
+ return /* @__PURE__ */ r("div", { style: { padding: 24 }, children: [
2927
+ /* @__PURE__ */ e(
2928
+ ye,
2929
+ {
2930
+ title: n ? `编辑订阅 #${t}` : "新建订阅",
2931
+ subtitle: "配置数据源、抽取器、鉴权与调度策略",
2932
+ back: !0,
2933
+ extra: /* @__PURE__ */ r(P, { children: [
2934
+ /* @__PURE__ */ e(_, { onClick: () => s("/subscribe/list"), children: "取消" }),
2935
+ /* @__PURE__ */ e(_, { type: "primary", icon: /* @__PURE__ */ e(gt, {}), loading: c, onClick: u, children: "保存 (自动验证)" })
2936
+ ] })
2937
+ }
2938
+ ),
2939
+ /* @__PURE__ */ e(M, { children: /* @__PURE__ */ e(Ae, { spinning: a, children: /* @__PURE__ */ r(
2940
+ E,
2941
+ {
2942
+ form: k,
2943
+ layout: "vertical",
2944
+ initialValues: {
2945
+ sourceType: "HTTP",
2946
+ httpMethod: "GET",
2947
+ authType: "NONE",
2948
+ extractorType: "STANDARD_JSON",
2949
+ enabled: !0,
2950
+ minIntervalSec: 60,
2951
+ maxItemsPerRun: 1e3,
2952
+ timeoutMs: 15e3
2953
+ },
2954
+ children: [
2955
+ /* @__PURE__ */ r(M, { type: "inner", title: "基本信息", style: { marginBottom: 16 }, children: [
2956
+ /* @__PURE__ */ e(E.Item, { label: "名称", name: "name", rules: [{ required: !0, message: "请输入名称" }], children: /* @__PURE__ */ e(B, { placeholder: "例如: GitHub PR 通知" }) }),
2957
+ /* @__PURE__ */ e(E.Item, { label: "说明", name: "description", children: /* @__PURE__ */ e(B.TextArea, { rows: 2, placeholder: "(可选)" }) })
2958
+ ] }),
2959
+ /* @__PURE__ */ r(M, { type: "inner", title: "数据源", style: { marginBottom: 16 }, children: [
2960
+ /* @__PURE__ */ e(E.Item, { label: "数据源形态", name: "sourceType", rules: [{ required: !0 }], children: /* @__PURE__ */ r(re.Group, { children: [
2961
+ /* @__PURE__ */ e(re.Button, { value: "HTTP", children: "HTTP / HTTPS" }),
2962
+ /* @__PURE__ */ e(re.Button, { value: "INTERNAL", disabled: !0, children: "内部 Bean" })
2963
+ ] }) }),
2964
+ l === "HTTP" && /* @__PURE__ */ r(Le, { children: [
2965
+ /* @__PURE__ */ e(
2966
+ E.Item,
2967
+ {
2968
+ label: "目标 URL",
2969
+ name: "targetUrl",
2970
+ rules: [{ required: !0, message: "请输入 URL" }],
2971
+ children: /* @__PURE__ */ e(B, { placeholder: "https://api.github.com/repos/.../pulls?state=open" })
2972
+ }
2973
+ ),
2974
+ /* @__PURE__ */ r(P, { size: "large", style: { width: "100%" }, children: [
2975
+ /* @__PURE__ */ e(E.Item, { label: "HTTP 方法", name: "httpMethod", children: /* @__PURE__ */ e(X, { style: { width: 120 }, options: [
2976
+ { value: "GET", label: "GET" },
2977
+ { value: "POST", label: "POST" },
2978
+ { value: "PUT", label: "PUT" }
2979
+ ] }) }),
2980
+ /* @__PURE__ */ e(E.Item, { label: "超时 (ms)", name: "timeoutMs", children: /* @__PURE__ */ e(Oe, { min: 1e3, max: 12e4, step: 1e3 }) })
2981
+ ] }),
2982
+ /* @__PURE__ */ e(E.Item, { label: "自定义 HTTP 头 (JSON)", name: "httpHeaders", children: /* @__PURE__ */ e(B.TextArea, { rows: 2, placeholder: '{"X-Trace-Id":"abc"}' }) }),
2983
+ /* @__PURE__ */ e(E.Item, { label: "请求体 (POST/PUT)", name: "requestBody", children: /* @__PURE__ */ e(B.TextArea, { rows: 3, placeholder: "(可选)" }) })
2984
+ ] })
2985
+ ] }),
2986
+ /* @__PURE__ */ r(M, { type: "inner", title: "鉴权 (从 z-mist 拉取 secret)", style: { marginBottom: 16 }, children: [
2987
+ /* @__PURE__ */ e(E.Item, { label: "鉴权方式", name: "authType", children: /* @__PURE__ */ e(X, { options: Pr }) }),
2988
+ g && g !== "NONE" && /* @__PURE__ */ e(
2989
+ E.Item,
2990
+ {
2991
+ label: "z-mist 凭据引用",
2992
+ name: "authSecretKey",
2993
+ extra: "从密钥中心 (z-mist) 选一个 secret; secret 的解密值会作为 secret 注入",
2994
+ children: /* @__PURE__ */ e(
2995
+ X,
2996
+ {
2997
+ showSearch: !0,
2998
+ allowClear: !0,
2999
+ placeholder: "选择 secret (key)",
3000
+ options: x.map((i) => ({
3001
+ value: i.secretKey,
3002
+ label: `${i.secretKey}${i.secretName ? " (" + i.secretName + ")" : ""}`
3003
+ }))
3004
+ }
3005
+ )
3006
+ }
3007
+ )
3008
+ ] }),
3009
+ /* @__PURE__ */ r(M, { type: "inner", title: "抽取器", style: { marginBottom: 16 }, children: [
3010
+ /* @__PURE__ */ e(
3011
+ E.Item,
3012
+ {
3013
+ label: "抽取器类型",
3014
+ name: "extractorType",
3015
+ rules: [{ required: !0 }],
3016
+ extra: "STANDARD_JSON/RSS_XML/ATOM_XML 直接解析; CUSTOM_SCRIPT 调 z-script 平台",
3017
+ children: /* @__PURE__ */ e(X, { options: Er })
3018
+ }
3019
+ ),
3020
+ d === "CUSTOM_SCRIPT" && /* @__PURE__ */ e(
3021
+ E.Item,
3022
+ {
3023
+ label: "z-script 脚本",
3024
+ name: "extractorScriptCode",
3025
+ rules: [{ required: !0, message: "请选择脚本" }],
3026
+ extra: "在 智能中心 > 脚本中心 维护脚本. 脚本返回 { items: [...], nextCursor: '...' }",
3027
+ children: /* @__PURE__ */ e(
3028
+ X,
3029
+ {
3030
+ showSearch: !0,
3031
+ placeholder: "选择已启用的脚本",
3032
+ options: A.map((i) => ({
3033
+ value: i.scriptCode,
3034
+ label: `${i.scriptCode} (${i.dslType})${i.scriptName ? " - " + i.scriptName : ""}`
3035
+ }))
3036
+ }
3037
+ )
3038
+ }
3039
+ )
3040
+ ] }),
3041
+ /* @__PURE__ */ r(M, { type: "inner", title: "调度", style: { marginBottom: 16 }, children: [
3042
+ /* @__PURE__ */ e(
3043
+ E.Item,
3044
+ {
3045
+ label: "Cron 表达式",
3046
+ name: "cronExpr",
3047
+ rules: [{ required: !0, message: "请输入 Cron" }],
3048
+ extra: "Quartz 兼容, 例如 0 */5 * * * ? = 每 5 分钟",
3049
+ children: /* @__PURE__ */ e(B, { addonAfter: /* @__PURE__ */ e(
3050
+ X,
3051
+ {
3052
+ style: { width: 140 },
3053
+ placeholder: "常用",
3054
+ options: Rr,
3055
+ onChange: (i) => k.setFieldValue("cronExpr", i),
3056
+ value: null
3057
+ }
3058
+ ) })
3059
+ }
3060
+ ),
3061
+ /* @__PURE__ */ r(P, { size: "large", children: [
3062
+ /* @__PURE__ */ e(E.Item, { label: "启用", name: "enabled", valuePropName: "checked", children: /* @__PURE__ */ r(re.Group, { children: [
3063
+ /* @__PURE__ */ e(re.Button, { value: !0, children: "启用" }),
3064
+ /* @__PURE__ */ e(re.Button, { value: !1, children: "停用" })
3065
+ ] }) }),
3066
+ /* @__PURE__ */ e(
3067
+ E.Item,
3068
+ {
3069
+ label: "最小间隔 (秒)",
3070
+ name: "minIntervalSec",
3071
+ extra: "距上次 run 至少 N 秒",
3072
+ children: /* @__PURE__ */ e(Oe, { min: 0, max: 3600 })
3073
+ }
3074
+ ),
3075
+ /* @__PURE__ */ e(E.Item, { label: "单次最多条数", name: "maxItemsPerRun", children: /* @__PURE__ */ e(Oe, { min: 1, max: 1e4 }) })
3076
+ ] })
3077
+ ] }),
3078
+ /* @__PURE__ */ e(
3079
+ V,
3080
+ {
3081
+ type: "success",
3082
+ showIcon: !0,
3083
+ title: "保存后会自动 dry-run: 真实 HTTP 一次, 把响应喂给抽取器, 失败时订阅进入 INVALID_AUTH 状态, 不会自动调度."
3084
+ }
3085
+ )
3086
+ ]
3087
+ }
3088
+ ) }) })
3089
+ ] });
3090
+ }
3091
+ const Or = {
3092
+ PENDING: "default",
3093
+ RUNNING: "processing",
3094
+ SUCCESS: "green",
3095
+ EMPTY: "default",
3096
+ FAILED: "red",
3097
+ FATAL: "red"
3098
+ };
3099
+ function zr() {
3100
+ const [t, s] = m([]), [n, k] = m(null), [a, y] = m([]), [c, f] = m([]), [x, T] = m(null), [A, p] = m(!1);
3101
+ U(() => {
3102
+ l();
3103
+ }, []), U(() => {
3104
+ n && d(n);
3105
+ }, [n]);
3106
+ const l = async () => {
3107
+ try {
3108
+ const u = await N.get("/subscribe/subscription/list"), i = (u == null ? void 0 : u.data) ?? u ?? [];
3109
+ s(Array.isArray(i) ? i : []), Array.isArray(i) && i.length > 0 && k(i[0].id);
3110
+ } catch {
3111
+ b.error("加载订阅列表失败");
3112
+ }
3113
+ }, d = async (u) => {
3114
+ p(!0);
3115
+ try {
3116
+ const i = await N.get(`/subscribe/run/list?subscriptionId=${u}&limit=50`), S = (i == null ? void 0 : i.data) ?? i ?? [];
3117
+ y(Array.isArray(S) ? S : []);
3118
+ } catch {
3119
+ b.error("加载运行历史失败");
3120
+ } finally {
3121
+ p(!1);
3122
+ }
3123
+ }, g = async (u) => {
3124
+ T(u);
3125
+ try {
3126
+ const i = await N.get(`/subscribe/run/${u}/items?limit=200`), S = (i == null ? void 0 : i.data) ?? i ?? [];
3127
+ f(Array.isArray(S) ? S : []);
3128
+ } catch {
3129
+ b.error("加载抽取项失败");
3130
+ }
3131
+ }, v = a.reduce((u, i) => u + (i.successCount || 0), 0), $ = a.reduce((u, i) => u + (i.deadLetterCount || 0), 0), C = a.reduce((u, i) => u + (i.duplicateCount || 0), 0);
3132
+ return /* @__PURE__ */ r("div", { children: [
3133
+ /* @__PURE__ */ e(
3134
+ ye,
3135
+ {
3136
+ title: "订阅中心 - 运行历史",
3137
+ subtitle: "查看各订阅的抽取运行记录与统计"
3138
+ }
3139
+ ),
3140
+ /* @__PURE__ */ e(
3141
+ Ut,
3142
+ {
3143
+ left: /* @__PURE__ */ e(
3144
+ X,
3145
+ {
3146
+ style: { width: 280 },
3147
+ placeholder: "选择订阅",
3148
+ value: n,
3149
+ onChange: k,
3150
+ options: t.map((u) => ({ value: u.id, label: u.name })),
3151
+ showSearch: !0,
3152
+ optionFilterProp: "label"
3153
+ }
3154
+ ),
3155
+ right: /* @__PURE__ */ r("a", { onClick: () => n && d(n), children: [
3156
+ /* @__PURE__ */ e(ee, {}),
3157
+ " 刷新"
3158
+ ] })
3159
+ }
3160
+ ),
3161
+ /* @__PURE__ */ r(Y, { gutter: 16, style: { marginBottom: 16 }, children: [
3162
+ /* @__PURE__ */ e(z, { span: 6, children: /* @__PURE__ */ e(M, { children: /* @__PURE__ */ e(K, { title: "run 总数", value: a.length }) }) }),
3163
+ /* @__PURE__ */ e(z, { span: 6, children: /* @__PURE__ */ e(M, { children: /* @__PURE__ */ e(
3164
+ K,
3165
+ {
3166
+ title: "成功条数",
3167
+ value: v,
3168
+ styles: { content: { color: "#3f8600" } }
3169
+ }
3170
+ ) }) }),
3171
+ /* @__PURE__ */ e(z, { span: 6, children: /* @__PURE__ */ e(M, { children: /* @__PURE__ */ e(
3172
+ K,
3173
+ {
3174
+ title: "死信条数",
3175
+ value: $,
3176
+ styles: { content: { color: "#cf1322" } }
3177
+ }
3178
+ ) }) }),
3179
+ /* @__PURE__ */ e(z, { span: 6, children: /* @__PURE__ */ e(M, { children: /* @__PURE__ */ e(K, { title: "重复跳过", value: C }) }) })
3180
+ ] }),
3181
+ /* @__PURE__ */ r(Y, { gutter: 16, children: [
3182
+ /* @__PURE__ */ e(z, { span: 12, children: /* @__PURE__ */ e(
3183
+ ie,
3184
+ {
3185
+ cardTitle: `运行列表 (${a.length})`,
3186
+ rows: a,
3187
+ rowKey: "id",
3188
+ loading: A,
3189
+ searchKeys: ["id", "status"],
3190
+ searchPlaceholder: "按 run ID / 状态过滤",
3191
+ emptyTitle: "暂无运行记录",
3192
+ emptyDescription: "该订阅还没有运行过,点右上角「刷新」或等下一次调度。",
3193
+ cardProps: { variant: "borderless", size: "small" },
3194
+ onRow: (u) => ({
3195
+ onClick: () => g(u.id),
3196
+ style: { cursor: "pointer", background: u.id === x ? "#e6f7ff" : "" }
3197
+ }),
3198
+ columns: [
3199
+ { title: "ID", dataIndex: "id", width: 60 },
3200
+ {
3201
+ title: "计划",
3202
+ dataIndex: "scheduledAt",
3203
+ width: 150,
3204
+ render: (u) => u ? new Date(u).toLocaleString() : "-"
3205
+ },
3206
+ { title: "耗时", dataIndex: "durationMs", width: 80 },
3207
+ {
3208
+ title: "状态",
3209
+ dataIndex: "status",
3210
+ width: 80,
3211
+ render: (u) => /* @__PURE__ */ e(w, { color: Or[u], children: u })
3212
+ },
3213
+ {
3214
+ title: "拉取/成功/死信",
3215
+ width: 150,
3216
+ render: (u, i) => `${i.fetchedCount} / ${i.successCount} / ${i.deadLetterCount}`
3217
+ }
3218
+ ]
3219
+ }
3220
+ ) }),
3221
+ /* @__PURE__ */ e(z, { span: 12, children: /* @__PURE__ */ e(
3222
+ ie,
3223
+ {
3224
+ cardTitle: x ? `run#${x} 抽取项 (${c.length})` : "抽取项",
3225
+ rows: c,
3226
+ rowKey: "id",
3227
+ searchKeys: ["dedupKey", "status"],
3228
+ searchPlaceholder: "按 dedupKey / 状态过滤",
3229
+ emptyTitle: x ? "该 run 无抽取项" : "暂无抽取项",
3230
+ emptyDescription: x ? "这次运行没有产生抽取项。" : "点击左侧「运行列表」中的 run 查看抽取项。",
3231
+ cardProps: { variant: "borderless", size: "small" },
3232
+ columns: [
3233
+ { title: "id", dataIndex: "dedupKey", width: 160, ellipsis: !0 },
3234
+ {
3235
+ title: "title",
3236
+ dataIndex: "normalized",
3237
+ render: (u) => {
3238
+ try {
3239
+ return JSON.parse(u).title || "(无标题)";
3240
+ } catch {
3241
+ return u;
3242
+ }
3243
+ }
3244
+ },
3245
+ {
3246
+ title: "link",
3247
+ dataIndex: "normalized",
3248
+ width: 60,
3249
+ render: (u) => {
3250
+ try {
3251
+ const i = JSON.parse(u);
3252
+ return i.link ? /* @__PURE__ */ e("a", { href: i.link, target: "_blank", children: "↗" }) : "-";
3253
+ } catch {
3254
+ return "-";
3255
+ }
3256
+ }
3257
+ },
3258
+ {
3259
+ title: "状态",
3260
+ dataIndex: "status",
3261
+ width: 100,
3262
+ render: (u) => /* @__PURE__ */ e(w, { children: u })
3263
+ }
3264
+ ]
3265
+ }
3266
+ ) })
3267
+ ] })
3268
+ ] });
3269
+ }
3270
+ function Mr() {
3271
+ return /* @__PURE__ */ r(ct, { children: [
3272
+ /* @__PURE__ */ e(ne, { index: !0, element: /* @__PURE__ */ e(dt, { to: "list", replace: !0 }) }),
3273
+ /* @__PURE__ */ e(ne, { path: "list", element: /* @__PURE__ */ e(_r, {}) }),
3274
+ /* @__PURE__ */ e(ne, { path: "new", element: /* @__PURE__ */ e(at, {}) }),
3275
+ /* @__PURE__ */ e(ne, { path: "edit/:id", element: /* @__PURE__ */ e(at, {}) }),
3276
+ /* @__PURE__ */ e(ne, { path: "runs", element: /* @__PURE__ */ e(zr, {}) })
3277
+ ] });
3278
+ }
3279
+ const ln = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
3280
+ __proto__: null,
3281
+ default: Mr
3282
+ }, Symbol.toStringTag, { value: "Module" })), Lr = {
3283
+ OPEN: { color: "blue", text: "待开始" },
3284
+ IN_PROGRESS: { color: "green", text: "进行中" },
3285
+ COMPLETED: { color: "default", text: "已完成" },
3286
+ ARCHIVED: { color: "default", text: "已归档" }
3287
+ };
3288
+ function $r() {
3289
+ const t = xe(), [s, n] = m("mine"), [k, a] = m([]), [y, c] = m(!1), [f, x] = m(null), T = async () => {
3290
+ c(!0), x(null);
3291
+ try {
3292
+ const l = s === "mine" ? "/project/list/mine?limit=100" : `/project/list/by-status?status=${s}&limit=100`, d = await N.get(l), g = (d == null ? void 0 : d.data) ?? d ?? [];
3293
+ a(Array.isArray(g) ? g : []);
3294
+ } catch (l) {
3295
+ x((l == null ? void 0 : l.message) || (l == null ? void 0 : l.msg) || "加载失败");
3296
+ } finally {
3297
+ c(!1);
3298
+ }
3299
+ };
3300
+ U(() => {
3301
+ T();
3302
+ }, [s]);
3303
+ const A = async (l) => {
3304
+ try {
3305
+ const d = await N.post(`/project/${l}/status?status=COMPLETED`);
3306
+ d && d.success !== !1 && (b.success("已标记完成"), T());
3307
+ } catch (d) {
3308
+ b.error("操作失败: " + ((d == null ? void 0 : d.message) || ""));
3309
+ }
3310
+ };
3311
+ return /* @__PURE__ */ r("div", { children: [
3312
+ /* @__PURE__ */ e(
3313
+ ye,
3314
+ {
3315
+ title: "项目中心",
3316
+ subtitle: "管理由 CEO 立项的项目与 Agent 对话上下文",
3317
+ breadcrumb: [{ label: "项目中心" }]
3318
+ }
3319
+ ),
3320
+ f && !y && /* @__PURE__ */ e("div", { style: { marginBottom: 16 }, children: /* @__PURE__ */ e(Ht, { error: f, onRetry: T }) }),
3321
+ /* @__PURE__ */ r("div", { style: {
3322
+ background: "#ffffff",
3323
+ borderRadius: 16,
3324
+ padding: 20,
3325
+ boxShadow: "0 1px 3px rgba(15, 23, 42, 0.04), 0 1px 2px rgba(15, 23, 42, 0.06)"
3326
+ }, children: [
3327
+ /* @__PURE__ */ e(
3328
+ Ie,
3329
+ {
3330
+ activeKey: s,
3331
+ onChange: n,
3332
+ tabBarExtraContent: /* @__PURE__ */ r(P, { children: [
3333
+ /* @__PURE__ */ e(_, { icon: /* @__PURE__ */ e(ee, {}), onClick: T, loading: y, children: "刷新" }),
3334
+ /* @__PURE__ */ e(
3335
+ _,
3336
+ {
3337
+ type: "primary",
3338
+ icon: /* @__PURE__ */ e(yt, {}),
3339
+ onClick: () => t("/project/new"),
3340
+ children: "新建项目"
3341
+ }
3342
+ )
3343
+ ] }),
3344
+ items: [
3345
+ { key: "mine", label: "我的进行中" },
3346
+ { key: "OPEN", label: "待开始" },
3347
+ { key: "IN_PROGRESS", label: "进行中" },
3348
+ { key: "COMPLETED", label: "已完成" }
3349
+ ]
3350
+ }
3351
+ ),
3352
+ /* @__PURE__ */ e(
3353
+ ie,
3354
+ {
3355
+ rows: k,
3356
+ columns: [
3357
+ { title: "ID", dataIndex: "id", width: 60 },
3358
+ {
3359
+ title: "名称",
3360
+ dataIndex: "name",
3361
+ render: (l, d) => /* @__PURE__ */ r(P, { orientation: "vertical", size: 0, children: [
3362
+ /* @__PURE__ */ e("a", { onClick: () => t(`/project/${d.id}`), style: { fontWeight: 500 }, children: l }),
3363
+ d.description && /* @__PURE__ */ e("span", { style: { color: "#999", fontSize: 12 }, children: d.description })
3364
+ ] })
3365
+ },
3366
+ { title: "来源", dataIndex: "sourceType", width: 100, render: (l) => /* @__PURE__ */ e(w, { children: l }) },
3367
+ {
3368
+ title: "订阅",
3369
+ dataIndex: "sourceSubscriptionId",
3370
+ width: 80,
3371
+ render: (l) => l ? `#${l}` : /* @__PURE__ */ e("span", { style: { color: "#ccc" }, children: "-" })
3372
+ },
3373
+ {
3374
+ title: "状态",
3375
+ dataIndex: "status",
3376
+ width: 100,
3377
+ render: (l) => {
3378
+ const d = Lr[l] || { color: "default", text: l };
3379
+ return /* @__PURE__ */ e(w, { color: d.color, children: d.text });
3380
+ }
3381
+ },
3382
+ { title: "消息数", dataIndex: "messageCount", width: 80 },
3383
+ {
3384
+ title: "上下文",
3385
+ width: 130,
3386
+ render: (l, d) => /* @__PURE__ */ r(w, { color: "blue", children: [
3387
+ d.contextSize || 0,
3388
+ "B"
3389
+ ] })
3390
+ },
3391
+ {
3392
+ title: "最近活动",
3393
+ dataIndex: "lastMessageAt",
3394
+ width: 150,
3395
+ render: (l) => l ? new Date(l).toLocaleString() : /* @__PURE__ */ e("span", { style: { color: "#ccc" }, children: "-" })
3396
+ },
3397
+ {
3398
+ title: "操作",
3399
+ width: 160,
3400
+ render: (l, d) => /* @__PURE__ */ r(P, { size: 4, children: [
3401
+ /* @__PURE__ */ e(_, { type: "link", size: "small", onClick: () => t(`/project/${d.id}`), children: "对话" }),
3402
+ d.status !== "COMPLETED" && d.status !== "ARCHIVED" && /* @__PURE__ */ e(
3403
+ je,
3404
+ {
3405
+ title: "标记为已完成?",
3406
+ onConfirm: () => A(d.id),
3407
+ okButtonProps: { danger: !0 },
3408
+ children: /* @__PURE__ */ e(_, { type: "link", size: "small", icon: /* @__PURE__ */ e(Ue, {}), children: "完成" })
3409
+ }
3410
+ )
3411
+ ] })
3412
+ }
3413
+ ],
3414
+ rowKey: "id",
3415
+ loading: y,
3416
+ searchKeys: ["name", "id"],
3417
+ searchPlaceholder: "按项目名称 / ID 过滤",
3418
+ emptyTitle: "还没有项目",
3419
+ emptyDescription: "立项一个项目, 让 Agent 围绕目标持续推进对话与任务",
3420
+ emptyActionText: "新建第一个项目",
3421
+ emptyOnAction: () => t("/project/new"),
3422
+ tableProps: { size: "middle" },
3423
+ cardProps: { variant: "borderless", styles: { body: { padding: 0 } } }
3424
+ }
3425
+ )
3426
+ ] })
3427
+ ] });
3428
+ }
3429
+ const Nr = [
3430
+ { value: "general", label: "通用助手" },
3431
+ { value: "analyst", label: "分析师" },
3432
+ { value: "writer", label: "写手" },
3433
+ { value: "pm", label: "产品经理" },
3434
+ { value: "ops", label: "运营" }
3435
+ ];
3436
+ function Dr() {
3437
+ const t = xe(), [s] = St(), [n] = E.useForm(), [k, a] = m(!1), [y, c] = m("from-subscribe"), [f, x] = m([]), [T, A] = m([]), [p, l] = m(!1), [d, g] = m([]), [v, $] = m(null);
3438
+ U(() => {
3439
+ const S = s.get("subscriptionId"), L = s.get("itemIds");
3440
+ S && ($(Number(S)), n.setFieldValue("sourceSubscriptionId", Number(S)), u(S)), L && g(L.split(",").map(Number).filter(Boolean));
3441
+ }, [s]), U(() => {
3442
+ C();
3443
+ }, []);
3444
+ const C = async () => {
3445
+ try {
3446
+ const S = await N.get("/subscribe/subscription/list"), L = (S == null ? void 0 : S.data) ?? S ?? [];
3447
+ x(Array.isArray(L) ? L.filter((J) => J.status === "VERIFIED") : []);
3448
+ } catch {
3449
+ }
3450
+ }, u = async (S) => {
3451
+ l(!0);
3452
+ try {
3453
+ const L = await N.get(`/subscribe/run/list?subscriptionId=${S}&limit=1`), J = (L == null ? void 0 : L.data) ?? L ?? [];
3454
+ if (J.length === 0) {
3455
+ A([]);
3456
+ return;
3457
+ }
3458
+ const H = J[0], h = await N.get(`/subscribe/run/${H.id}/items?limit=100`), o = (h == null ? void 0 : h.data) ?? h ?? [];
3459
+ A(Array.isArray(o) ? o : []);
3460
+ } catch {
3461
+ b.error("加载抽取项失败");
3462
+ } finally {
3463
+ l(!1);
3464
+ }
3465
+ };
3466
+ return /* @__PURE__ */ e("div", { style: { padding: 24 }, children: /* @__PURE__ */ e(
3467
+ M,
3468
+ {
3469
+ title: /* @__PURE__ */ r(P, { children: [
3470
+ /* @__PURE__ */ e(_, { type: "text", icon: /* @__PURE__ */ e(ft, {}), onClick: () => t("/project/list") }),
3471
+ /* @__PURE__ */ e(Fe, {}),
3472
+ "新建项目 (立项)"
3473
+ ] }),
3474
+ extra: /* @__PURE__ */ r(P, { children: [
3475
+ /* @__PURE__ */ e(_, { onClick: () => t("/project/list"), children: "取消" }),
3476
+ /* @__PURE__ */ e(
3477
+ _,
3478
+ {
3479
+ type: "primary",
3480
+ icon: /* @__PURE__ */ e(gt, {}),
3481
+ loading: k,
3482
+ onClick: async () => {
3483
+ try {
3484
+ const S = await n.validateFields();
3485
+ if (y === "from-subscribe" && d.length === 0) {
3486
+ b.warning("请至少选 1 个 item");
3487
+ return;
3488
+ }
3489
+ a(!0);
3490
+ const L = {
3491
+ ...S,
3492
+ sourceItemIds: y === "from-subscribe" ? d.map(String) : null
3493
+ }, J = y === "from-subscribe" ? "/project/create-from-items" : "/project/create-manual", H = await N.post(J, L);
3494
+ if (H && H.success !== !1) {
3495
+ const h = H.data ?? H;
3496
+ b.success("立项成功"), t(`/project/${h.id}`);
3497
+ } else
3498
+ b.error((H == null ? void 0 : H.message) || "立项失败");
3499
+ } catch (S) {
3500
+ S != null && S.errorFields || b.error("立项失败: " + ((S == null ? void 0 : S.message) || ""));
3501
+ } finally {
3502
+ a(!1);
3503
+ }
3504
+ },
3505
+ children: "立项"
3506
+ }
3507
+ )
3508
+ ] }),
3509
+ children: /* @__PURE__ */ r(E, { form: n, layout: "vertical", initialValues: { agentRole: "general" }, children: [
3510
+ /* @__PURE__ */ e(E.Item, { label: "来源", children: /* @__PURE__ */ r(re.Group, { value: y, onChange: (S) => c(S.target.value), children: [
3511
+ /* @__PURE__ */ e(re.Button, { value: "from-subscribe", children: "从订阅线索立项 (主路径)" }),
3512
+ /* @__PURE__ */ e(re.Button, { value: "manual", children: "手动立项 (无源数据)" })
3513
+ ] }) }),
3514
+ /* @__PURE__ */ e(E.Item, { label: "项目名称", name: "name", rules: [{ required: !0, message: "请输入名称" }], children: /* @__PURE__ */ e(B, { placeholder: "例如: 跟进 GitHub 高优 Issue" }) }),
3515
+ /* @__PURE__ */ e(E.Item, { label: "项目描述", name: "description", children: /* @__PURE__ */ e(B.TextArea, { rows: 2, placeholder: "(可选) 这个项目要解决什么?" }) }),
3516
+ y === "from-subscribe" && /* @__PURE__ */ r(M, { type: "inner", title: "源数据", style: { marginBottom: 16 }, children: [
3517
+ /* @__PURE__ */ e(
3518
+ E.Item,
3519
+ {
3520
+ label: "选择订阅",
3521
+ name: "sourceSubscriptionId",
3522
+ rules: [{ required: !0, message: "请选订阅" }],
3523
+ children: /* @__PURE__ */ e(
3524
+ X,
3525
+ {
3526
+ placeholder: "选择订阅 (拉取最近一次 run 的 items)",
3527
+ options: f.map((S) => ({ value: S.id, label: `#${S.id} ${S.name}` })),
3528
+ onChange: (S) => {
3529
+ $(S), u(S), g([]);
3530
+ }
3531
+ }
3532
+ )
3533
+ }
3534
+ ),
3535
+ v && /* @__PURE__ */ r(Ae, { spinning: p, children: [
3536
+ /* @__PURE__ */ r("div", { style: { marginBottom: 8 }, children: [
3537
+ /* @__PURE__ */ r(w, { color: "blue", children: [
3538
+ "已选 ",
3539
+ d.length,
3540
+ " / ",
3541
+ T.length
3542
+ ] }),
3543
+ /* @__PURE__ */ e(
3544
+ _,
3545
+ {
3546
+ size: "small",
3547
+ onClick: () => g(T.map((S) => S.id)),
3548
+ children: "全选"
3549
+ }
3550
+ ),
3551
+ /* @__PURE__ */ e(
3552
+ _,
3553
+ {
3554
+ size: "small",
3555
+ onClick: () => g([]),
3556
+ style: { marginLeft: 4 },
3557
+ children: "清空"
3558
+ }
3559
+ )
3560
+ ] }),
3561
+ /* @__PURE__ */ e(
3562
+ ie,
3563
+ {
3564
+ rows: T,
3565
+ rowKey: "id",
3566
+ rowSelection: {
3567
+ selectedRowKeys: d,
3568
+ onChange: g
3569
+ },
3570
+ searchKeys: ["dedupKey"],
3571
+ searchPlaceholder: "按 dedupKey 过滤",
3572
+ emptyTitle: "暂无源数据",
3573
+ emptyDescription: "该订阅最近一次运行没有抽取项,换一个订阅或先让订阅跑一次。",
3574
+ cardProps: { variant: "borderless", styles: { body: { padding: 0 } } },
3575
+ columns: [
3576
+ { title: "id", dataIndex: "dedupKey", width: 160, ellipsis: !0 },
3577
+ {
3578
+ title: "title",
3579
+ dataIndex: "normalized",
3580
+ render: (S) => {
3581
+ try {
3582
+ return JSON.parse(S).title || "(无)";
3583
+ } catch {
3584
+ return S;
3585
+ }
3586
+ }
3587
+ },
3588
+ {
3589
+ title: "fetched",
3590
+ dataIndex: "fetchedAt",
3591
+ width: 150,
3592
+ render: (S) => S ? new Date(S).toLocaleString() : "-"
3593
+ }
3594
+ ]
3595
+ }
3596
+ )
3597
+ ] })
3598
+ ] }),
3599
+ /* @__PURE__ */ r(M, { type: "inner", title: "Agent 配置", style: { marginBottom: 16 }, children: [
3600
+ /* @__PURE__ */ e(E.Item, { label: "Agent 角色", name: "agentRole", extra: "决定 system prompt 的语气 / 视角", children: /* @__PURE__ */ e(X, { options: Nr }) }),
3601
+ /* @__PURE__ */ e(
3602
+ E.Item,
3603
+ {
3604
+ label: "模型 (可选)",
3605
+ name: "modelCode",
3606
+ extra: "留空走默认 (智能中心 LLM 凭证里第一个 enabled)",
3607
+ children: /* @__PURE__ */ e(B, { placeholder: "例如: gpt-4 / deepseek-chat" })
3608
+ }
3609
+ )
3610
+ ] }),
3611
+ /* @__PURE__ */ e(
3612
+ V,
3613
+ {
3614
+ type: "info",
3615
+ showIcon: !0,
3616
+ title: "立项后源数据会被快照 (context_snapshot), 后续订阅更新不会影响项目上下文."
3617
+ }
3618
+ )
3619
+ ] })
3620
+ }
3621
+ ) });
3622
+ }
3623
+ const it = {
3624
+ USER: { color: "blue", icon: /* @__PURE__ */ e(ut, {}), label: "CEO" },
3625
+ ASSISTANT: { color: "purple", icon: /* @__PURE__ */ e(Ne, {}), label: "Agent" },
3626
+ SYSTEM: { color: "default", icon: null, label: "系统" }
3627
+ }, Br = {
3628
+ OPEN: { color: "blue", text: "待开始" },
3629
+ IN_PROGRESS: { color: "green", text: "进行中" },
3630
+ COMPLETED: { color: "default", text: "已完成" },
3631
+ ARCHIVED: { color: "default", text: "已归档" }
3632
+ };
3633
+ function qr() {
3634
+ const { id: t } = ot(), s = xe(), [n, k] = m(null), [a, y] = m([]), [c, f] = m(""), [x, T] = m(!1), A = st(null);
3635
+ U(() => {
3636
+ t && p();
3637
+ }, [t]), U(() => {
3638
+ A.current && (A.current.scrollTop = A.current.scrollHeight);
3639
+ }, [a]);
3640
+ const p = async () => {
3641
+ try {
3642
+ const [v, $] = await Promise.all([
3643
+ N.get(`/project/${t}`),
3644
+ N.get(`/project/${t}/messages`)
3645
+ ]);
3646
+ k((v == null ? void 0 : v.data) ?? v), y(Array.isArray(($ == null ? void 0 : $.data) ?? $) ? ($ == null ? void 0 : $.data) ?? $ : []);
3647
+ } catch {
3648
+ b.error("加载项目失败");
3649
+ }
3650
+ }, l = async () => {
3651
+ if (!c.trim()) return;
3652
+ const v = c.trim();
3653
+ f(""), T(!0);
3654
+ const $ = { seq: -1, role: "USER", content: v, createdAt: (/* @__PURE__ */ new Date()).toISOString() };
3655
+ y((C) => [...C, $]);
3656
+ try {
3657
+ const C = await N.post(`/project/${t}/chat`, { message: v });
3658
+ if (C && C.success !== !1) {
3659
+ const i = (C.data ?? C).message;
3660
+ y((S) => [...S.filter((J) => J.seq !== -1), ...i ? [i] : []]), setTimeout(p, 100);
3661
+ } else
3662
+ b.error((C == null ? void 0 : C.message) || "发送失败");
3663
+ } catch (C) {
3664
+ b.error("发送失败: " + ((C == null ? void 0 : C.message) || ""));
3665
+ } finally {
3666
+ T(!1);
3667
+ }
3668
+ }, d = async () => {
3669
+ try {
3670
+ const v = await N.post(`/project/${t}/status?status=COMPLETED`);
3671
+ v && v.success !== !1 && (b.success("已标记完成"), p());
3672
+ } catch {
3673
+ b.error("操作失败");
3674
+ }
3675
+ };
3676
+ if (!n) return /* @__PURE__ */ e("div", { style: { padding: 24 }, children: /* @__PURE__ */ e(Ae, {}) });
3677
+ const g = Br[n.status] || { color: "default", text: n.status };
3678
+ return /* @__PURE__ */ r("div", { style: { padding: 24, height: "calc(100vh - 64px)", display: "flex", flexDirection: "column", gap: 16 }, children: [
3679
+ /* @__PURE__ */ r(
3680
+ M,
3681
+ {
3682
+ title: /* @__PURE__ */ r(P, { children: [
3683
+ /* @__PURE__ */ e(_, { type: "text", icon: /* @__PURE__ */ e(ft, {}), onClick: () => s("/project/list") }),
3684
+ /* @__PURE__ */ e(Fe, {}),
3685
+ /* @__PURE__ */ e("span", { style: { fontWeight: 500 }, children: n.name }),
3686
+ /* @__PURE__ */ e(w, { color: g.color, children: g.text })
3687
+ ] }),
3688
+ extra: /* @__PURE__ */ r(P, { children: [
3689
+ n.contextSize > 0 && /* @__PURE__ */ r(w, { color: "blue", children: [
3690
+ "上下文 ",
3691
+ n.contextSize,
3692
+ " B"
3693
+ ] }),
3694
+ /* @__PURE__ */ e(w, { children: n.agentRole }),
3695
+ n.modelCode && /* @__PURE__ */ e(w, { color: "purple", children: n.modelCode }),
3696
+ n.status !== "COMPLETED" && n.status !== "ARCHIVED" && /* @__PURE__ */ e(je, { title: "标记完成?", onConfirm: d, children: /* @__PURE__ */ e(_, { icon: /* @__PURE__ */ e(Ue, {}), children: "标记完成" }) })
3697
+ ] }),
3698
+ children: [
3699
+ n.description && /* @__PURE__ */ e("div", { style: { color: "#666", marginBottom: 8 }, children: n.description }),
3700
+ /* @__PURE__ */ r(P, { size: "large", children: [
3701
+ /* @__PURE__ */ e(K, { title: "消息数", value: n.messageCount || 0 }),
3702
+ n.sourceSubscriptionId && /* @__PURE__ */ e(K, { title: "来源订阅", value: `#${n.sourceSubscriptionId}` }),
3703
+ /* @__PURE__ */ e(
3704
+ K,
3705
+ {
3706
+ title: "立项",
3707
+ value: n.createdAt ? new Date(n.createdAt).toLocaleString() : "-"
3708
+ }
3709
+ )
3710
+ ] })
3711
+ ]
3712
+ }
3713
+ ),
3714
+ /* @__PURE__ */ r(
3715
+ M,
3716
+ {
3717
+ style: { flex: 1, display: "flex", flexDirection: "column" },
3718
+ styles: { body: { flex: 1, display: "flex", flexDirection: "column", padding: 0 } },
3719
+ children: [
3720
+ /* @__PURE__ */ e("div", { ref: A, style: { flex: 1, overflow: "auto", padding: 16, background: "#fafafa" }, children: a.length === 0 ? /* @__PURE__ */ e(Ct, { description: "还没有消息, 跟 Agent 说点什么?" }) : /* @__PURE__ */ r(P, { orientation: "vertical", style: { width: "100%" }, size: "middle", children: [
3721
+ a.map((v) => {
3722
+ const $ = it[v.role] || it.SYSTEM, C = v.role === "USER";
3723
+ return /* @__PURE__ */ e("div", { style: {
3724
+ display: "flex",
3725
+ justifyContent: C ? "flex-end" : "flex-start"
3726
+ }, children: /* @__PURE__ */ r("div", { style: {
3727
+ maxWidth: "70%",
3728
+ background: C ? "#1677ff" : "#fff",
3729
+ color: C ? "#fff" : "#000",
3730
+ border: C ? "none" : "1px solid #e8e8e8",
3731
+ borderRadius: 8,
3732
+ padding: "10px 14px",
3733
+ boxShadow: "0 1px 2px rgba(0,0,0,0.04)"
3734
+ }, children: [
3735
+ /* @__PURE__ */ e("div", { style: { fontSize: 12, opacity: 0.7, marginBottom: 4 }, children: /* @__PURE__ */ r(P, { size: 4, children: [
3736
+ $.icon,
3737
+ $.label,
3738
+ v.seq > 0 && /* @__PURE__ */ r("span", { children: [
3739
+ "#",
3740
+ v.seq
3741
+ ] }),
3742
+ v.latencyMs > 0 && /* @__PURE__ */ r("span", { children: [
3743
+ "· ",
3744
+ v.latencyMs,
3745
+ "ms"
3746
+ ] }),
3747
+ v.modelCode && /* @__PURE__ */ r("span", { children: [
3748
+ "· ",
3749
+ v.modelCode
3750
+ ] })
3751
+ ] }) }),
3752
+ /* @__PURE__ */ e("div", { style: { whiteSpace: "pre-wrap", wordBreak: "break-word" }, children: v.content })
3753
+ ] }) }, v.id || v.seq);
3754
+ }),
3755
+ x && /* @__PURE__ */ e("div", { style: { display: "flex", justifyContent: "flex-start" }, children: /* @__PURE__ */ r("div", { style: {
3756
+ background: "#fff",
3757
+ border: "1px solid #e8e8e8",
3758
+ borderRadius: 8,
3759
+ padding: "10px 14px"
3760
+ }, children: [
3761
+ /* @__PURE__ */ e(Ae, { size: "small" }),
3762
+ " 思考中..."
3763
+ ] }) })
3764
+ ] }) }),
3765
+ n.status === "COMPLETED" || n.status === "ARCHIVED" ? /* @__PURE__ */ e(
3766
+ V,
3767
+ {
3768
+ style: { margin: 12, marginBottom: 0 },
3769
+ type: "info",
3770
+ title: "项目已完成 / 归档, 不再接受新消息",
3771
+ showIcon: !0
3772
+ }
3773
+ ) : /* @__PURE__ */ r("div", { style: { borderTop: "1px solid #f0f0f0", padding: 12, display: "flex", gap: 8 }, children: [
3774
+ /* @__PURE__ */ e(
3775
+ B.TextArea,
3776
+ {
3777
+ value: c,
3778
+ onChange: (v) => f(v.target.value),
3779
+ onPressEnter: (v) => {
3780
+ v.shiftKey || (v.preventDefault(), l());
3781
+ },
3782
+ placeholder: "输入消息, Enter 发送 (Shift+Enter 换行)",
3783
+ autoSize: { minRows: 1, maxRows: 6 },
3784
+ disabled: x
3785
+ }
3786
+ ),
3787
+ /* @__PURE__ */ e(
3788
+ _,
3789
+ {
3790
+ type: "primary",
3791
+ icon: /* @__PURE__ */ e(qt, {}),
3792
+ loading: x,
3793
+ onClick: l,
3794
+ disabled: !c.trim(),
3795
+ children: "发送"
3796
+ }
3797
+ )
3798
+ ] })
3799
+ ]
3800
+ }
3801
+ )
3802
+ ] });
3803
+ }
3804
+ function jr() {
3805
+ return /* @__PURE__ */ r(ct, { children: [
3806
+ /* @__PURE__ */ e(ne, { index: !0, element: /* @__PURE__ */ e(dt, { to: "list", replace: !0 }) }),
3807
+ /* @__PURE__ */ e(ne, { path: "list", element: /* @__PURE__ */ e($r, {}) }),
3808
+ /* @__PURE__ */ e(ne, { path: "new", element: /* @__PURE__ */ e(Dr, {}) }),
3809
+ /* @__PURE__ */ e(ne, { path: ":id", element: /* @__PURE__ */ e(qr, {}) })
3810
+ ] });
3811
+ }
3812
+ const an = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
3813
+ __proto__: null,
3814
+ default: jr
3815
+ }, Symbol.toStringTag, { value: "Module" }));
3816
+ export {
3817
+ rn as C,
3818
+ Be as E,
3819
+ Ir as M,
3820
+ nn as O,
3821
+ jr as P,
3822
+ br as R,
3823
+ Mr as S,
3824
+ fr as T,
3825
+ Wr as Z,
3826
+ Zr as a,
3827
+ qe as b,
3828
+ tn as c,
3829
+ Yr as d,
3830
+ wr as e,
3831
+ yr as f,
3832
+ Ge as g,
3833
+ Qr as h,
3834
+ lr as i,
3835
+ ln as j,
3836
+ an as k,
3837
+ N as r,
3838
+ or as s
3839
+ };