@yuku123/z-team-component 0.2.29 → 0.2.31

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 (49) hide show
  1. package/dist/{ChangeLogView-CG-o5YP1.js → ChangeLogView-FLd1wS8H.js} +1 -1
  2. package/dist/ComponentDoc-CUhlRqDo.js +3843 -0
  3. package/dist/DebugPlayground-cxffrMgF.js +15 -0
  4. package/dist/{InvitationManagementPage-ByJuWwA_.js → InvitationManagementPage-DBAAQ3Qq.js} +90 -85
  5. package/dist/{OnboardingPage-D58h1JK_.js → OnboardingPage-zLHkQLok.js} +2 -2
  6. package/dist/SmartWorkbench.module-DzQskKT0.js +85 -0
  7. package/dist/SystemShell-yMCZOMUN.js +635 -0
  8. package/dist/{admin-logs-C2V1ElH9.js → admin-logs-Dv86pFvY.js} +2 -2
  9. package/dist/{api--Fg0hL9Y.js → api-19TXED_O.js} +52 -39
  10. package/dist/api-63lPU5Cs.js +20 -0
  11. package/dist/{createWorkspaceWsHandler-CqGqcTh_.js → createWorkspaceWsHandler-CBk4DqP4.js} +6 -5
  12. package/dist/{index-CDKg_qI5.js → index-B5_xKK08.js} +1140 -1153
  13. package/dist/{index-D2S8FrNc.js → index-BCBBZW4m.js} +358 -347
  14. package/dist/{index-D5u3BjCZ.js → index-BIJnjJd5.js} +2 -2
  15. package/dist/{index-bbwTcNjB.js → index-BTLD5gUt.js} +3 -3
  16. package/dist/{index-CiMxCTOS.js → index-B_EBV24V.js} +1 -1
  17. package/dist/{index-DOVOWiGU.js → index-BbjzrjsP.js} +1134 -1132
  18. package/dist/{index-BafC42Cl.js → index-Bd57t_yF.js} +1 -1
  19. package/dist/{index-C2aPiQSz.js → index-BjqYiZpC.js} +3 -3
  20. package/dist/{index-BaCiSbPR.js → index-BoGVJ0hC.js} +1 -1
  21. package/dist/{index-C01UUprh.js → index-BpuJ9Njb.js} +7016 -6946
  22. package/dist/index-C6vfXs2f.js +1329 -0
  23. package/dist/{index-CcFJEYgr.js → index-C815hPWS.js} +55 -52
  24. package/dist/{index-DvIHX7lZ.js → index-CcpWacSZ.js} +243 -236
  25. package/dist/index-CrC94bvI.js +169 -0
  26. package/dist/{index-Dky6GVc1.js → index-CwIgdJYL.js} +9 -9
  27. package/dist/{index-Da7ls5q6.js → index-DOPkM2W8.js} +6 -6
  28. package/dist/{index-CTD7k9dP.js → index-DYgD6BuB.js} +4 -4
  29. package/dist/{index-Da3doGtf.js → index-JMzBzwiO.js} +57 -54
  30. package/dist/{index-BwFEDHy3.js → index-VHvEmmhf.js} +5 -5
  31. package/dist/{index-CRac8IT2.js → index-icI-ZchA.js} +3 -3
  32. package/dist/{index-Dao4uqQd.js → index-x4-W5ClM.js} +4 -4
  33. package/dist/index.js +7 -6
  34. package/dist/{instance-1QEDBRqA.js → instance-D951fRuD.js} +1 -1
  35. package/dist/pages.js +13 -9
  36. package/dist/{schedule-C89oiqIR.js → schedule-DD50-7cs.js} +1 -1
  37. package/dist/{send-default-agent-team-message-CxkWi3XC.js → send-default-agent-team-message-Bbs2rMNf.js} +1 -1
  38. package/dist/{sso-user-BE1Ell5F.js → sso-user-BEY5ICaR.js} +1 -1
  39. package/dist/{training-o-vSBkqP.js → training-B-9tNFQw.js} +1 -1
  40. package/dist/{useAppStore-wgWaxcyc.js → useAppStore-BQN-26ns.js} +1 -1
  41. package/dist/{webide-BxD6cYe-.js → webide-P867RFZi.js} +4 -4
  42. package/dist/z-team-component.css +1 -1
  43. package/package.json +2 -2
  44. package/dist/ProjectApp-oUbzb0Io.js +0 -3818
  45. package/dist/SmartWorkbench.module-xRRmpTTw.js +0 -85
  46. package/dist/SystemShell-D4mGsT0X.js +0 -604
  47. package/dist/api-3-Ykp2ll.js +0 -19
  48. package/dist/index-B8mNsH88.js +0 -1411
  49. package/dist/index-DYDba1NC.js +0 -187
@@ -0,0 +1,3843 @@
1
+ import { jsx as e, jsxs as n, Fragment as Me } from "react/jsx-runtime";
2
+ import { lazy as xt, Suspense as wt, useState as m, useEffect as F, useRef as it } from "react";
3
+ import { useLocation as kt, useNavigate as xe, useParams as ot, Routes as ct, Route as re, Navigate as dt, useSearchParams as It } from "react-router-dom";
4
+ import { Row as Y, Col as O, Typography as ae, Alert as Z, Card as L, Space as E, Button as A, Table as Q, Drawer as we, Descriptions as z, Tag as w, Tooltip as he, message as b, Modal as me, Statistic as K, Input as B, Select as V, Tabs as ke, Form as P, Upload as St, Popconfirm as Ue, Spin as _e, Radio as ne, InputNumber as Re, Empty as Tt } from "antd";
5
+ import { SettingOutlined as Ct, ProjectOutlined as Pe, UserOutlined as ut, AuditOutlined as De, RobotOutlined as $e, ApiOutlined as qe, AppstoreOutlined as vt, ThunderboltOutlined as be, BarChartOutlined as At, ScheduleOutlined as _t, FileTextOutlined as Ke, ReloadOutlined as ee, ExperimentOutlined as Pt, PlayCircleOutlined as Ee, CopyOutlined as pt, GlobalOutlined as ht, NodeIndexOutlined as Et, UndoOutlined as zt, FileSearchOutlined as Rt, VideoCameraOutlined as Je, SearchOutlined as mt, EyeOutlined as Ot, CodeOutlined as fe, InfoCircleOutlined as Lt, FunctionOutlined as Se, ImportOutlined as Ne, CloudUploadOutlined as Ve, FileAddOutlined as Mt, PlusOutlined as yt, EditOutlined as Dt, PauseCircleOutlined as $t, CheckCircleOutlined as Fe, DeleteOutlined as Nt, ExclamationCircleOutlined as Bt, SaveOutlined as gt, ArrowLeftOutlined as ft, SendOutlined as jt } from "@ant-design/icons";
6
+ import "@yuku123/z-frontend-common";
7
+ import { PageHeader as ye, GradientStatCard as Te, SectionHeader as Ut, FeatureCard as qt, DarkBanner as Kt, ListTable as se, TableToolbar as Ft, ErrorState as Ht, ComponentDoc as Gt } from "@yuku123/z-frontend-common/ui";
8
+ import He from "axios";
9
+ const X = (t) => {
10
+ const i = xt(t);
11
+ return (r) => /* @__PURE__ */ e(wt, { fallback: null, children: /* @__PURE__ */ e(i, { ...r }) });
12
+ }, oe = X(() => import("./index-BbjzrjsP.js").then((t) => t.H)), Zt = X(() => import("./index-DOPkM2W8.js")), Jt = X(() => import("./index-BTLD5gUt.js")), Vt = X(() => import("./index-DYgD6BuB.js")), Wt = X(() => import("./index-x4-W5ClM.js")), Xt = X(() => import("./index-BIJnjJd5.js"));
13
+ X(() => import("./index-BpuJ9Njb.js"));
14
+ const Yt = X(() => import("./index-C815hPWS.js")), Qt = X(() => import("./index-UsGqMo11.js")), en = X(() => import("./index-BkX0I2aB.js")), tn = X(() => import("./index-B_EBV24V.js")), nn = X(() => import("./index-Bd57t_yF.js")), rn = X(() => import("./index-BjqYiZpC.js"));
15
+ function Qn({ forcedMode: t }) {
16
+ const { pathname: i } = kt(), r = i.replace(/\/+$/, "") || "/";
17
+ return t === "system" ? /* @__PURE__ */ e(oe, { forcedChatMode: "system" }) : t === "rpa" ? /* @__PURE__ */ e(oe, { forcedChatMode: "rpa" }) : t === "dev" ? /* @__PURE__ */ e(oe, { forcedChatMode: "dev" }) : r === "/workspace" ? /* @__PURE__ */ e(oe, {}) : r === "/workspace/phone" ? /* @__PURE__ */ e(Zt, {}) : r === "/workspace/from-ticket" ? /* @__PURE__ */ e(Jt, {}) : r === "/workspace/from-scenario" ? /* @__PURE__ */ e(Vt, {}) : r === "/workspace/build-by-form" ? /* @__PURE__ */ e(Wt, {}) : r === "/scenario" ? /* @__PURE__ */ e(Xt, {}) : r === "/admin" ? /* @__PURE__ */ e(oe, {}) : r === "/welcome" ? /* @__PURE__ */ e(Qt, {}) : r === "/portal" ? /* @__PURE__ */ e(en, {}) : r === "/chatdemo" ? /* @__PURE__ */ e(Yt, {}) : r === "/embed/chat" || r.startsWith("/embed/chat/") ? /* @__PURE__ */ e(rn, {}) : r === "/change-log" ? /* @__PURE__ */ e(tn, {}) : r === "/docs" ? /* @__PURE__ */ e(nn, {}) : /* @__PURE__ */ e(oe, {});
18
+ }
19
+ function an(t) {
20
+ if (!t || typeof t != "string") return null;
21
+ const i = t.split(".");
22
+ if (i.length !== 3) return null;
23
+ try {
24
+ let r = i[1].replace(/-/g, "+").replace(/_/g, "/");
25
+ const S = r.length % 4;
26
+ S && (r += "=".repeat(4 - S));
27
+ const l = atob(r), y = Uint8Array.from(l, (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 ln(t, i = 30) {
34
+ const r = an(t);
35
+ return !r || typeof r.exp != "number" ? !0 : Date.now() / 1e3 > r.exp - i;
36
+ }
37
+ let We = !1;
38
+ const sn = [
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 on(t) {
57
+ return sn.some((i) => t.includes(i));
58
+ }
59
+ function Xe(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 i = window.location.pathname + window.location.search, r = encodeURIComponent(i);
68
+ window.location.href = `/login?redirect=${r}`;
69
+ }
70
+ function cn(t) {
71
+ if (t && typeof t == "object" && "code" in t && "data" in t) {
72
+ const i = t;
73
+ return (typeof i.success == "boolean" ? i.success : typeof i.code == "number" && i.code >= 200 && i.code < 300) ? i.data : Promise.reject(new Error(i.message || "请求失败"));
74
+ }
75
+ return t;
76
+ }
77
+ function dn(t, i = {}) {
78
+ const { tokenKey: r = "token", userInfoKey: S = "userInfo" } = i;
79
+ t.interceptors.request.use((l) => {
80
+ const y = localStorage.getItem(r);
81
+ if (y && ln(y))
82
+ return Xe(`请求前检测到 token 已过期 (${l.url || ""})`), Promise.reject(new He.CanceledError("token expired"));
83
+ try {
84
+ const c = localStorage.getItem(S);
85
+ if (c) {
86
+ const f = JSON.parse(c), x = f.tenantCode || "default", C = f.domainCode || "default", _ = f.id ?? f.userId, h = (l.method || "get").toLowerCase();
87
+ if (typeof l.url == "string" && l.url.includes("/ctc/ac/") && (l.params = { ...l.params || {} }, l.params.tenantCode || (l.params.tenantCode = x), l.params.domainCode || (l.params.domainCode = C)), _ != null && (l.headers["X-User-Id"] = String(_)), h !== "get" && h !== "delete" && l.data && typeof l.data == "object") {
88
+ const a = l.data;
89
+ a.tenantCode == null && (a.tenantCode = x), a.domainCode == null && (a.domainCode = C);
90
+ }
91
+ }
92
+ } catch {
93
+ }
94
+ return l;
95
+ }), t.interceptors.response.use(
96
+ (l) => cn(l.data),
97
+ (l) => {
98
+ var f, x;
99
+ const y = (f = l.response) == null ? void 0 : f.status, c = ((x = l.config) == null ? void 0 : x.url) || "";
100
+ return y === 401 ? on(c) ? console.warn(`[401] 公开接口返回 401 (不是 token 问题): ${c}`) : Xe(`接口 ${c} 返回 401`) : y === 403 ? console.warn("[403] 没有权限访问该资源:", c) : y === 404 ? console.warn("[404] 接口不存在:", c) : y === 500 && console.error("[500] 服务器内部错误:", c), Promise.reject(l);
101
+ }
102
+ );
103
+ }
104
+ function Ge(t = {}) {
105
+ const i = He.create({
106
+ baseURL: t.baseURL ?? "/api",
107
+ timeout: t.timeout ?? 1e4,
108
+ withCredentials: !0
109
+ // Cookie 模式:浏览器自动携带 Cookie
110
+ });
111
+ return dn(i, {
112
+ tokenKey: t.tokenKey,
113
+ userInfoKey: t.userInfoKey
114
+ }), i;
115
+ }
116
+ const $ = Ge(), er = Ge(), Ce = 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, un = [
117
+ {
118
+ key: "ai",
119
+ color: "violet",
120
+ title: "智能中心",
121
+ subtitle: "Agent · 模型 · MCP · 技能",
122
+ icon: /* @__PURE__ */ e($e, {}),
123
+ href: "/ai/agent/app",
124
+ items: [
125
+ {
126
+ title: "Agent 应用",
127
+ description: "创建和管理 AI Agent 应用, 支持多种 LLM 模型",
128
+ icon: /* @__PURE__ */ e($e, {}),
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(qe, {}),
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(Pe, {}),
165
+ href: "/task/dashboard",
166
+ items: [
167
+ {
168
+ title: "任务仪表盘",
169
+ description: "实时任务执行情况, 成功率与时长统计",
170
+ icon: /* @__PURE__ */ e(At, {}),
171
+ color: "green",
172
+ tags: [{ label: "看板", color: "green" }]
173
+ },
174
+ {
175
+ title: "任务列表",
176
+ description: "所有定时/手动任务, 支持 Cron 表达式",
177
+ icon: /* @__PURE__ */ e(_t, {}),
178
+ color: "blue",
179
+ tags: [{ label: "调度", color: "blue" }]
180
+ },
181
+ {
182
+ title: "项目管理",
183
+ description: "项目维度组织任务, 支持里程碑",
184
+ icon: /* @__PURE__ */ e(Pe, {}),
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(De, {}),
196
+ href: "/workflow/dashboard",
197
+ items: [
198
+ {
199
+ title: "流程仪表盘",
200
+ description: "流程实例统计与效率分析",
201
+ icon: /* @__PURE__ */ e(De, {}),
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
+ ], tr = () => {
215
+ const [t, i] = m({
216
+ configCount: null,
217
+ projectCount: null,
218
+ userCount: null,
219
+ roleCount: null
220
+ });
221
+ return F(() => {
222
+ let r = !0;
223
+ const S = [
224
+ Ce.get("/config/list", { params: { pageSize: 1 } }).then((l) => ve(l)).then((l) => r && i((y) => ({ ...y, configCount: l }))).catch(() => r && i((l) => ({ ...l, configCount: 0 }))),
225
+ Ce.get("/project/user/list").then((l) => ve(l)).then((l) => r && i((y) => ({ ...y, projectCount: l }))).catch(() => r && i((l) => ({ ...l, projectCount: 0 }))),
226
+ Ce.get("/ctc/ac/accounts", { params: { pageSize: 1 } }).then((l) => ve(l)).then((l) => r && i((y) => ({ ...y, userCount: l }))).catch(() => r && i((l) => ({ ...l, userCount: 0 }))),
227
+ Ce.get("/ctc/authz/roles/list").then((l) => ve(l)).then((l) => r && i((y) => ({ ...y, roleCount: l }))).catch(() => r && i((l) => ({ ...l, roleCount: 0 })))
228
+ ];
229
+ return () => {
230
+ r = !1, S.forEach((l) => {
231
+ var y;
232
+ return (y = l == null ? void 0 : l.catch) == null ? void 0 : y.call(l, () => {
233
+ });
234
+ });
235
+ };
236
+ }, []), /* @__PURE__ */ n("div", { children: [
237
+ /* @__PURE__ */ e(
238
+ ye,
239
+ {
240
+ title: "统一管理平台",
241
+ subtitle: "一站式企业级应用管理平台 · 整合配置 / 任务 / 工作流 / 用户 / 调度 等核心模块",
242
+ breadcrumb: [{ label: "首页" }]
243
+ }
244
+ ),
245
+ /* @__PURE__ */ n(Y, { gutter: [16, 16], children: [
246
+ /* @__PURE__ */ e(O, { xs: 24, sm: 12, md: 12, lg: 6, children: /* @__PURE__ */ e(
247
+ Te,
248
+ {
249
+ icon: /* @__PURE__ */ e(Ct, {}),
250
+ label: "配置中心",
251
+ value: t.configCount,
252
+ suffix: "条",
253
+ color: "violet",
254
+ trend: 12.5,
255
+ href: "/config/list"
256
+ }
257
+ ) }),
258
+ /* @__PURE__ */ e(O, { xs: 24, sm: 12, md: 12, lg: 6, children: /* @__PURE__ */ e(
259
+ Te,
260
+ {
261
+ icon: /* @__PURE__ */ e(Pe, {}),
262
+ label: "我的项目",
263
+ value: t.projectCount,
264
+ suffix: "个",
265
+ color: "blue",
266
+ trend: 8.3,
267
+ href: "/project/list"
268
+ }
269
+ ) }),
270
+ /* @__PURE__ */ e(O, { xs: 24, sm: 12, md: 12, lg: 6, children: /* @__PURE__ */ e(
271
+ Te,
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(O, { xs: 24, sm: 12, md: 12, lg: 6, children: /* @__PURE__ */ e(
283
+ Te,
284
+ {
285
+ icon: /* @__PURE__ */ e(De, {}),
286
+ label: "角色数",
287
+ value: t.roleCount,
288
+ suffix: "个",
289
+ color: "orange",
290
+ trend: 4.7,
291
+ href: "/ctc/4a/role"
292
+ }
293
+ ) })
294
+ ] }),
295
+ un.map((r) => /* @__PURE__ */ n("div", { style: { marginBottom: 32 }, children: [
296
+ /* @__PURE__ */ e(
297
+ Ut,
298
+ {
299
+ color: r.color,
300
+ title: r.title,
301
+ subtitle: r.subtitle,
302
+ moreHref: r.href
303
+ }
304
+ ),
305
+ /* @__PURE__ */ e(Y, { gutter: [16, 16], children: r.items.map((S, l) => /* @__PURE__ */ e(
306
+ O,
307
+ {
308
+ xs: 24,
309
+ sm: 12,
310
+ md: 12,
311
+ lg: 6,
312
+ xl: 6,
313
+ xxl: 6,
314
+ children: /* @__PURE__ */ e(
315
+ qt,
316
+ {
317
+ title: S.title,
318
+ description: S.description,
319
+ icon: S.icon,
320
+ color: S.color,
321
+ tags: S.tags,
322
+ meta: S.meta,
323
+ href: r.href
324
+ }
325
+ )
326
+ },
327
+ l
328
+ )) })
329
+ ] }, r.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 pn = "/api";
343
+ function bt() {
344
+ return He.create({ baseURL: pn, timeout: 15e3, withCredentials: !0 });
345
+ }
346
+ const Ie = bt(), hn = bt();
347
+ hn.interceptors.request.use((t) => t);
348
+ Ie.interceptors.request.use((t) => t);
349
+ const ze = "/mock-platform", G = (t, i) => Ie.get(`${ze}${t}`, { params: i }).then((r) => r.data), q = (t, i, r) => Ie.post(`${ze}${t}`, i, { params: r }).then((S) => S.data), Ae = (t, i, r) => Ie.put(`${ze}${t}`, i, { params: r }).then((S) => S.data), ce = (t, i) => Ie.delete(`${ze}${t}`, { params: i }).then((r) => r.data), j = {
350
+ stats: () => G("/stats"),
351
+ environments: {
352
+ list: () => G("/environments/list"),
353
+ create: (t) => q("/environments", t),
354
+ update: (t, i) => Ae("/environments", i, { envCode: t }),
355
+ delete: (t) => ce("/environments", { envCode: t })
356
+ },
357
+ endpoints: {
358
+ list: (t, i, r) => G("/endpoints/list", { envCode: t, scenarioCode: i, status: r }),
359
+ get: (t) => G("/endpoints/byCode", { mockCode: t }),
360
+ create: (t) => q("/endpoints", t),
361
+ update: (t, i) => Ae("/endpoints", i, { mockCode: t }),
362
+ delete: (t) => ce("/endpoints", { mockCode: t }),
363
+ toggle: (t, i) => q("/endpoints/toggle", null, { mockCode: t, status: i })
364
+ },
365
+ scenarios: {
366
+ list: () => G("/scenarios/list"),
367
+ get: (t) => G("/scenarios/byCode", { scenarioCode: t }),
368
+ create: (t) => q("/scenarios", t),
369
+ update: (t, i) => Ae("/scenarios", i, { scenarioCode: t }),
370
+ delete: (t) => ce("/scenarios", { scenarioCode: t }),
371
+ reset: (t) => q("/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) => q("/cases", t),
378
+ update: (t, i) => Ae("/cases", i, { caseCode: t }),
379
+ delete: (t) => ce("/cases", { caseCode: t }),
380
+ run: (t) => q("/cases/run", null, { caseCode: t }),
381
+ runBatch: (t) => q("/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, i, r) => q("/recordings/start", {
388
+ recordingCode: t,
389
+ recordingName: i,
390
+ targetUrl: r
391
+ }),
392
+ stop: (t) => q("/recordings/stop", null, { recordingCode: t }),
393
+ export: (t, i) => q("/recordings/export", { recordingCode: t, projectCode: i }),
394
+ import: (t, i) => q("/recordings/import", { recordingCode: t, projectCode: i }),
395
+ playback: (t, i) => q("/recordings/playback", { recordingCode: t, targetUrl: i }),
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) => q("/curl/parse", { curlText: t }),
405
+ run: (t) => q("/curl/run", { curlText: t }),
406
+ importAsCase: (t) => q("/curl/import-as-case", t),
407
+ importAsEndpoint: (t) => q("/curl/import-as-endpoint", t)
408
+ },
409
+ openapi: {
410
+ parse: (t) => q("/openapi/parse", { content: t }),
411
+ importBatch: (t) => q("/openapi/import-batch", t),
412
+ sample: (t) => G("/openapi/sample", { format: t })
413
+ }
414
+ }, { Text: le, Paragraph: mn } = ae, Ye = { GET: "green", POST: "blue", PUT: "orange", DELETE: "red", PATCH: "purple" };
415
+ function Be({ activeEnvCode: t }) {
416
+ const [i, r] = m([]), [S, l] = m(!1), [y, c] = m(null), [f, x] = m(!1), [C, _] = m(null);
417
+ F(() => {
418
+ h();
419
+ }, [t]);
420
+ const h = async () => {
421
+ l(!0), c(null);
422
+ try {
423
+ const g = await j.endpoints.list(t);
424
+ r(Array.isArray(g) ? g : []);
425
+ } catch (g) {
426
+ c((g == null ? void 0 : g.message) || "API unavailable"), r([]);
427
+ } finally {
428
+ l(!1);
429
+ }
430
+ }, a = (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__ */ n(E, { children: [
437
+ /* @__PURE__ */ e(w, { color: Ye[v.method] || "default", children: v.method }),
438
+ /* @__PURE__ */ e(le, { 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__ */ n(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__ */ n(le, { type: "warning", children: [
461
+ g,
462
+ "ms"
463
+ ] }) : /* @__PURE__ */ e(le, { 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(le, { 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(le, { 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(le, { 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__ */ n(E, { size: "small", children: [
501
+ /* @__PURE__ */ e(he, { title: "预览响应", children: /* @__PURE__ */ e(
502
+ A,
503
+ {
504
+ size: "small",
505
+ type: "link",
506
+ icon: /* @__PURE__ */ e(Ee, {}),
507
+ onClick: () => {
508
+ _(v), x(!0);
509
+ },
510
+ children: "预览"
511
+ }
512
+ ) }),
513
+ /* @__PURE__ */ e(he, { title: "复制URL", children: /* @__PURE__ */ e(
514
+ A,
515
+ {
516
+ size: "small",
517
+ type: "link",
518
+ icon: /* @__PURE__ */ e(pt, {}),
519
+ onClick: () => {
520
+ navigator.clipboard.writeText(a(v)), b.success("已复制");
521
+ }
522
+ }
523
+ ) })
524
+ ] })
525
+ }
526
+ ];
527
+ return /* @__PURE__ */ n("div", { children: [
528
+ y && /* @__PURE__ */ e(
529
+ Z,
530
+ {
531
+ type: "warning",
532
+ showIcon: !0,
533
+ style: { marginBottom: 16 },
534
+ title: "后端 API 暂未连接",
535
+ description: y
536
+ }
537
+ ),
538
+ /* @__PURE__ */ n(Y, { gutter: 16, style: { marginBottom: 16 }, children: [
539
+ /* @__PURE__ */ e(O, { span: 6, children: /* @__PURE__ */ n(L, { children: [
540
+ /* @__PURE__ */ e("strong", { children: "总端点" }),
541
+ /* @__PURE__ */ e("div", { style: { fontSize: 22 }, children: i.length })
542
+ ] }) }),
543
+ /* @__PURE__ */ e(O, { span: 6, children: /* @__PURE__ */ n(L, { children: [
544
+ /* @__PURE__ */ e("strong", { children: "已启用" }),
545
+ /* @__PURE__ */ e("div", { style: { fontSize: 22, color: "#52c41a" }, children: i.filter((g) => g.status === 1).length })
546
+ ] }) }),
547
+ /* @__PURE__ */ e(O, { span: 6, children: /* @__PURE__ */ n(L, { children: [
548
+ /* @__PURE__ */ e("strong", { children: "已禁用" }),
549
+ /* @__PURE__ */ e("div", { style: { fontSize: 22, color: "#ff4d4f" }, children: i.filter((g) => g.status === 0).length })
550
+ ] }) }),
551
+ /* @__PURE__ */ e(O, { span: 6, children: /* @__PURE__ */ n(L, { children: [
552
+ /* @__PURE__ */ e("strong", { children: "总命中" }),
553
+ /* @__PURE__ */ e("div", { style: {
554
+ fontSize: 22,
555
+ color: "#1890ff"
556
+ }, children: i.reduce((g, v) => g + (v.hit_count || 0), 0) })
557
+ ] }) })
558
+ ] }),
559
+ /* @__PURE__ */ e(E, { style: { marginBottom: 16 }, children: /* @__PURE__ */ e(A, { icon: /* @__PURE__ */ e(ee, {}), onClick: h, children: "刷新" }) }),
560
+ /* @__PURE__ */ e(
561
+ Q,
562
+ {
563
+ dataSource: i,
564
+ columns: d,
565
+ rowKey: "id",
566
+ loading: S,
567
+ pagination: { pageSize: 10 },
568
+ scroll: { x: 1300 },
569
+ size: "small"
570
+ }
571
+ ),
572
+ /* @__PURE__ */ e(
573
+ we,
574
+ {
575
+ title: /* @__PURE__ */ n(E, { children: [
576
+ /* @__PURE__ */ e(Pt, {}),
577
+ "端点详情: ",
578
+ C == null ? void 0 : C.mock_code
579
+ ] }),
580
+ open: f,
581
+ onClose: () => x(!1),
582
+ size: "large",
583
+ children: C && /* @__PURE__ */ n("div", { children: [
584
+ /* @__PURE__ */ n(z, { column: 2, size: "small", bordered: !0, style: { marginBottom: 16 }, children: [
585
+ /* @__PURE__ */ e(z.Item, { label: "编码", children: C.mock_code }),
586
+ /* @__PURE__ */ e(z.Item, { label: "名称", children: C.mock_name }),
587
+ /* @__PURE__ */ e(z.Item, { label: "方法", children: /* @__PURE__ */ e(w, { color: Ye[C.method], children: C.method }) }),
588
+ /* @__PURE__ */ e(z.Item, { label: "环境", children: C.env_code }),
589
+ /* @__PURE__ */ e(z.Item, { label: "路径", span: 2, children: C.path }),
590
+ /* @__PURE__ */ e(z.Item, { label: "状态码", children: C.status_code }),
591
+ /* @__PURE__ */ n(z.Item, { label: "延迟", children: [
592
+ C.delay_ms,
593
+ "ms"
594
+ ] }),
595
+ /* @__PURE__ */ n(z.Item, { label: "优先级", children: [
596
+ "P",
597
+ C.priority
598
+ ] }),
599
+ /* @__PURE__ */ e(z.Item, { label: "命中", children: C.hit_count || 0 }),
600
+ /* @__PURE__ */ e(z.Item, { label: "故障", children: C.fault_type && C.fault_type !== "NONE" ? /* @__PURE__ */ e(w, { color: "red", children: C.fault_type }) : /* @__PURE__ */ e(le, { type: "secondary", children: "-" }) }),
601
+ /* @__PURE__ */ e(z.Item, { label: "场景", children: C.scenario_code || "-" }),
602
+ /* @__PURE__ */ e(z.Item, { label: "状态", span: 2, children: C.status === 1 ? /* @__PURE__ */ e(w, { color: "green", children: "启用" }) : /* @__PURE__ */ e(w, { children: "禁用" }) }),
603
+ /* @__PURE__ */ e(z.Item, { label: "完整 URL", span: 2, children: /* @__PURE__ */ e(le, { copyable: !0, children: a(C) }) })
604
+ ] }),
605
+ /* @__PURE__ */ e(mn, { 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: C.response_template })
617
+ ] })
618
+ }
619
+ )
620
+ ] });
621
+ }
622
+ const { Text: Oe } = ae, yn = { MOCK: "green", REAL: "blue", MIXED: "orange" };
623
+ function je({ onEnvChange: t }) {
624
+ const [i, r] = m([]), [S, l] = m(!1);
625
+ F(() => {
626
+ y();
627
+ }, []);
628
+ const y = async () => {
629
+ l(!0);
630
+ try {
631
+ const f = await j.environments.list();
632
+ r(Array.isArray(f) ? f : []);
633
+ } catch (f) {
634
+ b.warning("加载环境列表失败: " + (f == null ? void 0 : f.message));
635
+ } finally {
636
+ l(!1);
637
+ }
638
+ };
639
+ return /* @__PURE__ */ n("div", { children: [
640
+ /* @__PURE__ */ e(
641
+ Z,
642
+ {
643
+ type: "info",
644
+ showIcon: !0,
645
+ style: { marginBottom: 16 },
646
+ message: "环境隔离 - 控制 Mock 与真实服务的切换",
647
+ description: /* @__PURE__ */ n("div", { children: [
648
+ /* @__PURE__ */ n("div", { children: [
649
+ /* @__PURE__ */ e(w, { color: "green", children: "MOCK" }),
650
+ " 完全拦截,仅返回 Mock 数据"
651
+ ] }),
652
+ /* @__PURE__ */ n("div", { children: [
653
+ /* @__PURE__ */ e(w, { color: "blue", children: "REAL" }),
654
+ " 全部代理到 base_url(适合压测、回归测试)"
655
+ ] }),
656
+ /* @__PURE__ */ n("div", { children: [
657
+ /* @__PURE__ */ e(w, { color: "orange", children: "MIXED" }),
658
+ " Mock 优先,未匹配时转发到 base_url(开发联调)"
659
+ ] })
660
+ ] })
661
+ }
662
+ ),
663
+ /* @__PURE__ */ e(E, { style: { marginBottom: 16 }, children: /* @__PURE__ */ e(A, { icon: /* @__PURE__ */ e(ee, {}), onClick: y, children: "刷新" }) }),
664
+ /* @__PURE__ */ e(
665
+ Q,
666
+ {
667
+ dataSource: i,
668
+ columns: [
669
+ {
670
+ title: "环境编码",
671
+ dataIndex: "env_code",
672
+ key: "env_code",
673
+ width: 140,
674
+ render: (f) => /* @__PURE__ */ e(Oe, { 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: yn[f] || "default", children: f })
683
+ },
684
+ {
685
+ title: "真实服务地址",
686
+ dataIndex: "base_url",
687
+ key: "base_url",
688
+ render: (f) => f ? /* @__PURE__ */ e(Oe, { copyable: !0, children: f }) : /* @__PURE__ */ e(Oe, { 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(E, { size: "small", children: /* @__PURE__ */ e(
710
+ A,
711
+ {
712
+ size: "small",
713
+ type: "link",
714
+ icon: /* @__PURE__ */ e(ht, {}),
715
+ onClick: () => {
716
+ t && t(x.env_code);
717
+ },
718
+ children: "切换"
719
+ }
720
+ ) })
721
+ }
722
+ ],
723
+ rowKey: "id",
724
+ loading: S,
725
+ pagination: { pageSize: 10 },
726
+ size: "small"
727
+ }
728
+ )
729
+ ] });
730
+ }
731
+ const { Text: gn } = ae;
732
+ function fn() {
733
+ const [t, i] = m([]), [r, S] = m(!1), [l, y] = m(!1), [c, f] = m(null);
734
+ F(() => {
735
+ x();
736
+ }, []);
737
+ const x = async () => {
738
+ S(!0);
739
+ try {
740
+ const a = await j.scenarios.list();
741
+ i(Array.isArray(a) ? a : []);
742
+ } catch {
743
+ b.warning("加载场景列表失败");
744
+ } finally {
745
+ S(!1);
746
+ }
747
+ }, C = async (a) => {
748
+ try {
749
+ await j.scenarios.reset(a), b.success("已重置所有实例状态");
750
+ } catch {
751
+ b.error("重置失败");
752
+ }
753
+ }, _ = async (a) => {
754
+ try {
755
+ const d = await j.scenarios.instances(a);
756
+ f({ code: a, list: d }), y(!0);
757
+ } catch {
758
+ b.error("加载失败");
759
+ }
760
+ };
761
+ return /* @__PURE__ */ n("div", { children: [
762
+ /* @__PURE__ */ e(
763
+ Z,
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(E, { style: { marginBottom: 16 }, children: /* @__PURE__ */ e(A, { 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: (a) => /* @__PURE__ */ e(gn, { code: !0, children: a })
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: (a) => /* @__PURE__ */ e(w, { color: "blue", children: a })
792
+ },
793
+ {
794
+ title: "描述",
795
+ dataIndex: "description",
796
+ key: "description",
797
+ width: 240,
798
+ render: (a) => a || "-"
799
+ },
800
+ {
801
+ title: "操作",
802
+ key: "action",
803
+ width: 200,
804
+ fixed: "right",
805
+ render: (a, d) => /* @__PURE__ */ n(E, { size: "small", children: [
806
+ /* @__PURE__ */ e(
807
+ A,
808
+ {
809
+ size: "small",
810
+ type: "link",
811
+ icon: /* @__PURE__ */ e(Et, {}),
812
+ onClick: () => _(d.scenario_code),
813
+ children: "实例"
814
+ }
815
+ ),
816
+ /* @__PURE__ */ e(
817
+ A,
818
+ {
819
+ size: "small",
820
+ type: "link",
821
+ icon: /* @__PURE__ */ e(zt, {}),
822
+ onClick: () => C(d.scenario_code),
823
+ children: "重置"
824
+ }
825
+ )
826
+ ] })
827
+ }
828
+ ],
829
+ rowKey: "id",
830
+ loading: r,
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: l,
841
+ onCancel: () => y(!1),
842
+ footer: /* @__PURE__ */ e(A, { 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: (a) => /* @__PURE__ */ e(w, { color: "blue", children: a })
855
+ },
856
+ { title: "最后变更", dataIndex: "update_time", key: "update_time" }
857
+ ],
858
+ rowKey: (a, d) => a.instance_key || d,
859
+ pagination: !1,
860
+ size: "small"
861
+ }
862
+ )
863
+ }
864
+ )
865
+ ] });
866
+ }
867
+ const { Text: ie } = ae, Le = { PASS: "green", FAIL: "red", SKIP: "default" }, bn = { P0: "red", P1: "orange", P2: "blue", P3: "default" };
868
+ function xn() {
869
+ const [t, i] = m([]), [r, S] = m(!1), [l, y] = m([]), [c, f] = m(!1), [x, C] = m(null), [_, h] = m(null), [a, d] = m(!1);
870
+ F(() => {
871
+ g();
872
+ }, []);
873
+ const g = async () => {
874
+ S(!0);
875
+ try {
876
+ const u = await j.cases.list();
877
+ i(Array.isArray(u) ? u : []);
878
+ } catch {
879
+ b.warning("加载用例列表失败");
880
+ } finally {
881
+ S(!1);
882
+ }
883
+ }, v = async (u) => {
884
+ try {
885
+ const s = await j.cases.run(u.case_code);
886
+ C(s), f(!0), (s == null ? void 0 : s.status) === "PASS" ? b.success("用例通过") : b.error("用例失败: " + ((s == null ? void 0 : s.error) || (s == null ? void 0 : s.actualStatus))), g();
887
+ } catch (s) {
888
+ b.error("执行失败: " + (s == null ? void 0 : s.message));
889
+ }
890
+ }, D = async () => {
891
+ if (l.length === 0) {
892
+ b.warning("请先选择用例");
893
+ return;
894
+ }
895
+ try {
896
+ const u = await j.cases.runBatch(l);
897
+ h(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
+ }, T = [
902
+ {
903
+ title: "用例编码",
904
+ dataIndex: "case_code",
905
+ key: "case_code",
906
+ width: 180,
907
+ render: (u) => /* @__PURE__ */ e(ie, { 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(ie, { 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: bn[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: Le[u], children: u }) : "-"
946
+ },
947
+ {
948
+ title: "统计",
949
+ key: "stats",
950
+ width: 130,
951
+ align: "center",
952
+ render: (u, s) => /* @__PURE__ */ n(E, { size: "small", children: [
953
+ /* @__PURE__ */ e(ie, { type: "success", children: s.pass_count || 0 }),
954
+ "/",
955
+ /* @__PURE__ */ e(ie, { type: "danger", children: s.fail_count || 0 }),
956
+ /* @__PURE__ */ n(ie, { type: "secondary", children: [
957
+ "(",
958
+ s.run_count || 0,
959
+ ")"
960
+ ] })
961
+ ] })
962
+ },
963
+ {
964
+ title: "操作",
965
+ key: "action",
966
+ width: 120,
967
+ fixed: "right",
968
+ render: (u, s) => /* @__PURE__ */ e(E, { size: "small", children: /* @__PURE__ */ e(
969
+ A,
970
+ {
971
+ size: "small",
972
+ type: "link",
973
+ icon: /* @__PURE__ */ e(Ee, {}),
974
+ onClick: () => v(s),
975
+ children: "运行"
976
+ }
977
+ ) })
978
+ }
979
+ ];
980
+ return /* @__PURE__ */ n("div", { children: [
981
+ /* @__PURE__ */ e(
982
+ Z,
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__ */ n(E, { style: { marginBottom: 16 }, children: [
992
+ /* @__PURE__ */ e(A, { icon: /* @__PURE__ */ e(ee, {}), onClick: g, children: "刷新" }),
993
+ /* @__PURE__ */ n(
994
+ A,
995
+ {
996
+ type: "primary",
997
+ icon: /* @__PURE__ */ e(Ee, {}),
998
+ onClick: D,
999
+ disabled: l.length === 0,
1000
+ children: [
1001
+ "批量运行 (",
1002
+ l.length,
1003
+ ")"
1004
+ ]
1005
+ }
1006
+ )
1007
+ ] }),
1008
+ /* @__PURE__ */ e(
1009
+ Q,
1010
+ {
1011
+ dataSource: t,
1012
+ columns: T,
1013
+ rowKey: "id",
1014
+ loading: r,
1015
+ rowSelection: {
1016
+ selectedRowKeys: l,
1017
+ // 批量执行收的是 **case_code 列表**(后端按 case_code 查行),
1018
+ // 原来这里存的是 rowKey(=id) ⇒ 批量执行永远查不到行。
1019
+ onChange: (u, s) => y(s.map((I) => I.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__ */ n(E, { children: [
1030
+ /* @__PURE__ */ e(Rt, {}),
1031
+ "用例执行结果"
1032
+ ] }),
1033
+ open: c,
1034
+ onClose: () => f(!1),
1035
+ size: "large",
1036
+ children: x && /* @__PURE__ */ n("div", { children: [
1037
+ /* @__PURE__ */ n(Y, { gutter: 16, style: { marginBottom: 16 }, children: [
1038
+ /* @__PURE__ */ e(O, { span: 8, children: /* @__PURE__ */ e(L, { children: /* @__PURE__ */ e(
1039
+ K,
1040
+ {
1041
+ title: "结果",
1042
+ value: x.status,
1043
+ styles: { content: { color: Le[x.status] === "green" ? "#52c41a" : "#ff4d4f" } }
1044
+ }
1045
+ ) }) }),
1046
+ /* @__PURE__ */ e(O, { span: 8, children: /* @__PURE__ */ e(L, { children: /* @__PURE__ */ e(K, { title: "实际状态码", value: x.actualStatus || "-" }) }) }),
1047
+ /* @__PURE__ */ e(O, { span: 8, children: /* @__PURE__ */ e(L, { children: /* @__PURE__ */ e(K, { title: "耗时(ms)", value: x.durationMs || 0 }) }) })
1048
+ ] }),
1049
+ /* @__PURE__ */ n(z, { column: 1, size: "small", bordered: !0, style: { marginBottom: 16 }, children: [
1050
+ /* @__PURE__ */ e(z.Item, { label: "用例编码", children: x.caseCode }),
1051
+ /* @__PURE__ */ e(z.Item, { label: "用例名称", children: x.caseName }),
1052
+ /* @__PURE__ */ e(z.Item, { label: "错误信息", children: x.error || "-" })
1053
+ ] }),
1054
+ x.assertionResults && /* @__PURE__ */ n(Me, { children: [
1055
+ /* @__PURE__ */ e(ie, { 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(ie, { 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: `批量执行结果 (${(_ == null ? void 0 : _.total) || 0} 条)`,
1098
+ open: a,
1099
+ onCancel: () => d(!1),
1100
+ footer: /* @__PURE__ */ e(A, { onClick: () => d(!1), children: "关闭" }),
1101
+ size: "large",
1102
+ children: _ && /* @__PURE__ */ n(Me, { children: [
1103
+ /* @__PURE__ */ n(Y, { gutter: 16, style: { marginBottom: 16 }, children: [
1104
+ /* @__PURE__ */ e(O, { span: 6, children: /* @__PURE__ */ e(L, { children: /* @__PURE__ */ e(K, { title: "总数", value: _.total }) }) }),
1105
+ /* @__PURE__ */ e(O, { span: 6, children: /* @__PURE__ */ e(L, { children: /* @__PURE__ */ e(
1106
+ K,
1107
+ {
1108
+ title: "通过",
1109
+ value: _.pass,
1110
+ styles: { content: { color: "#52c41a" } }
1111
+ }
1112
+ ) }) }),
1113
+ /* @__PURE__ */ e(O, { span: 6, children: /* @__PURE__ */ e(L, { children: /* @__PURE__ */ e(
1114
+ K,
1115
+ {
1116
+ title: "失败",
1117
+ value: _.fail,
1118
+ styles: { content: { color: "#ff4d4f" } }
1119
+ }
1120
+ ) }) }),
1121
+ /* @__PURE__ */ e(O, { span: 6, children: /* @__PURE__ */ e(L, { children: /* @__PURE__ */ e(
1122
+ K,
1123
+ {
1124
+ title: "通过率",
1125
+ value: `${_.total > 0 ? Math.round(_.pass / _.total * 100) : 0}%`
1126
+ }
1127
+ ) }) })
1128
+ ] }),
1129
+ /* @__PURE__ */ e(
1130
+ Q,
1131
+ {
1132
+ dataSource: _.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: Le[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 } = ae, Qe = {
1157
+ IDLE: "default",
1158
+ RECORDING: "red",
1159
+ STOPPED: "green",
1160
+ EXPIRED: "gray"
1161
+ };
1162
+ function wn() {
1163
+ const [t, i] = m([]), [r, S] = m(!1), [l, y] = m(!1), [c, f] = m(null), [x, C] = m([]);
1164
+ F(() => {
1165
+ _();
1166
+ }, []);
1167
+ const _ = async () => {
1168
+ S(!0);
1169
+ try {
1170
+ const d = await j.recordings.list();
1171
+ i(Array.isArray(d) ? d : []);
1172
+ } catch {
1173
+ b.warning("加载录制列表失败");
1174
+ } finally {
1175
+ S(!1);
1176
+ }
1177
+ }, h = async (d) => {
1178
+ try {
1179
+ const g = await j.recordings.requests(d.recording_code);
1180
+ f(d), C(Array.isArray(g) ? g : []), y(!0);
1181
+ } catch {
1182
+ b.error("加载失败");
1183
+ }
1184
+ };
1185
+ return /* @__PURE__ */ n("div", { children: [
1186
+ /* @__PURE__ */ e(
1187
+ Z,
1188
+ {
1189
+ type: "info",
1190
+ showIcon: !0,
1191
+ style: { marginBottom: 16 },
1192
+ message: "流量录制与回放",
1193
+ description: /* @__PURE__ */ n("div", { children: [
1194
+ /* @__PURE__ */ n("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(E, { style: { marginBottom: 16 }, children: /* @__PURE__ */ e(A, { icon: /* @__PURE__ */ e(ee, {}), onClick: _, 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(E, { size: "small", children: /* @__PURE__ */ e(
1247
+ A,
1248
+ {
1249
+ size: "small",
1250
+ type: "link",
1251
+ icon: /* @__PURE__ */ e(Je, {}),
1252
+ onClick: () => h(g),
1253
+ children: "详情"
1254
+ }
1255
+ ) })
1256
+ }
1257
+ ],
1258
+ rowKey: "id",
1259
+ loading: r,
1260
+ pagination: { pageSize: 10 },
1261
+ scroll: { x: 1300 },
1262
+ size: "small"
1263
+ }
1264
+ ),
1265
+ /* @__PURE__ */ e(
1266
+ we,
1267
+ {
1268
+ title: /* @__PURE__ */ n(E, { children: [
1269
+ /* @__PURE__ */ e(Je, {}),
1270
+ "录制详情: ",
1271
+ c == null ? void 0 : c.recording_code
1272
+ ] }),
1273
+ open: l,
1274
+ onClose: () => y(!1),
1275
+ size: "large",
1276
+ children: c && /* @__PURE__ */ n("div", { children: [
1277
+ /* @__PURE__ */ n(z, { column: 2, size: "small", bordered: !0, style: { marginBottom: 16 }, children: [
1278
+ /* @__PURE__ */ e(z.Item, { label: "编码", children: c.recording_code }),
1279
+ /* @__PURE__ */ e(z.Item, { label: "名称", children: c.recording_name }),
1280
+ /* @__PURE__ */ e(z.Item, { label: "状态", children: /* @__PURE__ */ e(w, { color: Qe[c.record_status], children: c.record_status }) }),
1281
+ /* @__PURE__ */ e(z.Item, { label: "请求数", children: c.total_requests }),
1282
+ /* @__PURE__ */ e(z.Item, { label: "目标 URL", span: 2, children: /* @__PURE__ */ e(de, { copyable: !0, children: c.target_url }) }),
1283
+ /* @__PURE__ */ e(z.Item, { label: "开始", children: c.start_time }),
1284
+ /* @__PURE__ */ e(z.Item, { label: "结束", children: c.end_time || "(录制中)" })
1285
+ ] }),
1286
+ /* @__PURE__ */ n(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 } = ae, kn = { MOCK: "green", PROXY: "blue", 404: "red", 502: "orange" };
1338
+ function In() {
1339
+ const [t, i] = m([]), [r, S] = m(null), [l, y] = m(!1), [c, f] = m(null), [x, C] = m(!1), [_, h] = m(""), [a, d] = m();
1340
+ F(() => {
1341
+ g();
1342
+ }, []);
1343
+ const g = async () => {
1344
+ y(!0);
1345
+ try {
1346
+ const [T, u] = await Promise.all([
1347
+ j.requestLogs.list({
1348
+ path: _ || void 0,
1349
+ matched: a,
1350
+ limit: 100
1351
+ }),
1352
+ j.requestLogs.stats().catch(() => null)
1353
+ ]);
1354
+ i(Array.isArray(T) ? T : []), S(u);
1355
+ } catch {
1356
+ b.warning("加载失败");
1357
+ } finally {
1358
+ y(!1);
1359
+ }
1360
+ }, v = (T) => {
1361
+ f(T), C(!0);
1362
+ }, D = [
1363
+ {
1364
+ title: "时间",
1365
+ dataIndex: "create_time",
1366
+ key: "create_time",
1367
+ width: 170,
1368
+ render: (T) => T ? new Date(T).toLocaleString() : "-"
1369
+ },
1370
+ {
1371
+ title: "环境",
1372
+ dataIndex: "env_code",
1373
+ key: "env_code",
1374
+ width: 100,
1375
+ render: (T) => /* @__PURE__ */ e(w, { children: T })
1376
+ },
1377
+ {
1378
+ title: "方法",
1379
+ dataIndex: "request_method",
1380
+ key: "request_method",
1381
+ width: 80,
1382
+ render: (T) => /* @__PURE__ */ e(w, { color: "blue", children: T })
1383
+ },
1384
+ {
1385
+ title: "路径",
1386
+ dataIndex: "request_path",
1387
+ key: "request_path",
1388
+ ellipsis: !0,
1389
+ render: (T) => /* @__PURE__ */ e(ue, { code: !0, children: T })
1390
+ },
1391
+ {
1392
+ title: "状态",
1393
+ dataIndex: "response_status",
1394
+ key: "response_status",
1395
+ width: 90,
1396
+ align: "center",
1397
+ render: (T) => T ? /* @__PURE__ */ e(w, { color: T >= 400 ? "red" : "green", children: T }) : "-"
1398
+ },
1399
+ {
1400
+ title: "匹配",
1401
+ dataIndex: "matched",
1402
+ key: "matched",
1403
+ width: 90,
1404
+ align: "center",
1405
+ render: (T) => T === 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: (T) => T ? /* @__PURE__ */ e(w, { color: kn[T], children: T }) : "-"
1413
+ },
1414
+ {
1415
+ title: "耗时",
1416
+ dataIndex: "duration_ms",
1417
+ key: "duration_ms",
1418
+ width: 80,
1419
+ align: "center",
1420
+ render: (T) => `${T || 0}ms`
1421
+ },
1422
+ {
1423
+ title: "Mock",
1424
+ dataIndex: "mock_code",
1425
+ key: "mock_code",
1426
+ width: 160,
1427
+ ellipsis: !0,
1428
+ render: (T) => T ? /* @__PURE__ */ e(ue, { code: !0, children: T }) : "-"
1429
+ },
1430
+ {
1431
+ title: "操作",
1432
+ key: "action",
1433
+ width: 80,
1434
+ render: (T, u) => /* @__PURE__ */ e(
1435
+ A,
1436
+ {
1437
+ size: "small",
1438
+ type: "link",
1439
+ icon: /* @__PURE__ */ e(Ot, {}),
1440
+ onClick: () => v(u),
1441
+ children: "详情"
1442
+ }
1443
+ )
1444
+ }
1445
+ ];
1446
+ return /* @__PURE__ */ n("div", { children: [
1447
+ /* @__PURE__ */ e(
1448
+ Z,
1449
+ {
1450
+ type: "info",
1451
+ showIcon: !0,
1452
+ style: { marginBottom: 16 },
1453
+ title: "Mock 请求日志 - 排查未匹配请求",
1454
+ description: "每一次请求都会留痕。包括请求/响应体、是否匹配 Mock、回退类型、耗时、场景状态等。便于排查“为什么这个请求没有 Mock 命中”问题。"
1455
+ }
1456
+ ),
1457
+ r && /* @__PURE__ */ n(Y, { gutter: 16, style: { marginBottom: 16 }, children: [
1458
+ /* @__PURE__ */ e(O, { span: 6, children: /* @__PURE__ */ e(L, { children: /* @__PURE__ */ e(K, { title: "总请求数", value: r.total || 0 }) }) }),
1459
+ /* @__PURE__ */ e(O, { span: 6, children: /* @__PURE__ */ e(L, { children: /* @__PURE__ */ e(
1460
+ K,
1461
+ {
1462
+ title: "Mock 命中",
1463
+ value: r.matched || 0,
1464
+ styles: { content: { color: "#52c41a" } }
1465
+ }
1466
+ ) }) }),
1467
+ /* @__PURE__ */ e(O, { span: 6, children: /* @__PURE__ */ e(L, { children: /* @__PURE__ */ e(
1468
+ K,
1469
+ {
1470
+ title: "未匹配",
1471
+ value: r.unmatched || 0,
1472
+ styles: { content: { color: "#ff4d4f" } }
1473
+ }
1474
+ ) }) }),
1475
+ /* @__PURE__ */ e(O, { span: 6, children: /* @__PURE__ */ e(L, { children: /* @__PURE__ */ e(
1476
+ K,
1477
+ {
1478
+ title: "命中率",
1479
+ value: `${r.total > 0 ? Math.round(r.matched / r.total * 100) : 0}%`
1480
+ }
1481
+ ) }) })
1482
+ ] }),
1483
+ /* @__PURE__ */ n(E, { 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: _,
1492
+ onChange: (T) => h(T.target.value),
1493
+ onPressEnter: g
1494
+ }
1495
+ ),
1496
+ /* @__PURE__ */ e(
1497
+ V,
1498
+ {
1499
+ placeholder: "匹配状态",
1500
+ allowClear: !0,
1501
+ style: { width: 140 },
1502
+ value: a,
1503
+ onChange: d,
1504
+ options: [
1505
+ { value: 1, label: "已命中" },
1506
+ { value: 0, label: "未匹配" }
1507
+ ]
1508
+ }
1509
+ ),
1510
+ /* @__PURE__ */ e(A, { icon: /* @__PURE__ */ e(ee, {}), onClick: g, children: "查询" })
1511
+ ] }),
1512
+ /* @__PURE__ */ e(
1513
+ Q,
1514
+ {
1515
+ dataSource: t,
1516
+ columns: D,
1517
+ rowKey: "id",
1518
+ loading: l,
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: () => C(!1),
1530
+ size: "large",
1531
+ children: c && /* @__PURE__ */ n("div", { children: [
1532
+ /* @__PURE__ */ n(z, { column: 2, size: "small", bordered: !0, style: { marginBottom: 16 }, children: [
1533
+ /* @__PURE__ */ e(z.Item, { label: "环境", children: c.env_code }),
1534
+ /* @__PURE__ */ e(z.Item, { label: "方法", children: /* @__PURE__ */ e(
1535
+ w,
1536
+ {
1537
+ color: "blue",
1538
+ children: c.request_method
1539
+ }
1540
+ ) }),
1541
+ /* @__PURE__ */ e(z.Item, { label: "路径", span: 2, children: /* @__PURE__ */ e(
1542
+ ue,
1543
+ {
1544
+ code: !0,
1545
+ children: c.request_path
1546
+ }
1547
+ ) }),
1548
+ /* @__PURE__ */ e(z.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__ */ n(z.Item, { label: "耗时", children: [
1556
+ c.duration_ms,
1557
+ "ms"
1558
+ ] }),
1559
+ /* @__PURE__ */ e(z.Item, { label: "匹配", children: c.matched === 1 ? /* @__PURE__ */ e(w, { color: "green", children: "命中" }) : /* @__PURE__ */ e(w, { color: "red", children: "未匹配" }) }),
1560
+ /* @__PURE__ */ e(z.Item, { label: "回退", children: c.fallback_type || "-" }),
1561
+ /* @__PURE__ */ e(z.Item, { label: "Mock", span: 2, children: c.mock_code || "-" }),
1562
+ /* @__PURE__ */ e(
1563
+ z.Item,
1564
+ {
1565
+ label: "场景状态",
1566
+ span: 2,
1567
+ children: c.scenario_state || "-"
1568
+ }
1569
+ ),
1570
+ /* @__PURE__ */ e(z.Item, { label: "客户端 IP", children: c.client_ip || "-" }),
1571
+ /* @__PURE__ */ e(z.Item, { label: "User-Agent", ellipsis: !0, children: c.user_agent || "-" }),
1572
+ /* @__PURE__ */ e(z.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 } = ae, et = [
1615
+ { key: "endpoints", label: "Mock 端点", component: Be },
1616
+ { key: "environments", label: "环境 (MOCK/REAL/MIXED)", component: je },
1617
+ { key: "scenarios", label: "场景状态机", component: fn },
1618
+ { key: "cases", label: "测试用例", component: xn },
1619
+ { key: "recordings", label: "录制回放", component: wn },
1620
+ { key: "request-logs", label: "请求日志", component: In }
1621
+ ];
1622
+ function Sn() {
1623
+ var _;
1624
+ const [t, i] = m("endpoints"), [r, S] = m([]), [l, y] = m("default"), [c, f] = m(null);
1625
+ F(() => {
1626
+ x(), C();
1627
+ }, []);
1628
+ const x = async () => {
1629
+ try {
1630
+ const h = await j.environments.list(), a = Array.isArray(h) ? h : [];
1631
+ if (S(a), a.length > 0 && !a.find((d) => d.env_code === l)) {
1632
+ const d = a.find((g) => g.is_default === 1) || a[0];
1633
+ y(d.env_code);
1634
+ }
1635
+ } catch {
1636
+ }
1637
+ }, C = async () => {
1638
+ try {
1639
+ const h = await j.stats();
1640
+ f(h);
1641
+ } catch {
1642
+ }
1643
+ };
1644
+ return (_ = et.find((h) => h.key === t)) == null || _.component, /* @__PURE__ */ n("div", { children: [
1645
+ /* @__PURE__ */ e(
1646
+ ye,
1647
+ {
1648
+ title: "Mock 平台",
1649
+ subtitle: "WireMock 级 · Mock 端点管理、环境隔离、场景状态机、测试用例库、录制回放、请求日志"
1650
+ }
1651
+ ),
1652
+ /* @__PURE__ */ e(
1653
+ ke,
1654
+ {
1655
+ activeKey: t,
1656
+ onChange: i,
1657
+ type: "card",
1658
+ tabBarExtraContent: /* @__PURE__ */ n(E, { size: "large", wrap: !0, children: [
1659
+ /* @__PURE__ */ n(E, { children: [
1660
+ /* @__PURE__ */ e(ht, {}),
1661
+ /* @__PURE__ */ e(te, { children: "当前环境:" }),
1662
+ /* @__PURE__ */ e(
1663
+ V,
1664
+ {
1665
+ value: l,
1666
+ onChange: y,
1667
+ style: { width: 200 },
1668
+ options: r.map((h) => ({
1669
+ value: h.env_code,
1670
+ label: `${h.env_name || h.env_code} (${h.env_type})`
1671
+ }))
1672
+ }
1673
+ )
1674
+ ] }),
1675
+ c && /* @__PURE__ */ n(E, { size: "large", children: [
1676
+ /* @__PURE__ */ n(te, { type: "secondary", children: [
1677
+ "端点: ",
1678
+ /* @__PURE__ */ e(te, { strong: !0, children: c.totalEndpoints })
1679
+ ] }),
1680
+ /* @__PURE__ */ n(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__ */ n(te, { type: "secondary", children: [
1692
+ "场景: ",
1693
+ /* @__PURE__ */ e(te, { strong: !0, children: c.totalScenarios })
1694
+ ] }),
1695
+ /* @__PURE__ */ n(te, { type: "secondary", children: [
1696
+ "用例: ",
1697
+ /* @__PURE__ */ e(te, { strong: !0, children: c.totalCases })
1698
+ ] })
1699
+ ] }),
1700
+ /* @__PURE__ */ e(A, { icon: /* @__PURE__ */ e(ee, {}), onClick: () => {
1701
+ x(), C();
1702
+ }, children: "刷新" })
1703
+ ] }),
1704
+ items: et.map((h) => ({
1705
+ key: h.key,
1706
+ label: h.label,
1707
+ children: h.component === Be ? /* @__PURE__ */ e(Be, { activeEnvCode: l }) : h.component === je ? /* @__PURE__ */ e(je, { onEnvChange: (a) => {
1708
+ y(a), b.success(`已切换到环境: ${a}`);
1709
+ } }) : /* @__PURE__ */ e(h.component, {})
1710
+ }))
1711
+ }
1712
+ )
1713
+ ] });
1714
+ }
1715
+ const nr = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1716
+ __proto__: null,
1717
+ default: Sn
1718
+ }, Symbol.toStringTag, { value: "Module" })), { Text: ge, Paragraph: rr } = ae, 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(Se, {}),
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(Se, {}),
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(Se, {}),
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(Se, {}),
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 ar({ onInsert: t, form: i, formField: r = "responseTemplate" }) {
1775
+ const [S, l] = m(""), y = (h) => {
1776
+ var a;
1777
+ try {
1778
+ (a = navigator.clipboard) == null || a.writeText(h);
1779
+ } catch {
1780
+ }
1781
+ if (t)
1782
+ t(h);
1783
+ else if (i) {
1784
+ const d = i.getFieldValue(r) || "";
1785
+ i.setFieldsValue({ [r]: d + (d.endsWith(`
1786
+ `) || !d ? "" : " ") + h });
1787
+ }
1788
+ b.success(`已插入: ${h}`);
1789
+ }, c = (h) => {
1790
+ var a;
1791
+ try {
1792
+ (a = navigator.clipboard) == null || a.writeText(h), b.success("已复制到剪贴板");
1793
+ } catch {
1794
+ b.warning("复制失败,请手动选择");
1795
+ }
1796
+ }, f = S.toLowerCase(), x = tt.map((h) => ({
1797
+ ...h,
1798
+ items: h.items.filter(
1799
+ (a) => !f || a.syntax.toLowerCase().includes(f) || a.desc.toLowerCase().includes(f) || a.example.toLowerCase().includes(f)
1800
+ )
1801
+ })).filter((h) => h.items.length > 0), C = tt.reduce((h, a) => h + a.items.length, 0), _ = x.reduce((h, a) => h + a.items.length, 0);
1802
+ return /* @__PURE__ */ n(
1803
+ L,
1804
+ {
1805
+ size: "small",
1806
+ title: /* @__PURE__ */ n(E, { children: [
1807
+ /* @__PURE__ */ e(fe, {}),
1808
+ /* @__PURE__ */ e(ge, { strong: !0, children: "模板表达式" }),
1809
+ /* @__PURE__ */ n(w, { color: "blue", children: [
1810
+ _,
1811
+ "/",
1812
+ C
1813
+ ] }),
1814
+ /* @__PURE__ */ e(he, { title: "点击按钮即可插入到上方响应模板;点击 syntax 文本可复制", children: /* @__PURE__ */ e(Lt, { style: { color: "#999" } }) })
1815
+ ] }),
1816
+ extra: /* @__PURE__ */ e(
1817
+ B,
1818
+ {
1819
+ size: "small",
1820
+ placeholder: "搜索 @ 表达式",
1821
+ prefix: /* @__PURE__ */ e(mt, {}),
1822
+ value: S,
1823
+ onChange: (h) => l(h.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((h) => /* @__PURE__ */ n("div", { style: { marginBottom: 12 }, children: [
1833
+ /* @__PURE__ */ n(E, { size: 4, style: { marginBottom: 6 }, children: [
1834
+ h.icon,
1835
+ /* @__PURE__ */ e(ge, { strong: !0, style: { fontSize: 13 }, children: h.group }),
1836
+ /* @__PURE__ */ e(w, { children: h.items.length })
1837
+ ] }),
1838
+ /* @__PURE__ */ e(Y, { gutter: [8, 8], children: h.items.map((a) => /* @__PURE__ */ e(O, { span: 24, children: /* @__PURE__ */ n(
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(he, { title: "点击复制", children: /* @__PURE__ */ e(
1852
+ ge,
1853
+ {
1854
+ code: !0,
1855
+ style: { cursor: "pointer", minWidth: 140, fontSize: 12 },
1856
+ onClick: () => c(a.syntax),
1857
+ children: a.syntax
1858
+ }
1859
+ ) }),
1860
+ /* @__PURE__ */ e(ge, { type: "secondary", style: { fontSize: 12, flex: 1 }, children: a.desc }),
1861
+ /* @__PURE__ */ e(w, { color: "default", style: { margin: 0, fontFamily: "monospace" }, children: a.example }),
1862
+ /* @__PURE__ */ e(he, { title: "插入到响应模板", children: /* @__PURE__ */ e(
1863
+ A,
1864
+ {
1865
+ size: "small",
1866
+ type: "text",
1867
+ icon: /* @__PURE__ */ e(pt, {}),
1868
+ onClick: () => y(a.syntax)
1869
+ }
1870
+ ) })
1871
+ ]
1872
+ }
1873
+ ) }, a.syntax)) })
1874
+ ] }, h.group))
1875
+ ]
1876
+ }
1877
+ );
1878
+ }
1879
+ const { TextArea: nt } = B, { Text: pe, Paragraph: Tn } = ae;
1880
+ function lr({ open: t, onClose: i, onSuccess: r, envOptions: S = [] }) {
1881
+ const [l, y] = m(""), [c, f] = m(null), [x, C] = m(null), [_, h] = m(!1), [a, d] = m(null), [g, v] = m(!1), [D, T] = m("import"), [u] = P.useForm(), [s] = P.useForm(), I = () => {
1882
+ y(""), f(null), C(null), d(null), u.resetFields(), s.resetFields();
1883
+ }, M = () => {
1884
+ I(), i();
1885
+ }, J = async () => {
1886
+ var R, k, N, W;
1887
+ if (!l.trim()) {
1888
+ b.warning("请先粘贴 curl 命令");
1889
+ return;
1890
+ }
1891
+ C(null), f(null), d(null);
1892
+ try {
1893
+ const U = await j.curl.parse(l);
1894
+ U.success ? (f(U.data), u.setFieldsValue({
1895
+ caseName: `from-curl-${((R = U.data) == null ? void 0 : R.method) || "GET"}-${(((k = U.data) == null ? void 0 : k.path) || "").replace(/\W+/g, "-")}`,
1896
+ caseGroup: "imported",
1897
+ envCode: S[0] || "default"
1898
+ }), s.setFieldsValue({
1899
+ mockName: `mock-${((N = U.data) == null ? void 0 : N.method) || "GET"}-${(((W = U.data) == null ? void 0 : W.path) || "").replace(/\W+/g, "-")}`,
1900
+ envCode: S[0] || "default",
1901
+ projectCode: "default",
1902
+ responseTemplate: `{
1903
+ "code": 0,
1904
+ "message": "ok",
1905
+ "data": {}
1906
+ }`
1907
+ })) : C(U.message || "解析失败");
1908
+ } catch (U) {
1909
+ C(String((U == null ? void 0 : U.message) || U));
1910
+ }
1911
+ }, H = async () => {
1912
+ if (!l.trim()) {
1913
+ b.warning("请先粘贴 curl 命令");
1914
+ return;
1915
+ }
1916
+ h(!0), d(null);
1917
+ try {
1918
+ const R = await j.curl.run(l);
1919
+ d(R);
1920
+ } catch (R) {
1921
+ d({ success: !1, error: String((R == null ? void 0 : R.message) || R) });
1922
+ } finally {
1923
+ h(!1);
1924
+ }
1925
+ }, p = async () => {
1926
+ if (!c) {
1927
+ b.warning("请先解析");
1928
+ return;
1929
+ }
1930
+ let R;
1931
+ try {
1932
+ R = await u.validateFields();
1933
+ } catch {
1934
+ return;
1935
+ }
1936
+ v(!0);
1937
+ try {
1938
+ const k = await j.curl.importAsCase({
1939
+ curl: l,
1940
+ caseName: R.caseName,
1941
+ caseGroup: R.caseGroup,
1942
+ envCode: R.envCode
1943
+ });
1944
+ k.success ? (b.success(`已导入测试用例: ${k.caseCode}`), r && r("case", k), M()) : b.error(k.message || "导入失败");
1945
+ } catch (k) {
1946
+ b.error(String((k == null ? void 0 : k.message) || k));
1947
+ } finally {
1948
+ v(!1);
1949
+ }
1950
+ }, o = async () => {
1951
+ if (!c) {
1952
+ b.warning("请先解析");
1953
+ return;
1954
+ }
1955
+ let R;
1956
+ try {
1957
+ R = await s.validateFields();
1958
+ } catch {
1959
+ return;
1960
+ }
1961
+ v(!0);
1962
+ try {
1963
+ const k = await j.curl.importAsEndpoint({
1964
+ curl: l,
1965
+ mockName: R.mockName,
1966
+ envCode: R.envCode,
1967
+ projectCode: R.projectCode,
1968
+ responseTemplate: R.responseTemplate
1969
+ });
1970
+ k.success ? (b.success(`已导入 Mock 端点: ${k.mockCode}`), r && r("endpoint", k), M()) : b.error(k.message || "导入失败");
1971
+ } catch (k) {
1972
+ b.error(String((k == null ? void 0 : k.message) || k));
1973
+ } finally {
1974
+ v(!1);
1975
+ }
1976
+ };
1977
+ return /* @__PURE__ */ n(
1978
+ me,
1979
+ {
1980
+ title: /* @__PURE__ */ n(E, { children: [
1981
+ /* @__PURE__ */ e(fe, {}),
1982
+ " 粘贴 curl 一键导入"
1983
+ ] }),
1984
+ open: t,
1985
+ onCancel: M,
1986
+ footer: null,
1987
+ size: "large",
1988
+ destroyOnHidden: !0,
1989
+ children: [
1990
+ /* @__PURE__ */ e(Tn, { type: "secondary", style: { marginBottom: 12 }, children: "从浏览器 DevTools / Postman / 终端复制 curl 命令,粘贴到下方即可解析、试跑、入库。" }),
1991
+ /* @__PURE__ */ e(
1992
+ nt,
1993
+ {
1994
+ value: l,
1995
+ onChange: (R) => y(R.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__ */ n(E, { style: { marginTop: 12 }, children: [
2005
+ /* @__PURE__ */ e(A, { icon: /* @__PURE__ */ e(Ke, {}), onClick: J, type: "primary", ghost: !0, children: "解析" }),
2006
+ /* @__PURE__ */ e(A, { icon: /* @__PURE__ */ e(be, {}), onClick: H, loading: _, children: "直接执行(试跑)" })
2007
+ ] }),
2008
+ x && /* @__PURE__ */ e(Z, { type: "error", showIcon: !0, style: { marginTop: 12 }, title: "解析失败", description: x }),
2009
+ c && /* @__PURE__ */ e(L, { size: "small", style: { marginTop: 16 }, title: "解析结果", children: /* @__PURE__ */ n(z, { column: 1, size: "small", bordered: !0, children: [
2010
+ /* @__PURE__ */ e(z.Item, { label: "Method", children: /* @__PURE__ */ e(w, { color: Cn(c.method), children: c.method }) }),
2011
+ /* @__PURE__ */ e(z.Item, { label: "URL", children: /* @__PURE__ */ e(pe, { code: !0, copyable: !0, children: c.url }) }),
2012
+ /* @__PURE__ */ e(z.Item, { label: "Path", children: /* @__PURE__ */ e(pe, { code: !0, children: c.path }) }),
2013
+ c.query && /* @__PURE__ */ e(z.Item, { label: "Query", children: /* @__PURE__ */ e(pe, { code: !0, children: c.query }) }),
2014
+ /* @__PURE__ */ e(z.Item, { label: "Headers", children: Object.keys(c.headers || {}).length === 0 ? /* @__PURE__ */ e(pe, { type: "secondary", children: "(无)" }) : /* @__PURE__ */ e("div", { children: Object.entries(c.headers).map(([R, k]) => /* @__PURE__ */ n("div", { children: [
2015
+ /* @__PURE__ */ n(pe, { strong: !0, children: [
2016
+ R,
2017
+ ":"
2018
+ ] }),
2019
+ " ",
2020
+ /* @__PURE__ */ e(pe, { code: !0, children: k })
2021
+ ] }, R)) }) }),
2022
+ c.body && /* @__PURE__ */ e(z.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
+ a && /* @__PURE__ */ n(L, { size: "small", style: { marginTop: 16 }, title: /* @__PURE__ */ n(E, { children: [
2032
+ /* @__PURE__ */ e(be, {}),
2033
+ /* @__PURE__ */ e("span", { children: "试跑结果" }),
2034
+ a.success ? /* @__PURE__ */ n(w, { color: "green", children: [
2035
+ a.status,
2036
+ " · ",
2037
+ a.durationMs,
2038
+ "ms · ",
2039
+ a.bodySize,
2040
+ "B"
2041
+ ] }) : /* @__PURE__ */ e(w, { color: "red", children: "FAILED" })
2042
+ ] }), children: [
2043
+ a.error && /* @__PURE__ */ e(Z, { type: "error", showIcon: !0, title: a.error }),
2044
+ a.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: a.body })
2052
+ ] }),
2053
+ c && /* @__PURE__ */ e(
2054
+ ke,
2055
+ {
2056
+ activeKey: D,
2057
+ onChange: T,
2058
+ style: { marginTop: 16 },
2059
+ items: [
2060
+ {
2061
+ key: "import",
2062
+ label: /* @__PURE__ */ n("span", { children: [
2063
+ /* @__PURE__ */ e(Ne, {}),
2064
+ " 导入为测试用例"
2065
+ ] }),
2066
+ children: /* @__PURE__ */ n(P, { form: u, layout: "vertical", children: [
2067
+ /* @__PURE__ */ n(Y, { gutter: 16, children: [
2068
+ /* @__PURE__ */ e(O, { span: 12, children: /* @__PURE__ */ e(P.Item, { name: "caseName", label: "用例名称", rules: [{ required: !0 }], children: /* @__PURE__ */ e(B, {}) }) }),
2069
+ /* @__PURE__ */ e(O, { span: 6, children: /* @__PURE__ */ e(P.Item, { name: "caseGroup", label: "用例分组", children: /* @__PURE__ */ e(B, {}) }) }),
2070
+ /* @__PURE__ */ e(O, { span: 6, children: /* @__PURE__ */ e(P.Item, { name: "envCode", label: "环境", children: S.length > 0 ? /* @__PURE__ */ e(V, { options: S.map((R) => ({ value: R, label: R })) }) : /* @__PURE__ */ e(B, {}) }) })
2071
+ ] }),
2072
+ /* @__PURE__ */ e(
2073
+ A,
2074
+ {
2075
+ type: "primary",
2076
+ onClick: p,
2077
+ loading: g,
2078
+ icon: /* @__PURE__ */ e(Ne, {}),
2079
+ children: "保存为测试用例"
2080
+ }
2081
+ )
2082
+ ] })
2083
+ },
2084
+ {
2085
+ key: "mock",
2086
+ label: /* @__PURE__ */ n("span", { children: [
2087
+ /* @__PURE__ */ e(fe, {}),
2088
+ " 导入为 Mock 端点"
2089
+ ] }),
2090
+ children: /* @__PURE__ */ n(P, { form: s, layout: "vertical", children: [
2091
+ /* @__PURE__ */ n(Y, { gutter: 16, children: [
2092
+ /* @__PURE__ */ e(O, { span: 12, children: /* @__PURE__ */ e(P.Item, { name: "mockName", label: "Mock 名称", rules: [{ required: !0 }], children: /* @__PURE__ */ e(B, {}) }) }),
2093
+ /* @__PURE__ */ e(O, { span: 6, children: /* @__PURE__ */ e(P.Item, { name: "envCode", label: "环境", children: S.length > 0 ? /* @__PURE__ */ e(V, { options: S.map((R) => ({ value: R, label: R })) }) : /* @__PURE__ */ e(B, {}) }) }),
2094
+ /* @__PURE__ */ e(O, { span: 6, children: /* @__PURE__ */ e(P.Item, { name: "projectCode", label: "项目", children: /* @__PURE__ */ e(B, {}) }) })
2095
+ ] }),
2096
+ /* @__PURE__ */ e(P.Item, { name: "responseTemplate", label: "响应模板 (JSON)", children: /* @__PURE__ */ e(
2097
+ nt,
2098
+ {
2099
+ autoSize: { minRows: 3, maxRows: 8 },
2100
+ style: { fontFamily: "Menlo, Monaco, monospace" }
2101
+ }
2102
+ ) }),
2103
+ /* @__PURE__ */ e(
2104
+ A,
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 Cn(t) {
2123
+ return { GET: "blue", POST: "green", PUT: "orange", DELETE: "red", PATCH: "purple" }[t] || "default";
2124
+ }
2125
+ const { TextArea: rt } = B;
2126
+ function sr({ open: t, onClose: i, onSuccess: r, envOptions: S = [] }) {
2127
+ const [l, y] = m("paste"), [c, f] = m(""), [x, C] = m(null), [_, h] = m(null), [a, d] = m(!1), [g, v] = m([]), [D, T] = m(!1), [u] = P.useForm(), s = it(null), I = () => {
2128
+ f(""), C(null), h(null), v([]), u.resetFields();
2129
+ }, M = () => {
2130
+ I(), i();
2131
+ }, J = async () => {
2132
+ if (!c.trim()) {
2133
+ b.warning("请先粘贴或上传 API 规约");
2134
+ return;
2135
+ }
2136
+ h(null), d(!0);
2137
+ try {
2138
+ const k = await j.openapi.parse(c);
2139
+ k.success ? (C(k), v((k.endpoints || []).map((N, W) => W)), u.setFieldsValue({
2140
+ envCode: S[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(`识别为 ${k.format},共 ${k.count} 个端点`)) : h(k.message || "解析失败");
2151
+ } catch (k) {
2152
+ h(String((k == null ? void 0 : k.message) || k));
2153
+ } finally {
2154
+ d(!1);
2155
+ }
2156
+ }, H = async (k) => {
2157
+ try {
2158
+ const N = await j.openapi.sample(k);
2159
+ N.success && (f(N.content), b.success(`已加载 ${N.format} 示例`));
2160
+ } catch (N) {
2161
+ b.error("加载示例失败: " + N.message);
2162
+ }
2163
+ }, p = (k) => {
2164
+ const N = new FileReader();
2165
+ return N.onload = (W) => {
2166
+ var U;
2167
+ f(String(((U = W.target) == null ? void 0 : U.result) || "")), b.success(`已读取 ${k.name}(${(k.size / 1024).toFixed(1)}KB)`);
2168
+ }, N.onerror = () => b.error("文件读取失败"), N.readAsText(k), !1;
2169
+ }, o = async () => {
2170
+ if (!x) {
2171
+ b.warning("请先解析");
2172
+ return;
2173
+ }
2174
+ let k;
2175
+ try {
2176
+ k = await u.validateFields();
2177
+ } catch {
2178
+ return;
2179
+ }
2180
+ T(!0);
2181
+ try {
2182
+ const N = (x.endpoints || []).map((U, Ze) => ({
2183
+ method: U.method,
2184
+ path: U.path
2185
+ })).filter((U, Ze) => g.includes(Ze)), W = await j.openapi.importBatch({
2186
+ content: c,
2187
+ selected: N,
2188
+ envCode: k.envCode,
2189
+ projectCode: k.projectCode,
2190
+ defaultResponse: k.defaultResponse,
2191
+ defaultStatus: k.defaultStatus,
2192
+ priority: k.priority,
2193
+ tagPrefix: k.tagPrefix
2194
+ });
2195
+ W.success ? (b.success(`已导入 ${W.imported} 个 Mock 端点${W.failed > 0 ? `,失败 ${W.failed}` : ""}`), r && r(W), M()) : b.error(W.message || "导入失败");
2196
+ } catch (N) {
2197
+ b.error(String((N == null ? void 0 : N.message) || N));
2198
+ } finally {
2199
+ T(!1);
2200
+ }
2201
+ }, R = [
2202
+ {
2203
+ title: "Method",
2204
+ dataIndex: "method",
2205
+ width: 90,
2206
+ render: (k) => /* @__PURE__ */ e(w, { color: vn(k), children: k })
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: (k) => (k || []).map((N) => /* @__PURE__ */ e(w, { children: N }, N))
2215
+ },
2216
+ {
2217
+ title: "Params",
2218
+ dataIndex: "parameters",
2219
+ width: 80,
2220
+ render: (k) => (k == null ? void 0 : k.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: (k) => k ? /* @__PURE__ */ e(w, { color: "green", children: "有" }) : /* @__PURE__ */ e(w, { children: "无" })
2229
+ }
2230
+ ];
2231
+ return /* @__PURE__ */ n(
2232
+ me,
2233
+ {
2234
+ title: /* @__PURE__ */ n(E, { children: [
2235
+ /* @__PURE__ */ e(Ve, {}),
2236
+ " 批量导入 API 规约"
2237
+ ] }),
2238
+ open: t,
2239
+ onCancel: M,
2240
+ footer: null,
2241
+ size: "large",
2242
+ destroyOnHidden: !0,
2243
+ children: [
2244
+ /* @__PURE__ */ e(
2245
+ ke,
2246
+ {
2247
+ activeKey: l,
2248
+ onChange: y,
2249
+ items: [
2250
+ {
2251
+ key: "paste",
2252
+ label: /* @__PURE__ */ n("span", { children: [
2253
+ /* @__PURE__ */ e(Ke, {}),
2254
+ " 粘贴 JSON"
2255
+ ] }),
2256
+ children: /* @__PURE__ */ n("div", { children: [
2257
+ /* @__PURE__ */ e(
2258
+ rt,
2259
+ {
2260
+ value: c,
2261
+ onChange: (k) => f(k.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__ */ n(E, { style: { marginTop: 8 }, children: [
2268
+ /* @__PURE__ */ e(A, { size: "small", onClick: () => H("openapi3"), children: "加载 OpenAPI 3 示例" }),
2269
+ /* @__PURE__ */ e(A, { size: "small", onClick: () => H("swagger2"), children: "加载 Swagger 2 示例" }),
2270
+ /* @__PURE__ */ e(A, { size: "small", onClick: () => H("postman"), children: "加载 Postman 示例" })
2271
+ ] })
2272
+ ] })
2273
+ },
2274
+ {
2275
+ key: "upload",
2276
+ label: /* @__PURE__ */ n("span", { children: [
2277
+ /* @__PURE__ */ e(Mt, {}),
2278
+ " 上传文件"
2279
+ ] }),
2280
+ children: /* @__PURE__ */ n(
2281
+ St.Dragger,
2282
+ {
2283
+ ref: s,
2284
+ accept: ".json,.yaml,.yml,application/json,text/yaml",
2285
+ beforeUpload: p,
2286
+ showUploadList: !1,
2287
+ style: { padding: 24 },
2288
+ children: [
2289
+ /* @__PURE__ */ e("p", { className: "ant-upload-drag-icon", children: /* @__PURE__ */ e(Ve, { 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__ */ n(E, { style: { marginTop: 12 }, children: [
2300
+ /* @__PURE__ */ e(A, { type: "primary", icon: /* @__PURE__ */ e(be, {}), onClick: J, loading: a, children: "解析" }),
2301
+ x && /* @__PURE__ */ e(w, { color: "blue", children: x.format }),
2302
+ x && /* @__PURE__ */ n(w, { children: [
2303
+ "共 ",
2304
+ x.count,
2305
+ " 个端点,已选 ",
2306
+ g.length
2307
+ ] })
2308
+ ] }),
2309
+ _ && /* @__PURE__ */ e(Z, { type: "error", showIcon: !0, style: { marginTop: 12 }, title: "解析失败", description: _ }),
2310
+ x && /* 端点预览 —— 走基座 ListTable(lead 008 §2 三件套):
2311
+ 标准分页 + 端侧过滤 + EmptyState。
2312
+ 原来那层 <Card size="small" title="预览(可勾选要导入的)"> 已去掉,
2313
+ 标题落到 ListTable 的 cardTitle,避免卡片套卡片。 */
2314
+ /* @__PURE__ */ e(
2315
+ se,
2316
+ {
2317
+ cardTitle: "预览(可勾选要导入的)",
2318
+ rows: x.endpoints || [],
2319
+ columns: R,
2320
+ rowKey: (k, N) => N,
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(L, { size: "small", style: { marginTop: 16 }, title: "导入配置", children: /* @__PURE__ */ n(P, { form: u, layout: "vertical", children: [
2334
+ /* @__PURE__ */ n(Y, { gutter: 16, children: [
2335
+ /* @__PURE__ */ e(O, { span: 6, children: /* @__PURE__ */ e(P.Item, { name: "envCode", label: "环境", rules: [{ required: !0 }], children: S.length > 0 ? /* @__PURE__ */ e(V, { options: S.map((k) => ({ value: k, label: k })) }) : /* @__PURE__ */ e(B, {}) }) }),
2336
+ /* @__PURE__ */ e(O, { span: 6, children: /* @__PURE__ */ e(P.Item, { name: "projectCode", label: "项目", children: /* @__PURE__ */ e(B, {}) }) }),
2337
+ /* @__PURE__ */ e(O, { span: 4, children: /* @__PURE__ */ e(P.Item, { name: "defaultStatus", label: "默认状态码", children: /* @__PURE__ */ e(B, { type: "number" }) }) }),
2338
+ /* @__PURE__ */ e(O, { span: 4, children: /* @__PURE__ */ e(P.Item, { name: "priority", label: "优先级", children: /* @__PURE__ */ e(B, { type: "number" }) }) }),
2339
+ /* @__PURE__ */ e(O, { span: 4, children: /* @__PURE__ */ e(P.Item, { name: "tagPrefix", label: "Tag 前缀", children: /* @__PURE__ */ e(B, {}) }) })
2340
+ ] }),
2341
+ /* @__PURE__ */ e(P.Item, { name: "defaultResponse", label: "默认响应(无 example 时使用)", children: /* @__PURE__ */ e(
2342
+ rt,
2343
+ {
2344
+ autoSize: { minRows: 3, maxRows: 6 },
2345
+ style: { fontFamily: "Menlo, Monaco, monospace" }
2346
+ }
2347
+ ) }),
2348
+ /* @__PURE__ */ n(
2349
+ A,
2350
+ {
2351
+ type: "primary",
2352
+ size: "large",
2353
+ icon: /* @__PURE__ */ e(Ne, {}),
2354
+ onClick: o,
2355
+ loading: D,
2356
+ disabled: g.length === 0,
2357
+ children: [
2358
+ "批量导入 ",
2359
+ g.length,
2360
+ " 个端点"
2361
+ ]
2362
+ }
2363
+ )
2364
+ ] }) })
2365
+ ]
2366
+ }
2367
+ );
2368
+ }
2369
+ function vn(t) {
2370
+ return { GET: "blue", POST: "green", PUT: "orange", DELETE: "red", PATCH: "purple" }[t] || "default";
2371
+ }
2372
+ const An = {
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
+ }, _n = {
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
+ }, at = {
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 Pn() {
2393
+ const t = xe(), [i, r] = m([]), [S, l] = m(!1), [y, c] = m(null), [f, x] = m([]), [C, _] = m({}), [h, a] = m(null), [d, g] = m([]), v = async () => {
2394
+ l(!0);
2395
+ try {
2396
+ const p = await $.get("/subscribe/subscription/list");
2397
+ p && p.success !== !1 && r(Array.isArray(p.data) ? p.data : Array.isArray(p) ? p : []);
2398
+ } catch (p) {
2399
+ b.error("获取订阅列表失败: " + ((p == null ? void 0 : p.message) || ""));
2400
+ } finally {
2401
+ l(!1);
2402
+ }
2403
+ };
2404
+ F(() => {
2405
+ v();
2406
+ }, []);
2407
+ const D = (p) => {
2408
+ me.confirm({
2409
+ title: "确认删除",
2410
+ icon: /* @__PURE__ */ e(Bt, {}),
2411
+ content: `确定要删除订阅 "${p.name}" 吗? 运行历史会保留.`,
2412
+ onOk: async () => {
2413
+ try {
2414
+ const o = await $.delete(`/subscribe/subscription/${p.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
+ }, T = async (p) => {
2422
+ try {
2423
+ const o = await $.post(`/subscribe/subscription/${p}/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 (p) => {
2429
+ try {
2430
+ const o = await $.post(`/subscribe/subscription/${p}/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
+ }, s = async (p) => {
2436
+ me.confirm({
2437
+ title: "手动触发",
2438
+ content: `将立即执行一次 "${p.name}" 的抽取, 同步返回 runId.`,
2439
+ onOk: async () => {
2440
+ try {
2441
+ const o = await $.post(`/subscribe/subscription/${p.id}/trigger?triggerBy=ceo`);
2442
+ if (o && (o.data !== void 0 || o.success !== !1)) {
2443
+ const R = o.data ?? o;
2444
+ b.success(`已触发, runId = ${R}`), M(p);
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
+ }, I = async (p) => {
2453
+ try {
2454
+ const o = await $.post(`/subscribe/subscription/${p.id}/dry-run`);
2455
+ c({ sub: p, result: (o == null ? void 0 : o.data) ?? o });
2456
+ } catch (o) {
2457
+ c({ sub: p, result: { success: !1, errorMessage: (o == null ? void 0 : o.message) || "请求失败" } });
2458
+ }
2459
+ }, M = async (p) => {
2460
+ try {
2461
+ const o = await $.get(`/subscribe/run/list?subscriptionId=${p.id}&limit=20`), R = (o == null ? void 0 : o.data) ?? o ?? [];
2462
+ x(Array.isArray(R) ? R : []), a(null), _({}), g([]), c({ sub: p, tab: "runs" });
2463
+ } catch {
2464
+ b.error("获取运行历史失败");
2465
+ }
2466
+ }, J = async (p) => {
2467
+ if (C[p]) {
2468
+ a(p);
2469
+ return;
2470
+ }
2471
+ try {
2472
+ const o = await $.get(`/subscribe/run/${p}/items?limit=200`), R = (o == null ? void 0 : o.data) ?? o ?? [];
2473
+ _((k) => ({ ...k, [p]: Array.isArray(R) ? R : [] })), a(p);
2474
+ } catch {
2475
+ b.error("获取抽取项失败");
2476
+ }
2477
+ };
2478
+ return /* @__PURE__ */ n("div", { children: [
2479
+ /* @__PURE__ */ e(
2480
+ ye,
2481
+ {
2482
+ title: "订阅中心 - 数据源订阅",
2483
+ subtitle: "负责把三方 / 内部 / RSS 等数据源按 Cron 定时抽取, 归一化后落到本地"
2484
+ }
2485
+ ),
2486
+ /* @__PURE__ */ e(
2487
+ Z,
2488
+ {
2489
+ type: "info",
2490
+ showIcon: !0,
2491
+ style: { marginBottom: 16 },
2492
+ message: "订阅中心负责把三方 / 内部 / RSS 等数据源按 Cron 定时抽取, 归一化后落到本地, 供 CEO 立项和 Agent 协作使用."
2493
+ }
2494
+ ),
2495
+ /* @__PURE__ */ e(
2496
+ se,
2497
+ {
2498
+ rows: i,
2499
+ columns: [
2500
+ {
2501
+ title: "ID",
2502
+ dataIndex: "id",
2503
+ width: 70
2504
+ },
2505
+ {
2506
+ title: "名称",
2507
+ dataIndex: "name",
2508
+ render: (p, o) => /* @__PURE__ */ n(E, { orientation: "vertical", size: 0, children: [
2509
+ /* @__PURE__ */ e("span", { style: { fontWeight: 500 }, children: p }),
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: (p) => /* @__PURE__ */ e(w, { children: p })
2518
+ },
2519
+ {
2520
+ title: "抽取器",
2521
+ dataIndex: "extractorType",
2522
+ width: 140,
2523
+ render: (p) => {
2524
+ const o = An[p] || { label: p, 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: (p) => /* @__PURE__ */ e("code", { style: { fontSize: 12 }, children: p })
2533
+ },
2534
+ {
2535
+ title: "状态",
2536
+ dataIndex: "status",
2537
+ width: 110,
2538
+ render: (p) => {
2539
+ const o = _n[p] || { color: "default", text: p };
2540
+ return /* @__PURE__ */ e(w, { color: o.color, children: o.text });
2541
+ }
2542
+ },
2543
+ {
2544
+ title: "启用",
2545
+ dataIndex: "enabled",
2546
+ width: 80,
2547
+ render: (p, o) => p ? /* @__PURE__ */ e(w, { color: "green", children: "是" }) : /* @__PURE__ */ e(w, { children: "否" })
2548
+ },
2549
+ {
2550
+ title: "最近 run",
2551
+ dataIndex: "lastStatus",
2552
+ width: 110,
2553
+ render: (p, o) => {
2554
+ var R;
2555
+ return p ? /* @__PURE__ */ e(he, { title: o.lastError || "", children: /* @__PURE__ */ e(w, { color: ((R = at[p]) == null ? void 0 : R.color) || "default", children: p }) }) : /* @__PURE__ */ e("span", { style: { color: "#ccc" }, children: "-" });
2556
+ }
2557
+ },
2558
+ {
2559
+ title: "累计",
2560
+ width: 130,
2561
+ render: (p, o) => /* @__PURE__ */ n(E, { size: 4, children: [
2562
+ /* @__PURE__ */ n(w, { color: "green", children: [
2563
+ "✓ ",
2564
+ o.successCountTotal || 0
2565
+ ] }),
2566
+ /* @__PURE__ */ n(w, { color: "red", children: [
2567
+ "✗ ",
2568
+ o.failCountTotal || 0
2569
+ ] })
2570
+ ] })
2571
+ },
2572
+ {
2573
+ title: "操作",
2574
+ width: 280,
2575
+ fixed: "right",
2576
+ render: (p, o) => /* @__PURE__ */ n(E, { size: 4, wrap: !0, children: [
2577
+ /* @__PURE__ */ e(
2578
+ A,
2579
+ {
2580
+ type: "link",
2581
+ size: "small",
2582
+ icon: /* @__PURE__ */ e(Dt, {}),
2583
+ onClick: () => t(`/subscribe/edit/${o.id}`),
2584
+ children: "编辑"
2585
+ }
2586
+ ),
2587
+ /* @__PURE__ */ e(
2588
+ A,
2589
+ {
2590
+ type: "link",
2591
+ size: "small",
2592
+ icon: /* @__PURE__ */ e(be, {}),
2593
+ onClick: () => I(o),
2594
+ children: "试运行"
2595
+ }
2596
+ ),
2597
+ /* @__PURE__ */ e(
2598
+ A,
2599
+ {
2600
+ type: "link",
2601
+ size: "small",
2602
+ icon: /* @__PURE__ */ e(Ee, {}),
2603
+ onClick: () => s(o),
2604
+ children: "触发"
2605
+ }
2606
+ ),
2607
+ /* @__PURE__ */ e(
2608
+ A,
2609
+ {
2610
+ type: "link",
2611
+ size: "small",
2612
+ onClick: () => M(o),
2613
+ children: "历史"
2614
+ }
2615
+ ),
2616
+ o.enabled ? /* @__PURE__ */ e(
2617
+ A,
2618
+ {
2619
+ type: "link",
2620
+ size: "small",
2621
+ icon: /* @__PURE__ */ e($t, {}),
2622
+ onClick: () => u(o.id),
2623
+ children: "停用"
2624
+ }
2625
+ ) : /* @__PURE__ */ e(
2626
+ A,
2627
+ {
2628
+ type: "link",
2629
+ size: "small",
2630
+ icon: /* @__PURE__ */ e(Fe, {}),
2631
+ onClick: () => T(o.id),
2632
+ children: "启用"
2633
+ }
2634
+ ),
2635
+ /* @__PURE__ */ e(Ue, { title: "确认删除?", onConfirm: () => D(o), okText: "删除", cancelText: "取消", children: /* @__PURE__ */ e(A, { type: "link", size: "small", danger: !0, icon: /* @__PURE__ */ e(Nt, {}), children: "删除" }) })
2636
+ ] })
2637
+ }
2638
+ ],
2639
+ rowKey: "id",
2640
+ loading: S,
2641
+ scroll: { x: 1400 },
2642
+ tableProps: { size: "middle" },
2643
+ searchKeys: ["name", "id", "sourceType"],
2644
+ searchPlaceholder: "按订阅名称 / ID / 数据源类型过滤",
2645
+ emptyTitle: "暂无订阅",
2646
+ emptyDescription: "订阅负责把三方数据源按 Cron 定时抽取归一化,先建一个订阅试试。",
2647
+ cardExtra: /* @__PURE__ */ n(E, { children: [
2648
+ /* @__PURE__ */ e(A, { icon: /* @__PURE__ */ e(ee, {}), onClick: v, children: "刷新" }),
2649
+ /* @__PURE__ */ e(
2650
+ A,
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
+ ke,
2670
+ {
2671
+ activeKey: h ? "items" : "list",
2672
+ onChange: (p) => p === "list" && a(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
+ se,
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: (p) => ({ onClick: () => J(p.id) }),
2693
+ columns: [
2694
+ { title: "runId", dataIndex: "id", width: 70 },
2695
+ {
2696
+ title: "计划",
2697
+ dataIndex: "scheduledAt",
2698
+ width: 160,
2699
+ render: (p) => p ? new Date(p).toLocaleString() : "-"
2700
+ },
2701
+ { title: "耗时(ms)", dataIndex: "durationMs", width: 90 },
2702
+ {
2703
+ title: "状态",
2704
+ dataIndex: "status",
2705
+ width: 90,
2706
+ render: (p) => {
2707
+ var o;
2708
+ return /* @__PURE__ */ e(w, { color: (o = at[p]) == null ? void 0 : o.color, children: p });
2709
+ }
2710
+ },
2711
+ {
2712
+ title: "拉取/成功/重复/死信",
2713
+ width: 200,
2714
+ render: (p, o) => `${o.fetchedCount} / ${o.successCount} / ${o.duplicateCount || 0} / ${o.deadLetterCount}`
2715
+ },
2716
+ {
2717
+ title: "错误",
2718
+ dataIndex: "errorMessage",
2719
+ render: (p) => p ? /* @__PURE__ */ e("span", { style: { color: "#cf1322", fontSize: 12 }, children: p }) : "-"
2720
+ }
2721
+ ]
2722
+ }
2723
+ )
2724
+ )
2725
+ },
2726
+ {
2727
+ key: "items",
2728
+ label: h ? `run#${h} 抽取项` : "抽取项",
2729
+ disabled: !h,
2730
+ children: /* @__PURE__ */ n(E, { orientation: "vertical", style: { width: "100%" }, children: [
2731
+ /* @__PURE__ */ n(E, { children: [
2732
+ /* @__PURE__ */ n(w, { color: "blue", children: [
2733
+ "已选 ",
2734
+ d.length,
2735
+ " 条"
2736
+ ] }),
2737
+ /* @__PURE__ */ n(
2738
+ A,
2739
+ {
2740
+ size: "small",
2741
+ type: "primary",
2742
+ icon: /* @__PURE__ */ e(Pe, {}),
2743
+ disabled: d.length === 0,
2744
+ onClick: () => {
2745
+ const p = d.join(",");
2746
+ t(`/project/new?subscriptionId=${y.sub.id}&itemIds=${p}`);
2747
+ },
2748
+ children: [
2749
+ "用所选 ",
2750
+ d.length,
2751
+ " 条立项"
2752
+ ]
2753
+ }
2754
+ )
2755
+ ] }),
2756
+ /* @__PURE__ */ e(
2757
+ se,
2758
+ {
2759
+ rows: C[h] || [],
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: (p) => {
2776
+ try {
2777
+ return JSON.parse(p).title || "(无标题)";
2778
+ } catch {
2779
+ return p;
2780
+ }
2781
+ }
2782
+ },
2783
+ {
2784
+ title: "link",
2785
+ dataIndex: "normalized",
2786
+ render: (p) => {
2787
+ try {
2788
+ const o = JSON.parse(p);
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: (p) => /* @__PURE__ */ e(w, { children: p })
2800
+ }
2801
+ ]
2802
+ }
2803
+ )
2804
+ ] })
2805
+ }
2806
+ ]
2807
+ }
2808
+ ) : /* @__PURE__ */ e(En, { result: y == null ? void 0 : y.result })
2809
+ }
2810
+ )
2811
+ ] });
2812
+ }
2813
+ function En({ result: t }) {
2814
+ return t ? t.success ? /* @__PURE__ */ n(E, { orientation: "vertical", style: { width: "100%" }, size: "middle", children: [
2815
+ /* @__PURE__ */ e(L, { size: "small", title: "调用结果", children: /* @__PURE__ */ n(E, { size: "large", wrap: !0, children: [
2816
+ /* @__PURE__ */ n("span", { children: [
2817
+ /* @__PURE__ */ e("b", { children: "HTTP:" }),
2818
+ " ",
2819
+ t.httpStatus || "-"
2820
+ ] }),
2821
+ /* @__PURE__ */ n("span", { children: [
2822
+ /* @__PURE__ */ e("b", { children: "耗时:" }),
2823
+ " ",
2824
+ t.latencyMs,
2825
+ "ms"
2826
+ ] }),
2827
+ /* @__PURE__ */ n("span", { children: [
2828
+ /* @__PURE__ */ e("b", { children: "大小:" }),
2829
+ " ",
2830
+ t.responseSize,
2831
+ "B"
2832
+ ] }),
2833
+ /* @__PURE__ */ n("span", { children: [
2834
+ /* @__PURE__ */ e("b", { children: "样本:" }),
2835
+ " ",
2836
+ t.sampleCount,
2837
+ " 条"
2838
+ ] })
2839
+ ] }) }),
2840
+ t.firstItem && /* @__PURE__ */ e(L, { 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(L, { 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(Z, { type: "warning", showIcon: !0, message: "字段问题", description: /* @__PURE__ */ e("ul", { children: t.fieldErrors.map((i, r) => /* @__PURE__ */ e("li", { children: i }, r)) }) })
2856
+ ] }) : /* @__PURE__ */ e(Z, { type: "error", showIcon: !0, title: "试运行失败", description: t.errorMessage || "未知错误" }) : null;
2857
+ }
2858
+ const zn = [
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
+ ], Rn = [
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
+ ], On = [
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 lt() {
2877
+ const { id: t } = ot(), i = xe(), r = !!t, [S] = P.useForm(), [l, y] = m(!1), [c, f] = m(!1), [x, C] = m([]), [_, h] = m([]), a = P.useWatch("sourceType", S), d = P.useWatch("extractorType", S), g = P.useWatch("authType", S);
2878
+ F(() => {
2879
+ v(), D(), r && T();
2880
+ }, [t]);
2881
+ const v = async () => {
2882
+ try {
2883
+ const s = await $.get("/secret/list"), I = (s == null ? void 0 : s.data) ?? s ?? [];
2884
+ C(Array.isArray(I) ? I : []);
2885
+ } catch {
2886
+ }
2887
+ }, D = async () => {
2888
+ try {
2889
+ const s = await $.get("/script/list"), I = (s == null ? void 0 : s.data) ?? s ?? [];
2890
+ h(Array.isArray(I) ? I.filter((M) => M.status === 1) : []);
2891
+ } catch {
2892
+ }
2893
+ }, T = async () => {
2894
+ y(!0);
2895
+ try {
2896
+ const s = await $.get(`/subscribe/subscription/${t}`), I = (s == null ? void 0 : s.data) ?? s;
2897
+ I && S.setFieldsValue({
2898
+ ...I,
2899
+ enabled: I.enabled === 1 || I.enabled === !0
2900
+ });
2901
+ } catch (s) {
2902
+ b.error("加载订阅失败: " + ((s == null ? void 0 : s.message) || ""));
2903
+ } finally {
2904
+ y(!1);
2905
+ }
2906
+ }, u = async () => {
2907
+ try {
2908
+ const s = await S.validateFields();
2909
+ f(!0);
2910
+ const I = {
2911
+ ...s,
2912
+ enabled: s.enabled ? 1 : 0
2913
+ };
2914
+ let M;
2915
+ if (r ? M = await $.put("/subscribe/subscription", I) : M = await $.post("/subscribe/subscription", I), M && M.success === !1) {
2916
+ b.error(M.message || "保存失败");
2917
+ return;
2918
+ }
2919
+ b.success(r ? "已更新 (注意: 修改 cron / url / 抽取器后会自动重置为 PENDING_VERIFY)" : "已创建, 已自动验证"), i("/subscribe/list");
2920
+ } catch (s) {
2921
+ s != null && s.errorFields ? b.warning("请检查表单") : b.error("保存失败: " + ((s == null ? void 0 : s.message) || ""));
2922
+ } finally {
2923
+ f(!1);
2924
+ }
2925
+ };
2926
+ return /* @__PURE__ */ n("div", { style: { padding: 24 }, children: [
2927
+ /* @__PURE__ */ e(
2928
+ ye,
2929
+ {
2930
+ title: r ? `编辑订阅 #${t}` : "新建订阅",
2931
+ subtitle: "配置数据源、抽取器、鉴权与调度策略",
2932
+ back: !0,
2933
+ extra: /* @__PURE__ */ n(E, { children: [
2934
+ /* @__PURE__ */ e(A, { onClick: () => i("/subscribe/list"), children: "取消" }),
2935
+ /* @__PURE__ */ e(A, { type: "primary", icon: /* @__PURE__ */ e(gt, {}), loading: c, onClick: u, children: "保存 (自动验证)" })
2936
+ ] })
2937
+ }
2938
+ ),
2939
+ /* @__PURE__ */ e(L, { children: /* @__PURE__ */ e(_e, { spinning: l, children: /* @__PURE__ */ n(
2940
+ P,
2941
+ {
2942
+ form: S,
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__ */ n(L, { type: "inner", title: "基本信息", style: { marginBottom: 16 }, children: [
2956
+ /* @__PURE__ */ e(P.Item, { label: "名称", name: "name", rules: [{ required: !0, message: "请输入名称" }], children: /* @__PURE__ */ e(B, { placeholder: "例如: GitHub PR 通知" }) }),
2957
+ /* @__PURE__ */ e(P.Item, { label: "说明", name: "description", children: /* @__PURE__ */ e(B.TextArea, { rows: 2, placeholder: "(可选)" }) })
2958
+ ] }),
2959
+ /* @__PURE__ */ n(L, { type: "inner", title: "数据源", style: { marginBottom: 16 }, children: [
2960
+ /* @__PURE__ */ e(P.Item, { label: "数据源形态", name: "sourceType", rules: [{ required: !0 }], children: /* @__PURE__ */ n(ne.Group, { children: [
2961
+ /* @__PURE__ */ e(ne.Button, { value: "HTTP", children: "HTTP / HTTPS" }),
2962
+ /* @__PURE__ */ e(ne.Button, { value: "INTERNAL", disabled: !0, children: "内部 Bean" })
2963
+ ] }) }),
2964
+ a === "HTTP" && /* @__PURE__ */ n(Me, { children: [
2965
+ /* @__PURE__ */ e(
2966
+ P.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__ */ n(E, { size: "large", style: { width: "100%" }, children: [
2975
+ /* @__PURE__ */ e(P.Item, { label: "HTTP 方法", name: "httpMethod", children: /* @__PURE__ */ e(V, { style: { width: 120 }, options: [
2976
+ { value: "GET", label: "GET" },
2977
+ { value: "POST", label: "POST" },
2978
+ { value: "PUT", label: "PUT" }
2979
+ ] }) }),
2980
+ /* @__PURE__ */ e(P.Item, { label: "超时 (ms)", name: "timeoutMs", children: /* @__PURE__ */ e(Re, { min: 1e3, max: 12e4, step: 1e3 }) })
2981
+ ] }),
2982
+ /* @__PURE__ */ e(P.Item, { label: "自定义 HTTP 头 (JSON)", name: "httpHeaders", children: /* @__PURE__ */ e(B.TextArea, { rows: 2, placeholder: '{"X-Trace-Id":"abc"}' }) }),
2983
+ /* @__PURE__ */ e(P.Item, { label: "请求体 (POST/PUT)", name: "requestBody", children: /* @__PURE__ */ e(B.TextArea, { rows: 3, placeholder: "(可选)" }) })
2984
+ ] })
2985
+ ] }),
2986
+ /* @__PURE__ */ n(L, { type: "inner", title: "鉴权 (从 z-mist 拉取 secret)", style: { marginBottom: 16 }, children: [
2987
+ /* @__PURE__ */ e(P.Item, { label: "鉴权方式", name: "authType", children: /* @__PURE__ */ e(V, { options: Rn }) }),
2988
+ g && g !== "NONE" && /* @__PURE__ */ e(
2989
+ P.Item,
2990
+ {
2991
+ label: "z-mist 凭据引用",
2992
+ name: "authSecretKey",
2993
+ extra: "从密钥中心 (z-mist) 选一个 secret; secret 的解密值会作为 secret 注入",
2994
+ children: /* @__PURE__ */ e(
2995
+ V,
2996
+ {
2997
+ showSearch: !0,
2998
+ allowClear: !0,
2999
+ placeholder: "选择 secret (key)",
3000
+ options: x.map((s) => ({
3001
+ value: s.secretKey,
3002
+ label: `${s.secretKey}${s.secretName ? " (" + s.secretName + ")" : ""}`
3003
+ }))
3004
+ }
3005
+ )
3006
+ }
3007
+ )
3008
+ ] }),
3009
+ /* @__PURE__ */ n(L, { type: "inner", title: "抽取器", style: { marginBottom: 16 }, children: [
3010
+ /* @__PURE__ */ e(
3011
+ P.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(V, { options: zn })
3018
+ }
3019
+ ),
3020
+ d === "CUSTOM_SCRIPT" && /* @__PURE__ */ e(
3021
+ P.Item,
3022
+ {
3023
+ label: "z-script 脚本",
3024
+ name: "extractorScriptCode",
3025
+ rules: [{ required: !0, message: "请选择脚本" }],
3026
+ extra: "在 智能中心 > 脚本中心 维护脚本. 脚本返回 { items: [...], nextCursor: '...' }",
3027
+ children: /* @__PURE__ */ e(
3028
+ V,
3029
+ {
3030
+ showSearch: !0,
3031
+ placeholder: "选择已启用的脚本",
3032
+ options: _.map((s) => ({
3033
+ value: s.scriptCode,
3034
+ label: `${s.scriptCode} (${s.dslType})${s.scriptName ? " - " + s.scriptName : ""}`
3035
+ }))
3036
+ }
3037
+ )
3038
+ }
3039
+ )
3040
+ ] }),
3041
+ /* @__PURE__ */ n(L, { type: "inner", title: "调度", style: { marginBottom: 16 }, children: [
3042
+ /* @__PURE__ */ e(
3043
+ P.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
+ V,
3051
+ {
3052
+ style: { width: 140 },
3053
+ placeholder: "常用",
3054
+ options: On,
3055
+ onChange: (s) => S.setFieldValue("cronExpr", s),
3056
+ value: null
3057
+ }
3058
+ ) })
3059
+ }
3060
+ ),
3061
+ /* @__PURE__ */ n(E, { size: "large", children: [
3062
+ /* @__PURE__ */ e(P.Item, { label: "启用", name: "enabled", valuePropName: "checked", children: /* @__PURE__ */ n(ne.Group, { children: [
3063
+ /* @__PURE__ */ e(ne.Button, { value: !0, children: "启用" }),
3064
+ /* @__PURE__ */ e(ne.Button, { value: !1, children: "停用" })
3065
+ ] }) }),
3066
+ /* @__PURE__ */ e(
3067
+ P.Item,
3068
+ {
3069
+ label: "最小间隔 (秒)",
3070
+ name: "minIntervalSec",
3071
+ extra: "距上次 run 至少 N 秒",
3072
+ children: /* @__PURE__ */ e(Re, { min: 0, max: 3600 })
3073
+ }
3074
+ ),
3075
+ /* @__PURE__ */ e(P.Item, { label: "单次最多条数", name: "maxItemsPerRun", children: /* @__PURE__ */ e(Re, { min: 1, max: 1e4 }) })
3076
+ ] })
3077
+ ] }),
3078
+ /* @__PURE__ */ e(
3079
+ Z,
3080
+ {
3081
+ type: "success",
3082
+ showIcon: !0,
3083
+ title: "保存后会自动 dry-run: 真实 HTTP 一次, 把响应喂给抽取器, 失败时订阅进入 INVALID_AUTH 状态, 不会自动调度."
3084
+ }
3085
+ )
3086
+ ]
3087
+ }
3088
+ ) }) })
3089
+ ] });
3090
+ }
3091
+ const Ln = {
3092
+ PENDING: "default",
3093
+ RUNNING: "processing",
3094
+ SUCCESS: "green",
3095
+ EMPTY: "default",
3096
+ FAILED: "red",
3097
+ FATAL: "red"
3098
+ };
3099
+ function Mn() {
3100
+ const [t, i] = m([]), [r, S] = m(null), [l, y] = m([]), [c, f] = m([]), [x, C] = m(null), [_, h] = m(!1);
3101
+ F(() => {
3102
+ a();
3103
+ }, []), F(() => {
3104
+ r && d(r);
3105
+ }, [r]);
3106
+ const a = async () => {
3107
+ try {
3108
+ const u = await $.get("/subscribe/subscription/list"), s = (u == null ? void 0 : u.data) ?? u ?? [];
3109
+ i(Array.isArray(s) ? s : []), Array.isArray(s) && s.length > 0 && S(s[0].id);
3110
+ } catch {
3111
+ b.error("加载订阅列表失败");
3112
+ }
3113
+ }, d = async (u) => {
3114
+ h(!0);
3115
+ try {
3116
+ const s = await $.get(`/subscribe/run/list?subscriptionId=${u}&limit=50`), I = (s == null ? void 0 : s.data) ?? s ?? [];
3117
+ y(Array.isArray(I) ? I : []);
3118
+ } catch {
3119
+ b.error("加载运行历史失败");
3120
+ } finally {
3121
+ h(!1);
3122
+ }
3123
+ }, g = async (u) => {
3124
+ C(u);
3125
+ try {
3126
+ const s = await $.get(`/subscribe/run/${u}/items?limit=200`), I = (s == null ? void 0 : s.data) ?? s ?? [];
3127
+ f(Array.isArray(I) ? I : []);
3128
+ } catch {
3129
+ b.error("加载抽取项失败");
3130
+ }
3131
+ }, v = l.reduce((u, s) => u + (s.successCount || 0), 0), D = l.reduce((u, s) => u + (s.deadLetterCount || 0), 0), T = l.reduce((u, s) => u + (s.duplicateCount || 0), 0);
3132
+ return /* @__PURE__ */ n("div", { children: [
3133
+ /* @__PURE__ */ e(
3134
+ ye,
3135
+ {
3136
+ title: "订阅中心 - 运行历史",
3137
+ subtitle: "查看各订阅的抽取运行记录与统计"
3138
+ }
3139
+ ),
3140
+ /* @__PURE__ */ e(
3141
+ Ft,
3142
+ {
3143
+ left: /* @__PURE__ */ e(
3144
+ V,
3145
+ {
3146
+ style: { width: 280 },
3147
+ placeholder: "选择订阅",
3148
+ value: r,
3149
+ onChange: S,
3150
+ options: t.map((u) => ({ value: u.id, label: u.name })),
3151
+ showSearch: !0,
3152
+ optionFilterProp: "label"
3153
+ }
3154
+ ),
3155
+ right: /* @__PURE__ */ n("a", { onClick: () => r && d(r), children: [
3156
+ /* @__PURE__ */ e(ee, {}),
3157
+ " 刷新"
3158
+ ] })
3159
+ }
3160
+ ),
3161
+ /* @__PURE__ */ n(Y, { gutter: 16, style: { marginBottom: 16 }, children: [
3162
+ /* @__PURE__ */ e(O, { span: 6, children: /* @__PURE__ */ e(L, { children: /* @__PURE__ */ e(K, { title: "run 总数", value: l.length }) }) }),
3163
+ /* @__PURE__ */ e(O, { span: 6, children: /* @__PURE__ */ e(L, { children: /* @__PURE__ */ e(
3164
+ K,
3165
+ {
3166
+ title: "成功条数",
3167
+ value: v,
3168
+ styles: { content: { color: "#3f8600" } }
3169
+ }
3170
+ ) }) }),
3171
+ /* @__PURE__ */ e(O, { span: 6, children: /* @__PURE__ */ e(L, { children: /* @__PURE__ */ e(
3172
+ K,
3173
+ {
3174
+ title: "死信条数",
3175
+ value: D,
3176
+ styles: { content: { color: "#cf1322" } }
3177
+ }
3178
+ ) }) }),
3179
+ /* @__PURE__ */ e(O, { span: 6, children: /* @__PURE__ */ e(L, { children: /* @__PURE__ */ e(K, { title: "重复跳过", value: T }) }) })
3180
+ ] }),
3181
+ /* @__PURE__ */ n(Y, { gutter: 16, children: [
3182
+ /* @__PURE__ */ e(O, { span: 12, children: /* @__PURE__ */ e(
3183
+ se,
3184
+ {
3185
+ cardTitle: `运行列表 (${l.length})`,
3186
+ rows: l,
3187
+ rowKey: "id",
3188
+ loading: _,
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: Ln[u], children: u })
3212
+ },
3213
+ {
3214
+ title: "拉取/成功/死信",
3215
+ width: 150,
3216
+ render: (u, s) => `${s.fetchedCount} / ${s.successCount} / ${s.deadLetterCount}`
3217
+ }
3218
+ ]
3219
+ }
3220
+ ) }),
3221
+ /* @__PURE__ */ e(O, { span: 12, children: /* @__PURE__ */ e(
3222
+ se,
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 s = JSON.parse(u);
3252
+ return s.link ? /* @__PURE__ */ e("a", { href: s.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 Dn() {
3271
+ return /* @__PURE__ */ n(ct, { children: [
3272
+ /* @__PURE__ */ e(re, { index: !0, element: /* @__PURE__ */ e(dt, { to: "list", replace: !0 }) }),
3273
+ /* @__PURE__ */ e(re, { path: "list", element: /* @__PURE__ */ e(Pn, {}) }),
3274
+ /* @__PURE__ */ e(re, { path: "new", element: /* @__PURE__ */ e(lt, {}) }),
3275
+ /* @__PURE__ */ e(re, { path: "edit/:id", element: /* @__PURE__ */ e(lt, {}) }),
3276
+ /* @__PURE__ */ e(re, { path: "runs", element: /* @__PURE__ */ e(Mn, {}) })
3277
+ ] });
3278
+ }
3279
+ const ir = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
3280
+ __proto__: null,
3281
+ default: Dn
3282
+ }, Symbol.toStringTag, { value: "Module" })), $n = {
3283
+ OPEN: { color: "blue", text: "待开始" },
3284
+ IN_PROGRESS: { color: "green", text: "进行中" },
3285
+ COMPLETED: { color: "default", text: "已完成" },
3286
+ ARCHIVED: { color: "default", text: "已归档" }
3287
+ };
3288
+ function Nn() {
3289
+ const t = xe(), [i, r] = m("mine"), [S, l] = m([]), [y, c] = m(!1), [f, x] = m(null), C = async () => {
3290
+ c(!0), x(null);
3291
+ try {
3292
+ const a = i === "mine" ? "/project/list/mine?limit=100" : `/project/list/by-status?status=${i}&limit=100`, d = await $.get(a), g = (d == null ? void 0 : d.data) ?? d ?? [];
3293
+ l(Array.isArray(g) ? g : []);
3294
+ } catch (a) {
3295
+ x((a == null ? void 0 : a.message) || (a == null ? void 0 : a.msg) || "加载失败");
3296
+ } finally {
3297
+ c(!1);
3298
+ }
3299
+ };
3300
+ F(() => {
3301
+ C();
3302
+ }, [i]);
3303
+ const _ = async (a) => {
3304
+ try {
3305
+ const d = await $.post(`/project/${a}/status?status=COMPLETED`);
3306
+ d && d.success !== !1 && (b.success("已标记完成"), C());
3307
+ } catch (d) {
3308
+ b.error("操作失败: " + ((d == null ? void 0 : d.message) || ""));
3309
+ }
3310
+ };
3311
+ return /* @__PURE__ */ n("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: C }) }),
3321
+ /* @__PURE__ */ n("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
+ ke,
3329
+ {
3330
+ activeKey: i,
3331
+ onChange: r,
3332
+ tabBarExtraContent: /* @__PURE__ */ n(E, { children: [
3333
+ /* @__PURE__ */ e(A, { icon: /* @__PURE__ */ e(ee, {}), onClick: C, loading: y, children: "刷新" }),
3334
+ /* @__PURE__ */ e(
3335
+ A,
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
+ se,
3354
+ {
3355
+ rows: S,
3356
+ columns: [
3357
+ { title: "ID", dataIndex: "id", width: 60 },
3358
+ {
3359
+ title: "名称",
3360
+ dataIndex: "name",
3361
+ render: (a, d) => /* @__PURE__ */ n(E, { orientation: "vertical", size: 0, children: [
3362
+ /* @__PURE__ */ e("a", { onClick: () => t(`/project/${d.id}`), style: { fontWeight: 500 }, children: a }),
3363
+ d.description && /* @__PURE__ */ e("span", { style: { color: "#999", fontSize: 12 }, children: d.description })
3364
+ ] })
3365
+ },
3366
+ { title: "来源", dataIndex: "sourceType", width: 100, render: (a) => /* @__PURE__ */ e(w, { children: a }) },
3367
+ {
3368
+ title: "订阅",
3369
+ dataIndex: "sourceSubscriptionId",
3370
+ width: 80,
3371
+ render: (a) => a ? `#${a}` : /* @__PURE__ */ e("span", { style: { color: "#ccc" }, children: "-" })
3372
+ },
3373
+ {
3374
+ title: "状态",
3375
+ dataIndex: "status",
3376
+ width: 100,
3377
+ render: (a) => {
3378
+ const d = $n[a] || { color: "default", text: a };
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: (a, d) => /* @__PURE__ */ n(w, { color: "blue", children: [
3387
+ d.contextSize || 0,
3388
+ "B"
3389
+ ] })
3390
+ },
3391
+ {
3392
+ title: "最近活动",
3393
+ dataIndex: "lastMessageAt",
3394
+ width: 150,
3395
+ render: (a) => a ? new Date(a).toLocaleString() : /* @__PURE__ */ e("span", { style: { color: "#ccc" }, children: "-" })
3396
+ },
3397
+ {
3398
+ title: "操作",
3399
+ width: 160,
3400
+ render: (a, d) => /* @__PURE__ */ n(E, { size: 4, children: [
3401
+ /* @__PURE__ */ e(A, { type: "link", size: "small", onClick: () => t(`/project/${d.id}`), children: "对话" }),
3402
+ d.status !== "COMPLETED" && d.status !== "ARCHIVED" && /* @__PURE__ */ e(
3403
+ Ue,
3404
+ {
3405
+ title: "标记为已完成?",
3406
+ onConfirm: () => _(d.id),
3407
+ okButtonProps: { danger: !0 },
3408
+ children: /* @__PURE__ */ e(A, { type: "link", size: "small", icon: /* @__PURE__ */ e(Fe, {}), 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 Bn = [
3430
+ { value: "general", label: "通用助手" },
3431
+ { value: "analyst", label: "分析师" },
3432
+ { value: "writer", label: "写手" },
3433
+ { value: "pm", label: "产品经理" },
3434
+ { value: "ops", label: "运营" }
3435
+ ];
3436
+ function jn() {
3437
+ const t = xe(), [i] = It(), [r] = P.useForm(), [S, l] = m(!1), [y, c] = m("from-subscribe"), [f, x] = m([]), [C, _] = m([]), [h, a] = m(!1), [d, g] = m([]), [v, D] = m(null);
3438
+ F(() => {
3439
+ const I = i.get("subscriptionId"), M = i.get("itemIds");
3440
+ I && (D(Number(I)), r.setFieldValue("sourceSubscriptionId", Number(I)), u(I)), M && g(M.split(",").map(Number).filter(Boolean));
3441
+ }, [i]), F(() => {
3442
+ T();
3443
+ }, []);
3444
+ const T = async () => {
3445
+ try {
3446
+ const I = await $.get("/subscribe/subscription/list"), M = (I == null ? void 0 : I.data) ?? I ?? [];
3447
+ x(Array.isArray(M) ? M.filter((J) => J.status === "VERIFIED") : []);
3448
+ } catch {
3449
+ }
3450
+ }, u = async (I) => {
3451
+ a(!0);
3452
+ try {
3453
+ const M = await $.get(`/subscribe/run/list?subscriptionId=${I}&limit=1`), J = (M == null ? void 0 : M.data) ?? M ?? [];
3454
+ if (J.length === 0) {
3455
+ _([]);
3456
+ return;
3457
+ }
3458
+ const H = J[0], p = await $.get(`/subscribe/run/${H.id}/items?limit=100`), o = (p == null ? void 0 : p.data) ?? p ?? [];
3459
+ _(Array.isArray(o) ? o : []);
3460
+ } catch {
3461
+ b.error("加载抽取项失败");
3462
+ } finally {
3463
+ a(!1);
3464
+ }
3465
+ };
3466
+ return /* @__PURE__ */ e("div", { style: { padding: 24 }, children: /* @__PURE__ */ e(
3467
+ L,
3468
+ {
3469
+ title: /* @__PURE__ */ n(E, { children: [
3470
+ /* @__PURE__ */ e(A, { type: "text", icon: /* @__PURE__ */ e(ft, {}), onClick: () => t("/project/list") }),
3471
+ /* @__PURE__ */ e(qe, {}),
3472
+ "新建项目 (立项)"
3473
+ ] }),
3474
+ extra: /* @__PURE__ */ n(E, { children: [
3475
+ /* @__PURE__ */ e(A, { onClick: () => t("/project/list"), children: "取消" }),
3476
+ /* @__PURE__ */ e(
3477
+ A,
3478
+ {
3479
+ type: "primary",
3480
+ icon: /* @__PURE__ */ e(gt, {}),
3481
+ loading: S,
3482
+ onClick: async () => {
3483
+ try {
3484
+ const I = await r.validateFields();
3485
+ if (y === "from-subscribe" && d.length === 0) {
3486
+ b.warning("请至少选 1 个 item");
3487
+ return;
3488
+ }
3489
+ l(!0);
3490
+ const M = {
3491
+ ...I,
3492
+ sourceItemIds: y === "from-subscribe" ? d.map(String) : null
3493
+ }, J = y === "from-subscribe" ? "/project/create-from-items" : "/project/create-manual", H = await $.post(J, M);
3494
+ if (H && H.success !== !1) {
3495
+ const p = H.data ?? H;
3496
+ b.success("立项成功"), t(`/project/${p.id}`);
3497
+ } else
3498
+ b.error((H == null ? void 0 : H.message) || "立项失败");
3499
+ } catch (I) {
3500
+ I != null && I.errorFields || b.error("立项失败: " + ((I == null ? void 0 : I.message) || ""));
3501
+ } finally {
3502
+ l(!1);
3503
+ }
3504
+ },
3505
+ children: "立项"
3506
+ }
3507
+ )
3508
+ ] }),
3509
+ children: /* @__PURE__ */ n(P, { form: r, layout: "vertical", initialValues: { agentRole: "general" }, children: [
3510
+ /* @__PURE__ */ e(P.Item, { label: "来源", children: /* @__PURE__ */ n(ne.Group, { value: y, onChange: (I) => c(I.target.value), children: [
3511
+ /* @__PURE__ */ e(ne.Button, { value: "from-subscribe", children: "从订阅线索立项 (主路径)" }),
3512
+ /* @__PURE__ */ e(ne.Button, { value: "manual", children: "手动立项 (无源数据)" })
3513
+ ] }) }),
3514
+ /* @__PURE__ */ e(P.Item, { label: "项目名称", name: "name", rules: [{ required: !0, message: "请输入名称" }], children: /* @__PURE__ */ e(B, { placeholder: "例如: 跟进 GitHub 高优 Issue" }) }),
3515
+ /* @__PURE__ */ e(P.Item, { label: "项目描述", name: "description", children: /* @__PURE__ */ e(B.TextArea, { rows: 2, placeholder: "(可选) 这个项目要解决什么?" }) }),
3516
+ y === "from-subscribe" && /* @__PURE__ */ n(L, { type: "inner", title: "源数据", style: { marginBottom: 16 }, children: [
3517
+ /* @__PURE__ */ e(
3518
+ P.Item,
3519
+ {
3520
+ label: "选择订阅",
3521
+ name: "sourceSubscriptionId",
3522
+ rules: [{ required: !0, message: "请选订阅" }],
3523
+ children: /* @__PURE__ */ e(
3524
+ V,
3525
+ {
3526
+ placeholder: "选择订阅 (拉取最近一次 run 的 items)",
3527
+ options: f.map((I) => ({ value: I.id, label: `#${I.id} ${I.name}` })),
3528
+ onChange: (I) => {
3529
+ D(I), u(I), g([]);
3530
+ }
3531
+ }
3532
+ )
3533
+ }
3534
+ ),
3535
+ v && /* @__PURE__ */ n(_e, { spinning: h, children: [
3536
+ /* @__PURE__ */ n("div", { style: { marginBottom: 8 }, children: [
3537
+ /* @__PURE__ */ n(w, { color: "blue", children: [
3538
+ "已选 ",
3539
+ d.length,
3540
+ " / ",
3541
+ C.length
3542
+ ] }),
3543
+ /* @__PURE__ */ e(
3544
+ A,
3545
+ {
3546
+ size: "small",
3547
+ onClick: () => g(C.map((I) => I.id)),
3548
+ children: "全选"
3549
+ }
3550
+ ),
3551
+ /* @__PURE__ */ e(
3552
+ A,
3553
+ {
3554
+ size: "small",
3555
+ onClick: () => g([]),
3556
+ style: { marginLeft: 4 },
3557
+ children: "清空"
3558
+ }
3559
+ )
3560
+ ] }),
3561
+ /* @__PURE__ */ e(
3562
+ se,
3563
+ {
3564
+ rows: C,
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: (I) => {
3581
+ try {
3582
+ return JSON.parse(I).title || "(无)";
3583
+ } catch {
3584
+ return I;
3585
+ }
3586
+ }
3587
+ },
3588
+ {
3589
+ title: "fetched",
3590
+ dataIndex: "fetchedAt",
3591
+ width: 150,
3592
+ render: (I) => I ? new Date(I).toLocaleString() : "-"
3593
+ }
3594
+ ]
3595
+ }
3596
+ )
3597
+ ] })
3598
+ ] }),
3599
+ /* @__PURE__ */ n(L, { type: "inner", title: "Agent 配置", style: { marginBottom: 16 }, children: [
3600
+ /* @__PURE__ */ e(P.Item, { label: "Agent 角色", name: "agentRole", extra: "决定 system prompt 的语气 / 视角", children: /* @__PURE__ */ e(V, { options: Bn }) }),
3601
+ /* @__PURE__ */ e(
3602
+ P.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
+ Z,
3613
+ {
3614
+ type: "info",
3615
+ showIcon: !0,
3616
+ title: "立项后源数据会被快照 (context_snapshot), 后续订阅更新不会影响项目上下文."
3617
+ }
3618
+ )
3619
+ ] })
3620
+ }
3621
+ ) });
3622
+ }
3623
+ const st = {
3624
+ USER: { color: "blue", icon: /* @__PURE__ */ e(ut, {}), label: "CEO" },
3625
+ ASSISTANT: { color: "purple", icon: /* @__PURE__ */ e($e, {}), label: "Agent" },
3626
+ SYSTEM: { color: "default", icon: null, label: "系统" }
3627
+ }, Un = {
3628
+ OPEN: { color: "blue", text: "待开始" },
3629
+ IN_PROGRESS: { color: "green", text: "进行中" },
3630
+ COMPLETED: { color: "default", text: "已完成" },
3631
+ ARCHIVED: { color: "default", text: "已归档" }
3632
+ };
3633
+ function qn() {
3634
+ const { id: t } = ot(), i = xe(), [r, S] = m(null), [l, y] = m([]), [c, f] = m(""), [x, C] = m(!1), _ = it(null);
3635
+ F(() => {
3636
+ t && h();
3637
+ }, [t]), F(() => {
3638
+ _.current && (_.current.scrollTop = _.current.scrollHeight);
3639
+ }, [l]);
3640
+ const h = async () => {
3641
+ try {
3642
+ const [v, D] = await Promise.all([
3643
+ $.get(`/project/${t}`),
3644
+ $.get(`/project/${t}/messages`)
3645
+ ]);
3646
+ S((v == null ? void 0 : v.data) ?? v), y(Array.isArray((D == null ? void 0 : D.data) ?? D) ? (D == null ? void 0 : D.data) ?? D : []);
3647
+ } catch {
3648
+ b.error("加载项目失败");
3649
+ }
3650
+ }, a = async () => {
3651
+ if (!c.trim()) return;
3652
+ const v = c.trim();
3653
+ f(""), C(!0);
3654
+ const D = { seq: -1, role: "USER", content: v, createdAt: (/* @__PURE__ */ new Date()).toISOString() };
3655
+ y((T) => [...T, D]);
3656
+ try {
3657
+ const T = await $.post(`/project/${t}/chat`, { message: v });
3658
+ if (T && T.success !== !1) {
3659
+ const s = (T.data ?? T).message;
3660
+ y((I) => [...I.filter((J) => J.seq !== -1), ...s ? [s] : []]), setTimeout(h, 100);
3661
+ } else
3662
+ b.error((T == null ? void 0 : T.message) || "发送失败");
3663
+ } catch (T) {
3664
+ b.error("发送失败: " + ((T == null ? void 0 : T.message) || ""));
3665
+ } finally {
3666
+ C(!1);
3667
+ }
3668
+ }, d = async () => {
3669
+ try {
3670
+ const v = await $.post(`/project/${t}/status?status=COMPLETED`);
3671
+ v && v.success !== !1 && (b.success("已标记完成"), h());
3672
+ } catch {
3673
+ b.error("操作失败");
3674
+ }
3675
+ };
3676
+ if (!r) return /* @__PURE__ */ e("div", { style: { padding: 24 }, children: /* @__PURE__ */ e(_e, {}) });
3677
+ const g = Un[r.status] || { color: "default", text: r.status };
3678
+ return /* @__PURE__ */ n("div", { style: { padding: 24, height: "calc(100vh - 64px)", display: "flex", flexDirection: "column", gap: 16 }, children: [
3679
+ /* @__PURE__ */ n(
3680
+ L,
3681
+ {
3682
+ title: /* @__PURE__ */ n(E, { children: [
3683
+ /* @__PURE__ */ e(A, { type: "text", icon: /* @__PURE__ */ e(ft, {}), onClick: () => i("/project/list") }),
3684
+ /* @__PURE__ */ e(qe, {}),
3685
+ /* @__PURE__ */ e("span", { style: { fontWeight: 500 }, children: r.name }),
3686
+ /* @__PURE__ */ e(w, { color: g.color, children: g.text })
3687
+ ] }),
3688
+ extra: /* @__PURE__ */ n(E, { children: [
3689
+ r.contextSize > 0 && /* @__PURE__ */ n(w, { color: "blue", children: [
3690
+ "上下文 ",
3691
+ r.contextSize,
3692
+ " B"
3693
+ ] }),
3694
+ /* @__PURE__ */ e(w, { children: r.agentRole }),
3695
+ r.modelCode && /* @__PURE__ */ e(w, { color: "purple", children: r.modelCode }),
3696
+ r.status !== "COMPLETED" && r.status !== "ARCHIVED" && /* @__PURE__ */ e(Ue, { title: "标记完成?", onConfirm: d, children: /* @__PURE__ */ e(A, { icon: /* @__PURE__ */ e(Fe, {}), children: "标记完成" }) })
3697
+ ] }),
3698
+ children: [
3699
+ r.description && /* @__PURE__ */ e("div", { style: { color: "#666", marginBottom: 8 }, children: r.description }),
3700
+ /* @__PURE__ */ n(E, { size: "large", children: [
3701
+ /* @__PURE__ */ e(K, { title: "消息数", value: r.messageCount || 0 }),
3702
+ r.sourceSubscriptionId && /* @__PURE__ */ e(K, { title: "来源订阅", value: `#${r.sourceSubscriptionId}` }),
3703
+ /* @__PURE__ */ e(
3704
+ K,
3705
+ {
3706
+ title: "立项",
3707
+ value: r.createdAt ? new Date(r.createdAt).toLocaleString() : "-"
3708
+ }
3709
+ )
3710
+ ] })
3711
+ ]
3712
+ }
3713
+ ),
3714
+ /* @__PURE__ */ n(
3715
+ L,
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: _, style: { flex: 1, overflow: "auto", padding: 16, background: "#fafafa" }, children: l.length === 0 ? /* @__PURE__ */ e(Tt, { description: "还没有消息, 跟 Agent 说点什么?" }) : /* @__PURE__ */ n(E, { orientation: "vertical", style: { width: "100%" }, size: "middle", children: [
3721
+ l.map((v) => {
3722
+ const D = st[v.role] || st.SYSTEM, T = v.role === "USER";
3723
+ return /* @__PURE__ */ e("div", { style: {
3724
+ display: "flex",
3725
+ justifyContent: T ? "flex-end" : "flex-start"
3726
+ }, children: /* @__PURE__ */ n("div", { style: {
3727
+ maxWidth: "70%",
3728
+ background: T ? "#1677ff" : "#fff",
3729
+ color: T ? "#fff" : "#000",
3730
+ border: T ? "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__ */ n(E, { size: 4, children: [
3736
+ D.icon,
3737
+ D.label,
3738
+ v.seq > 0 && /* @__PURE__ */ n("span", { children: [
3739
+ "#",
3740
+ v.seq
3741
+ ] }),
3742
+ v.latencyMs > 0 && /* @__PURE__ */ n("span", { children: [
3743
+ "· ",
3744
+ v.latencyMs,
3745
+ "ms"
3746
+ ] }),
3747
+ v.modelCode && /* @__PURE__ */ n("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__ */ n("div", { style: {
3756
+ background: "#fff",
3757
+ border: "1px solid #e8e8e8",
3758
+ borderRadius: 8,
3759
+ padding: "10px 14px"
3760
+ }, children: [
3761
+ /* @__PURE__ */ e(_e, { size: "small" }),
3762
+ " 思考中..."
3763
+ ] }) })
3764
+ ] }) }),
3765
+ r.status === "COMPLETED" || r.status === "ARCHIVED" ? /* @__PURE__ */ e(
3766
+ Z,
3767
+ {
3768
+ style: { margin: 12, marginBottom: 0 },
3769
+ type: "info",
3770
+ title: "项目已完成 / 归档, 不再接受新消息",
3771
+ showIcon: !0
3772
+ }
3773
+ ) : /* @__PURE__ */ n("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(), a());
3781
+ },
3782
+ placeholder: "输入消息, Enter 发送 (Shift+Enter 换行)",
3783
+ autoSize: { minRows: 1, maxRows: 6 },
3784
+ disabled: x
3785
+ }
3786
+ ),
3787
+ /* @__PURE__ */ e(
3788
+ A,
3789
+ {
3790
+ type: "primary",
3791
+ icon: /* @__PURE__ */ e(jt, {}),
3792
+ loading: x,
3793
+ onClick: a,
3794
+ disabled: !c.trim(),
3795
+ children: "发送"
3796
+ }
3797
+ )
3798
+ ] })
3799
+ ]
3800
+ }
3801
+ )
3802
+ ] });
3803
+ }
3804
+ function Kn() {
3805
+ return /* @__PURE__ */ n(ct, { children: [
3806
+ /* @__PURE__ */ e(re, { index: !0, element: /* @__PURE__ */ e(dt, { to: "list", replace: !0 }) }),
3807
+ /* @__PURE__ */ e(re, { path: "list", element: /* @__PURE__ */ e(Nn, {}) }),
3808
+ /* @__PURE__ */ e(re, { path: "new", element: /* @__PURE__ */ e(jn, {}) }),
3809
+ /* @__PURE__ */ e(re, { path: ":id", element: /* @__PURE__ */ e(qn, {}) })
3810
+ ] });
3811
+ }
3812
+ const or = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
3813
+ __proto__: null,
3814
+ default: Kn
3815
+ }, Symbol.toStringTag, { value: "Module" })), Fn = "# z-team-component\n\nz-team(团队工作台)的**跨仓唯一前端面**:把「多模式工作台 / 模式切换 / z-opc 业务套件聚合 / 订阅域 / 项目域」\n这一整套团队工作台页面收敛成一个可复用的 React 组件包,由主壳(z-opc 主前端)挂载。\n\n- **npm 包名**:`@yuku123/z-team-component`\n- **宿主接入**:双入口 —— `.`(`ZTeamApp` / `SubscribeApp` / `ProjectApp`)与 `./pages`(`routes` / `appMeta` / `menuItems`)\n- **后端**:与 z-opc 主壳同源的 `/api/**`(axios `baseURL = '/api'`,Cookie 模式 `withCredentials`)\n- **技术栈**:React 19 + antd 6 + react-router-dom 7 + vite(**library mode**,双入口 `index` / `pages`,\n 基座与全部 `@yuku123/*` 一律 **external**,由消费方用自己的 node_modules 解析)\n\n> ⚠ z-team 是**主壳的总控包**:它自己不承载某个业务域,而是把 z-opc 的业务套件(`/ctc/*`、`/ai/*`、`/config/*` …)\n> 聚合进工作台外壳里渲染。所以本文档描述的是 **z-team 自身的能力**(工作台 / 模式切换 / 套件聚合 / 订阅 / 项目)。\n\n---\n\n## 一、能力概览\n\n### 1.1 顶层路由(`src/pages-manifest.ts` 的 `routes`)\n\n| 路由 | 组件 | 能力 |\n|------|------|------|\n| `/team/subscribe` | `SubscribeApp` | 订阅域:订阅列表 / 编辑 / 运行历史 |\n| `/team/project` | `ProjectApp` | 项目域:项目列表 / 创建 / 详情 |\n| `/team/docs` | `ComponentDocPage` | 本文件渲染页(左侧 240px TOC + 右侧正文) |\n| `/team/:rest*` | `ZTeamApp` | **兜底**:`ZTeamApp` 内部按 `useLocation().pathname` 懒加载分发到下面 15 个域 |\n\n`menuItems`:`/team/subscribe`(订阅)/ `/team/project`(项目)/ `/team/workspace`(工作台)/ `/team/docs`(组件文档,末项)。\n\n### 1.2 `ZTeamApp` 顶层分发(`src/zteam-adapter/App.tsx`)\n\n| pathname | 渲染的域 | 源文件 |\n|----------|----------|--------|\n| `/workspace` | 工作台 | `src/zteam/pages/workspace/index.tsx` |\n| `/workspace/phone` | 移动端工作台 | `src/zteam/pages/workspace/phone/index.tsx` |\n| `/workspace/from-ticket` | 从工单进入 | `src/zteam/pages/workspace/from-ticket.tsx` |\n| `/workspace/from-scenario` | 从场景进入 | `src/zteam/pages/workspace/from-scenario.tsx` |\n| `/workspace/build-by-form` | 表单构建 | `src/zteam/pages/workspace/build-by-form.tsx` |\n| `/scenario` | 场景 | `src/zteam/pages/scenario/index.tsx` |\n| `/admin` | 管理后台(走工作台外壳的 admin 分支) | `src/zteam/pages/admin/index.tsx` |\n| `/welcome` | 产品介绍 | `src/zteam/pages/welcome/index.tsx` |\n| `/portal` | 场景入口 | `src/zteam/pages/portal/index.tsx` |\n| `/chatdemo` | 聊天演示 | `src/zteam/pages/chatdemo/index.tsx` |\n| `/embed/chat` | 嵌入式聊天 | `src/zteam/pages/embed/chat/index.tsx` |\n| `/change-log` | 变更记录 | `src/zteam/pages/change-log/index.tsx` |\n| `/docs` | **操作手册页**(52KB 手写暗色主题页,**与本文件的组件文档页不是一回事**) | `src/zteam/pages/docs/index.tsx` |\n\n`src/zteam/pages/` 下共 **15 个域目录**:`admin` / `agenthub-digital-brain-test` / `change-log` / `chatdemo` /\n`docs` / `download` / `embed` / `login` / `note` / `phone` / `portal` / `rpa` / `scenario` / `welcome` / `workspace`。\n其中 `agenthub-digital-brain-test` / `download` / `login` / `note` / `rpa` **没有** `ZTeamApp` 顶层分支,\n由域内路由或别的入口进入。\n\n### 1.3 工作台模式切换(`src/zteam/pages/workspace/utils/chatMode.ts`)\n\n`ChatMode` 共 13 种:`personal` / `collaboration` / `smart` / `product` / `dev` / `test` / `ops` / `admin` /\n`system` / `life` / `training` / `rpa` / `knowledge`(默认 `collaboration`)。\n\n模式切换统一走 `history.push` 到对应顶层路由(`Layout/index.tsx` 的 `handleModeSwitch`):\n\n| 模式 | 落点 |\n|------|------|\n| `system` | `/ctc/4a/account`(z-opc 业务路径;已在业务路径上时不重复跳) |\n| `test` | `/test/qa/dashboard` |\n| `admin` | `/admin?mode=admin` |\n| `rpa` | `/rpa/dashboard` |\n| 其余模式 | `/workspace?mode=xxx`(必须带 `?desktop=1`,否则窄视口会被重定向到移动端工作台) |\n\n模式持久化在 URL query 上(`?mode=xxx`,`replaceState` 不污染历史记录);\n`/admin*` → `admin`、`/ops/*` → `ops`、`/lc/*` → `dev` 由 `readModeFromUrl()` 自动识别。\n\n### 1.4 套件聚合(`src/zteam/pages/workspace/components/Layout/SystemShell.tsx`)\n\n`SystemShell` 用一张 `SYSTEM_ROUTES` 表把 **z-opc 的业务套件**接进工作台的右侧内容区,\n用 `matchSystemPath()` 做 pathname 匹配(精确 → 通配 `*` / 参数 `:param`),支持 `/ctc/*`、`/ai/*`、`/config/*`、\n`/task/*`、`/workflow/*`、`/schedule/*`、`/mist/*`、`/meta/*`、`/msg/*`、`/rpc/*`、`/kb/*`、`/product/*`、`/ops/*` 等前缀。\n\n## 二、导出面\n\n```js\n// 主入口(. 桶):工作台主壳 + 订阅 / 项目域 + 公共设施\nimport ZTeamApp, {SubscribeApp, ProjectApp, history, isTokenExpired, ComponentDocPage}\n from '@yuku123/z-team-component'\n\n// 宿主组装面(./pages 桶):路由清单 + 菜单\nimport {routes, appMeta, menuItems, ComponentDocPage} from '@yuku123/z-team-component/pages'\n```\n\n- `routes`:`/team/subscribe`、`/team/project`、`/team/docs`、`/team/:rest*`(兜底)。\n- `appMeta`:`{ title: 'z-team 团队工作台', short: 'team' }`。\n- `ComponentDocPage`:组件文档页,**主入口与 `./pages` 桶都具名导出**(名字全仓统一,主壳按这个名字取)。\n\n## 三、API 端点\n\n请求实例由 `src/common/services/api.js` 的 axios 工厂创建:`baseURL = '/api'`(可用 `configureBaseURL()` 改),\n`timeout = 15000`,`withCredentials = true`(**Cookie 模式,不设 Authorization Header**)。\n下表路径是 `src/common/services/`、`src/services/`、`src/subscribe/services/`、`src/project/services/` 里\n**实际调用**的路径(已补上 `/api` 前缀)。\n\n| 方法 | 路径 | 说明 |\n|---|---|---|\n| POST | `/api/ctc/authn/login` | 登录 |\n| GET | `/api/ctc/authn/my-tenants` | 我的租户 |\n| POST | `/api/ctc/authn/select-tenant` | 选择租户 |\n| POST | `/api/ctc/authn/switch-tenant` | 切换租户 |\n| GET | `/api/ctc/app-menu/tree` | 应用菜单树 |\n| GET/POST | `/api/ctc/ac/invitations`、`/accept`、`/redeem`、`/leave` | 邀请(加入 / 兑换 / 退出) |\n| GET/POST | `/api/ctc/ac/invitations/members`、`/members/{memberId}/remove`、`/{id}/revoke` | 邀请成员管理 |\n| GET/POST/PUT/DELETE | `/api/agent/team/workspace`、`/workspace/{id}` | Agent 团队工作区 |\n| GET | `/api/agent/team/workspace/list`、`/file-tree-by-path`、`/file-content` | 工作区列表 / 文件树 / 文件内容 |\n| GET/POST/PUT/DELETE | `/api/agent/team/work-item`、`/work-item/{id}` | 工作项 |\n| GET | `/api/agent/team/conversation/{conversationId}/work-items` | 会话下的工作项 |\n| POST | `/api/agent/skill/register`、`/heartbeat`、`/pull`、`/sync-logs` | 技能注册 / 心跳 / 拉取 / 日志回传 |\n| POST/GET | `/api/agent/skill/bind`、`/unbind`、`/bindings` | 技能绑定 |\n| GET/POST/DELETE | `/api/agent/instance/list`、`/get`、`/create`、`/create-container`、`/create-external`、`/destroy-container`、`/destroy-local-process`、`/agent-types`、`/health`、`/status` | Agent 实例(容器 / 外部 / 本地进程) |\n| POST/GET | `/api/bot/feedback`、`/feedback/recent`、`/feedback/score` | Bot 反馈 |\n| GET | `/api/skill/get`、`/api/skill/page` | 技能查询 |\n| GET/POST | `/api/task`、`/task/list`、`/task/complete`、`/task/move`、`/task/project/list` | 任务 |\n| GET/POST | `/api/project`、`/api/project/archive`、`/api/project/user/list` | 项目 |\n| GET/POST/PUT/DELETE | `/api/mock-platform/{environments,endpoints,scenarios,cases,recordings,...}` | Mock 平台(`z-script-web` 的 `MockPlatformController`) |\n| GET | `/api/{name}/list`、`/api/{name}/page`、`/api/{name}/byId` | 通用 CRUD 工厂(`makeApi(name)`,`src/common/services/api.js`) |\n\n各服务模块另有自己的探活端点(`/api/agentTeam/health`、`/api/ctcAc/health`、`/api/ctcAcDomain/health`、\n`/api/ctcSurl/health`、`/api/ctcUser/health`、`/api/job/health`、`/api/metaApp/health`、\n`/api/privateConfig/health`、`/api/webide/health`)。\n\n## 四、页面说明\n\n### 4.1 工作台(`src/zteam/pages/workspace/`)\n\n工作台是本包最大的域,含 `Layout`(顶栏 + 模式切换 + 内容区)、`ProductWorkbench` / `SmartWorkbench` /\n`DevWorkbench` / `OpsWorkbench` 等工作台壳,以及聊天、笔记、代码编辑、知识图谱等通用组件。\n\n### 4.2 套件聚合壳(`SystemShell`)\n\n工作台的「系统」模式用它把 z-opc 业务页面(账号 / 角色 / 应用 / 租户 / 组织 / 权限 / 短链 / 字典 / 审计 /\nwebide / Agent / LLM / MCP / 技能 / OSS / 任务 / 流程 / 调度 / 密钥 / 运维 等)渲染进工作台右侧内容区,\n而不是回到 z-opc 旧 Layout。\n\n### 4.3 订阅域(`src/subscribe/pages/`)\n\n`SubscribeApp` + `SubscriptionList` / `SubscriptionEdit` / `RunHistory`:订阅的列表、编辑与运行历史。\n\n### 4.4 项目域(`src/project/pages/`)\n\n`ProjectApp` + `ProjectList` / `ProjectCreate` / `ProjectDetail`:项目的列表、创建与详情。\n\n### 4.5 组件文档\n\n本文件。内容以 `?raw` 在编译期内联,零额外请求;左侧 240px TOC 随滚动联动。\n渲染用基座的 `ComponentDoc`(`@yuku123/z-frontend-common/ui`),不在本包重写 TOC / 两栏 / 滚动联动。\n\n## 五、配置\n\n| 配置项 | 默认值 | 说明 |\n|---|---|---|\n| `configureBaseURL(baseURL)` | `'/api'` | 改写 axios `baseURL`(`src/common/services/api.js`) |\n| 请求 `timeout` | `15000` | axios 实例默认值 |\n| `withCredentials` | `true` | Cookie 模式;**不设 Authorization Header** |\n| vite `external` | 25 个精确包 + 4 条前缀规则 | `react` / `react-dom` / `antd` / `@ant-design/icons` / `@yuku123/*` / `@zopc-mock/*` / `echarts/*` / `highlight.js/*` 等一律 external,**消费方必须自备** |\n| vite alias | `@` → `src/`、`@zteam` → `src/zteam/` | 仅 standalone 构建用;打包后路径已解析 |\n| 模式 URL 参数 | `?mode=xxx` | 持久化在 query 上;`collaboration` 是默认值,不写入 URL |\n| `?desktop=1` | — | 强制桌面版工作台(窄视口默认跳 `/workspace/phone`) |\n\n## 六、已知限制\n\n- **`/team/docs` 目前没有可达路径**:主壳 `z-opc-main-starter-frontend/src/domainRoutes.ts` 的 `DOMAINS` 数组里\n **没有注册 z-team 域**(截至 2026-10-23),所以 z-team 的 `routes` 清单还没有被主壳消费。\n ⇒ 需要主控决定是否接线(注册 z-team 域,或在主壳里显式挂 `ComponentDocPage`)。\n- **`ZTeamApp` 内部没有 `/team/docs` 分支**:它按**绝对 pathname** 分发(`/workspace`、`/scenario`、`/docs` …),\n 未知路径兜底渲染工作台。所以即使走了 `/team/:rest*` 兜底路由,`/team/docs` 也会落进工作台而不是文档页。\n (`ZTeamApp` 不在本批次的改动范围内,需要单独接线。)\n- **已有另一个「文档页」**:`src/zteam/pages/docs/index.tsx` 是 52KB 的手写暗色主题**操作手册**页,\n 路由是 `/docs`。它与本 §7 的**组件文档页**不是一回事(内容、样式、来源都不同),别混淆。\n- **本仓没有 `tsconfig.json`,构建不做类型检查**(`npm run build` = `vite build` + 产物守卫脚本)。\n 基座只发 JS 不发 `.d.ts`,`src/z-frontend-common-ui.d.ts` 是手写的最小声明;\n 新增基座组件时要同步补声明(当前该声明文件里**还没有** `ComponentDoc`,因为本包的文档页走的是 `.jsx`,不参与类型检查)。\n- **组件包必须 external 基座**:`@yuku123/z-frontend-common/ui` 在 dist 里保持裸 import,\n 消费方(主壳)必须自己装基座,否则会出现两份 UI 主题。\n- **工作台下的部分工作台壳仍在改造中**(`ProductWorkbench` / `SmartWorkbench` 等),页面结构可能继续变,\n 本文档只描述到「域 + 顶层路由 + 模式」这一层,域内二级页面未逐页展开。\n- **请求是 Cookie 模式**:后端 `SsoInterceptor` 靠 `Accept` / `Content-Type` 判断「是不是 API 请求」,\n 裸 `fetch` 不带 `Accept` 会被当成页面访问而 302 跳登录页(构建产物有 `guard-fetch-accept.mjs` 守卫)。\n\n## 七、变更记录\n\n| 版本 | 变更 |\n|---|---|\n| 0.2.30(未发布) | 新增组件文档页 `ComponentDocPage`(lead 008 §7):`src/DOC.md` + 基座 `ComponentDoc` 薄包装 + 菜单末项 `/team/docs` |\n| 0.2.30 | 工作台模式体系(13 种 `ChatMode`)+ `SystemShell` 套件聚合 + 订阅 / 项目双域 |\n";
3816
+ function cr() {
3817
+ return /* @__PURE__ */ e(Gt, { markdown: Fn, title: "组件文档 — z-team" });
3818
+ }
3819
+ export {
3820
+ cr as C,
3821
+ Be as E,
3822
+ Sn as M,
3823
+ sr as O,
3824
+ Kn as P,
3825
+ wn as R,
3826
+ Dn as S,
3827
+ xn as T,
3828
+ Qn as Z,
3829
+ er as a,
3830
+ lr as b,
3831
+ je as c,
3832
+ ar as d,
3833
+ tr as e,
3834
+ In as f,
3835
+ fn as g,
3836
+ Ge as h,
3837
+ ln as i,
3838
+ nr as j,
3839
+ ir as k,
3840
+ or as l,
3841
+ $ as r,
3842
+ dn as s
3843
+ };