@pactor-app/skills 1.33.0 → 1.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/pactor-prd/SKILL.md +20 -23
- package/pactor-prd/references/acceptance-checklist.md +1 -1
- package/pactor-prd/references/data-api.md +35 -0
- package/pactor-prd/references/incremental-wireframe-delta.md +8 -9
- package/pactor-prd/references/page-inventory-and-files.md +2 -2
- package/pactor-prd/references/page-templates.md +59 -12
- package/pactor-prd/references/project-structure.md +1 -1
- package/pactor-prd/template/README.md +4 -4
- package/pactor-prd/template/app/api/d/[...parts]/route.ts +80 -0
- package/pactor-prd/template/app/layout.tsx +1 -3
- package/pactor-prd/template/next-env.d.ts +2 -2
- package/pactor-prd/template/next.config.js +2 -2
- package/pactor-prd/template/package.json +4 -4
- package/pactor-prd/template/pnpm-lock.yaml +97 -97
- package/pactor-prd/template/src/pactor/App.tsx +3 -2
- package/pactor-prd/template/src/pactor/actions.ts +5 -431
- package/pactor-prd/template/src/pactor/config.ts +12 -4
- package/pactor-prd/template/src/server/yaml/common/dashboard.yaml +1 -1
- package/pactor-prd/template/src/server/yaml/common/login.yaml +46 -75
- package/pactor-prd/template/src/server/yaml/models/data-list.yaml +344 -0
- package/pactor-prd/template/src/server/yaml/provider/provider-detail.yaml +2 -2
- package/pactor-prd/template/src/server/yaml/provider/provider-edit.yaml +1 -1
- package/pactor-prd/template/src/server/yaml/provider/provider-list.yaml +1 -1
- package/pactor-prd/template/src/server/yaml/route/route-detail.yaml +1 -1
- package/pactor-prd/template/src/server/yaml/route/route-edit.yaml +1 -1
- package/pactor-prd/template/src/server/yaml/route/route-list.yaml +1 -1
- package/pactor-prd/template/src/server/yaml/sitemap.yaml +23 -6
- package/pactor-prd/references/mock-data-routes.md +0 -66
- package/pactor-prd/template/app/api/data/[...parts]/route.ts +0 -118
- package/pactor-prd/template/app/login.css +0 -122
- package/pactor-prd/template/src/pactor/mocks/audit-mock.ts +0 -403
- package/pactor-prd/template/src/pactor/mocks/call-logs-mock.ts +0 -875
- package/pactor-prd/template/src/pactor/mocks/client-debug-mock.ts +0 -188
- package/pactor-prd/template/src/pactor/mocks/client-templates-mock.ts +0 -497
- package/pactor-prd/template/src/pactor/mocks/clients-mock.ts +0 -483
- package/pactor-prd/template/src/pactor/mocks/costs-mock.ts +0 -406
- package/pactor-prd/template/src/pactor/mocks/dashboard-mock.ts +0 -192
- package/pactor-prd/template/src/pactor/mocks/model-debug-mock.ts +0 -144
- package/pactor-prd/template/src/pactor/mocks/models-mock.ts +0 -799
- package/pactor-prd/template/src/pactor/mocks/ops-usage-mock.ts +0 -806
- package/pactor-prd/template/src/pactor/mocks/providers-mock.ts +0 -424
- package/pactor-prd/template/src/pactor/mocks/routes-mock.ts +0 -604
- package/pactor-prd/template/src/pactor/services.ts +0 -185
|
@@ -1,483 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 客户端(访问治理)演示数据服务(MVP mock,静态页面)。
|
|
3
|
-
* client.list / client.detail 注册为 Pactor service;接入真实后端后替换为
|
|
4
|
-
* http / service 数据源,DSL 绑定路径保持不变。
|
|
5
|
-
* 数据形态对齐 PRD《访问治理/Client/01-列表页》《02-详情页》(③路由授权 / ④配额策略 /
|
|
6
|
-
* ⑤限流策略 线框图与客户端额外的 ② AppKey、用量行)。
|
|
7
|
-
* 共享子类型(AuthRoute / QuotaRule / RateLimitRule)从 client-templates-mock 导入,
|
|
8
|
-
* 客户端配额规则在其上扩展用量字段(ClientQuotaRule)。
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import {
|
|
12
|
-
authRouteSnapshot,
|
|
13
|
-
quotaSummaryOf,
|
|
14
|
-
rateLimitSummaryOf,
|
|
15
|
-
type AuthRoute,
|
|
16
|
-
type QuotaRule,
|
|
17
|
-
type RateLimitRule,
|
|
18
|
-
} from "./client-templates-mock";
|
|
19
|
-
|
|
20
|
-
export type ClientStatus = "enabled" | "disabled" | "expired";
|
|
21
|
-
|
|
22
|
-
/** 客户端配额规则:在模板规则之上带运行用量(Runtime 维护,控制台近实时展示) */
|
|
23
|
-
export interface ClientQuotaRule extends QuotaRule {
|
|
24
|
-
/** 已用量 */
|
|
25
|
-
usageUsed?: number;
|
|
26
|
-
/** 千分位已用量文案 */
|
|
27
|
-
usageUsedText?: string;
|
|
28
|
-
/** 用量百分比(Progress 组件 value 直接绑定) */
|
|
29
|
-
usagePercent?: number;
|
|
30
|
-
/** 下次重置时间(仅周期循环),如「今日 24:00」 */
|
|
31
|
-
nextResetAt?: string;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export interface ClientRecord {
|
|
35
|
-
code: string;
|
|
36
|
-
name: string;
|
|
37
|
-
tags: string[];
|
|
38
|
-
description: string;
|
|
39
|
-
status: ClientStatus;
|
|
40
|
-
/** 启用 / 停用 / 已过期 */
|
|
41
|
-
statusLabel: string;
|
|
42
|
-
/** 到期时间(绝对时间),如 2027-01-01 23:59:59 */
|
|
43
|
-
expiresAt: string;
|
|
44
|
-
/** AppKey ID,如 gw-ak-7f3a2b1c */
|
|
45
|
-
appKeyId: string;
|
|
46
|
-
/** Secret 上次轮换时间 */
|
|
47
|
-
secretLastRotatedAt: string;
|
|
48
|
-
/** 来源模板(空白创建时为空) */
|
|
49
|
-
templateCode?: string;
|
|
50
|
-
templateName?: string;
|
|
51
|
-
authRoutes: AuthRoute[];
|
|
52
|
-
quotas: ClientQuotaRule[];
|
|
53
|
-
rateLimits: RateLimitRule[];
|
|
54
|
-
createdAt: string;
|
|
55
|
-
updatedAt: string;
|
|
56
|
-
operator: string;
|
|
57
|
-
// ── 预计算摘要(表达式不适合拼接复合文案) ──
|
|
58
|
-
routeCount: number;
|
|
59
|
-
quotaSummary: string;
|
|
60
|
-
rateLimitSummary: string;
|
|
61
|
-
tagsText: string;
|
|
62
|
-
/** Header 摘要:`gw-ak-7f3a2b1c · 到期 2027-01-01 · 3 路由 · 1000 RPM` */
|
|
63
|
-
appKeySummary: string;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export interface ClientListParams {
|
|
67
|
-
/** all | enabled | disabled | expired */
|
|
68
|
-
status?: string;
|
|
69
|
-
/** 名称模糊匹配 */
|
|
70
|
-
name?: string;
|
|
71
|
-
/** 标识模糊匹配 */
|
|
72
|
-
code?: string;
|
|
73
|
-
/** 标签多选(取交集) */
|
|
74
|
-
tags?: string[];
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/** 快筛 Chip 计数(数据构成口径,不随筛选变化) */
|
|
78
|
-
export interface ClientCounts {
|
|
79
|
-
all: { enabled: number; total: number };
|
|
80
|
-
status: Record<ClientStatus, number>;
|
|
81
|
-
/** 键为标签的表达式安全形式(连字符转下划线) */
|
|
82
|
-
tags: Record<string, number>;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/** 快筛 Chip 选项(ChipFilter 组件入项;文案在接口侧预计算) */
|
|
86
|
-
export interface ClientChipOption {
|
|
87
|
-
value: string;
|
|
88
|
-
text: string;
|
|
89
|
-
dot?: string;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
export interface ClientListResult {
|
|
93
|
-
items: ClientRecord[];
|
|
94
|
-
total: number;
|
|
95
|
-
counts: ClientCounts;
|
|
96
|
-
/** 快筛 Chip 组:tags 多选(含「全部」,点击清空) */
|
|
97
|
-
filters: { tags: ClientChipOption[] };
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
export const CLIENT_STATUS_LABELS: Record<ClientStatus, string> = {
|
|
101
|
-
enabled: "启用",
|
|
102
|
-
disabled: "停用",
|
|
103
|
-
expired: "已过期",
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
/** 用量行文案:`已用 3,240,000 / 10,000,000(32.4%)` */
|
|
107
|
-
export function usageSummaryOf(rule: ClientQuotaRule): string {
|
|
108
|
-
if (rule.usageUsed == null || rule.usagePercent == null) return "";
|
|
109
|
-
return `已用 ${rule.usageUsedText} / ${rule.limitText}(${rule.usagePercent}%)`;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/** 客户端配额规则用量字段派生 */
|
|
113
|
-
function deriveClientQuota(
|
|
114
|
-
rule: ClientQuotaRule,
|
|
115
|
-
): ClientQuotaRule {
|
|
116
|
-
const usageUsedText =
|
|
117
|
-
rule.usageUsed != null ? rule.usageUsed.toLocaleString("en-US") : undefined;
|
|
118
|
-
return { ...rule, usageUsedText };
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/** 列表/详情页摘要字段派生 */
|
|
122
|
-
function derive(
|
|
123
|
-
record: Omit<
|
|
124
|
-
ClientRecord,
|
|
125
|
-
| "statusLabel"
|
|
126
|
-
| "routeCount"
|
|
127
|
-
| "quotaSummary"
|
|
128
|
-
| "rateLimitSummary"
|
|
129
|
-
| "tagsText"
|
|
130
|
-
| "appKeySummary"
|
|
131
|
-
>,
|
|
132
|
-
): ClientRecord {
|
|
133
|
-
const rateLimitSummary = rateLimitSummaryOf(record.rateLimits);
|
|
134
|
-
return {
|
|
135
|
-
...record,
|
|
136
|
-
quotas: record.quotas.map(deriveClientQuota),
|
|
137
|
-
statusLabel: CLIENT_STATUS_LABELS[record.status],
|
|
138
|
-
routeCount: record.authRoutes.length,
|
|
139
|
-
quotaSummary: quotaSummaryOf(record.quotas),
|
|
140
|
-
rateLimitSummary,
|
|
141
|
-
tagsText: record.tags.join(" · "),
|
|
142
|
-
appKeySummary: `${record.appKeyId} · 到期 ${record.expiresAt.slice(0, 10)} · ${record.authRoutes.length} 路由 · ${rateLimitSummary}`,
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const CLIENTS: ClientRecord[] = [
|
|
147
|
-
derive({
|
|
148
|
-
code: "agent-app",
|
|
149
|
-
name: "agent-app",
|
|
150
|
-
tags: ["agent", "prod"],
|
|
151
|
-
description: "Agent 平台默认调用客户端",
|
|
152
|
-
status: "enabled",
|
|
153
|
-
expiresAt: "2027-01-01 23:59:59",
|
|
154
|
-
appKeyId: "gw-ak-7f3a2b1c",
|
|
155
|
-
secretLastRotatedAt: "2026-07-15",
|
|
156
|
-
templateCode: "agent-default",
|
|
157
|
-
templateName: "agent-default",
|
|
158
|
-
authRoutes: [
|
|
159
|
-
authRouteSnapshot("reasoning-default"),
|
|
160
|
-
authRouteSnapshot("general-chat"),
|
|
161
|
-
authRouteSnapshot("mobile-lite"),
|
|
162
|
-
],
|
|
163
|
-
quotas: [
|
|
164
|
-
{
|
|
165
|
-
name: "lifetime-total",
|
|
166
|
-
quotaType: "lifetime",
|
|
167
|
-
quotaTypeLabel: "总配额",
|
|
168
|
-
metric: "TOTAL_TOKEN",
|
|
169
|
-
metricLabel: "Total Token",
|
|
170
|
-
limit: 10000000,
|
|
171
|
-
limitText: "10,000,000",
|
|
172
|
-
mode: "hard",
|
|
173
|
-
modeLabel: "Hard Limit",
|
|
174
|
-
status: "enabled",
|
|
175
|
-
usageUsed: 3240000,
|
|
176
|
-
usagePercent: 32.4,
|
|
177
|
-
},
|
|
178
|
-
{
|
|
179
|
-
name: "daily-token-cap",
|
|
180
|
-
quotaType: "cyclic",
|
|
181
|
-
quotaTypeLabel: "周期循环配额",
|
|
182
|
-
metric: "TOTAL_TOKEN",
|
|
183
|
-
metricLabel: "Total Token",
|
|
184
|
-
limit: 500000,
|
|
185
|
-
limitText: "500,000",
|
|
186
|
-
mode: "soft",
|
|
187
|
-
modeLabel: "Soft Limit",
|
|
188
|
-
cycleUnit: "hour",
|
|
189
|
-
cycleValue: 24,
|
|
190
|
-
cycleLabel: "每 24 小时",
|
|
191
|
-
status: "enabled",
|
|
192
|
-
usageUsed: 120000,
|
|
193
|
-
usagePercent: 24,
|
|
194
|
-
nextResetAt: "今日 24:00",
|
|
195
|
-
},
|
|
196
|
-
],
|
|
197
|
-
rateLimits: [
|
|
198
|
-
{
|
|
199
|
-
name: "app-rpm",
|
|
200
|
-
limitType: "RPM",
|
|
201
|
-
limitTypeLabel: "RPM(每分钟请求数)",
|
|
202
|
-
limit: 1000,
|
|
203
|
-
limitText: "1,000",
|
|
204
|
-
burst: 100,
|
|
205
|
-
scopeAll: true,
|
|
206
|
-
scopeLabel: "全部授权路由",
|
|
207
|
-
status: "enabled",
|
|
208
|
-
},
|
|
209
|
-
{
|
|
210
|
-
name: "concurrent-cap",
|
|
211
|
-
limitType: "CONCURRENT",
|
|
212
|
-
limitTypeLabel: "Concurrent(并发连接数)",
|
|
213
|
-
limit: 50,
|
|
214
|
-
limitText: "50",
|
|
215
|
-
scopeAll: true,
|
|
216
|
-
scopeLabel: "全部授权路由",
|
|
217
|
-
status: "enabled",
|
|
218
|
-
},
|
|
219
|
-
],
|
|
220
|
-
createdAt: "2026-06-06 11:00",
|
|
221
|
-
updatedAt: "2026-09-15 09:20",
|
|
222
|
-
operator: "张三",
|
|
223
|
-
}),
|
|
224
|
-
derive({
|
|
225
|
-
code: "web-portal",
|
|
226
|
-
name: "web-portal",
|
|
227
|
-
tags: ["web", "prod"],
|
|
228
|
-
description: "Web 门户前端调用客户端",
|
|
229
|
-
status: "enabled",
|
|
230
|
-
expiresAt: "2027-12-31 23:59:59",
|
|
231
|
-
appKeyId: "gw-ak-9c1d4e5f",
|
|
232
|
-
secretLastRotatedAt: "2026-08-01",
|
|
233
|
-
templateCode: "web-portal-base",
|
|
234
|
-
templateName: "web-portal-base",
|
|
235
|
-
authRoutes: [authRouteSnapshot("general-chat")],
|
|
236
|
-
quotas: [
|
|
237
|
-
{
|
|
238
|
-
name: "weekly-request-cap",
|
|
239
|
-
quotaType: "cyclic",
|
|
240
|
-
quotaTypeLabel: "周期循环配额",
|
|
241
|
-
metric: "REQUEST",
|
|
242
|
-
metricLabel: "Request",
|
|
243
|
-
limit: 100000,
|
|
244
|
-
limitText: "100,000",
|
|
245
|
-
mode: "soft",
|
|
246
|
-
modeLabel: "Soft Limit",
|
|
247
|
-
cycleUnit: "day",
|
|
248
|
-
cycleValue: 7,
|
|
249
|
-
cycleLabel: "每 7 天",
|
|
250
|
-
status: "enabled",
|
|
251
|
-
usageUsed: 12300,
|
|
252
|
-
usagePercent: 12.3,
|
|
253
|
-
nextResetAt: "2026-09-22 00:00",
|
|
254
|
-
},
|
|
255
|
-
],
|
|
256
|
-
rateLimits: [
|
|
257
|
-
{
|
|
258
|
-
name: "web-rpm",
|
|
259
|
-
limitType: "RPM",
|
|
260
|
-
limitTypeLabel: "RPM(每分钟请求数)",
|
|
261
|
-
limit: 500,
|
|
262
|
-
limitText: "500",
|
|
263
|
-
scopeAll: true,
|
|
264
|
-
scopeLabel: "全部授权路由",
|
|
265
|
-
status: "enabled",
|
|
266
|
-
},
|
|
267
|
-
],
|
|
268
|
-
createdAt: "2026-07-02 10:00",
|
|
269
|
-
updatedAt: "2026-09-10 16:40",
|
|
270
|
-
operator: "李四",
|
|
271
|
-
}),
|
|
272
|
-
derive({
|
|
273
|
-
code: "internal-batch",
|
|
274
|
-
name: "internal-batch",
|
|
275
|
-
tags: ["batch", "internal"],
|
|
276
|
-
description: "内部离线批处理任务客户端(空白创建)",
|
|
277
|
-
status: "enabled",
|
|
278
|
-
expiresAt: "2027-06-30 23:59:59",
|
|
279
|
-
appKeyId: "gw-ak-2b8e6a0d",
|
|
280
|
-
secretLastRotatedAt: "2026-09-01",
|
|
281
|
-
authRoutes: [
|
|
282
|
-
authRouteSnapshot("reasoning-default"),
|
|
283
|
-
authRouteSnapshot("embeddings-std"),
|
|
284
|
-
],
|
|
285
|
-
quotas: [
|
|
286
|
-
{
|
|
287
|
-
name: "lifetime-total",
|
|
288
|
-
quotaType: "lifetime",
|
|
289
|
-
quotaTypeLabel: "总配额",
|
|
290
|
-
metric: "TOTAL_TOKEN",
|
|
291
|
-
metricLabel: "Total Token",
|
|
292
|
-
limit: 50000000,
|
|
293
|
-
limitText: "50,000,000",
|
|
294
|
-
mode: "hard",
|
|
295
|
-
modeLabel: "Hard Limit",
|
|
296
|
-
status: "enabled",
|
|
297
|
-
usageUsed: 8500000,
|
|
298
|
-
usagePercent: 17,
|
|
299
|
-
},
|
|
300
|
-
],
|
|
301
|
-
rateLimits: [
|
|
302
|
-
{
|
|
303
|
-
name: "batch-tpm",
|
|
304
|
-
limitType: "TPM",
|
|
305
|
-
limitTypeLabel: "TPM(每分钟 Token 数)",
|
|
306
|
-
limit: 2000000,
|
|
307
|
-
limitText: "2,000,000",
|
|
308
|
-
burst: 200000,
|
|
309
|
-
scopeAll: true,
|
|
310
|
-
scopeLabel: "全部授权路由",
|
|
311
|
-
status: "enabled",
|
|
312
|
-
},
|
|
313
|
-
],
|
|
314
|
-
createdAt: "2026-08-10 14:30",
|
|
315
|
-
updatedAt: "2026-09-08 20:15",
|
|
316
|
-
operator: "王五",
|
|
317
|
-
}),
|
|
318
|
-
derive({
|
|
319
|
-
code: "legacy-mobile",
|
|
320
|
-
name: "legacy-mobile",
|
|
321
|
-
tags: ["mobile", "legacy"],
|
|
322
|
-
description: "旧版移动端 App 调用客户端(已停用,待下线)",
|
|
323
|
-
status: "disabled",
|
|
324
|
-
expiresAt: "2026-12-31 23:59:59",
|
|
325
|
-
appKeyId: "gw-ak-5d7c9b2e",
|
|
326
|
-
secretLastRotatedAt: "2026-03-12",
|
|
327
|
-
authRoutes: [authRouteSnapshot("mobile-lite")],
|
|
328
|
-
quotas: [
|
|
329
|
-
{
|
|
330
|
-
name: "weekly-request-cap",
|
|
331
|
-
quotaType: "cyclic",
|
|
332
|
-
quotaTypeLabel: "周期循环配额",
|
|
333
|
-
metric: "REQUEST",
|
|
334
|
-
metricLabel: "Request",
|
|
335
|
-
limit: 50000,
|
|
336
|
-
limitText: "50,000",
|
|
337
|
-
mode: "soft",
|
|
338
|
-
modeLabel: "Soft Limit",
|
|
339
|
-
cycleUnit: "day",
|
|
340
|
-
cycleValue: 7,
|
|
341
|
-
cycleLabel: "每 7 天",
|
|
342
|
-
status: "disabled",
|
|
343
|
-
usageUsed: 0,
|
|
344
|
-
usagePercent: 0,
|
|
345
|
-
},
|
|
346
|
-
],
|
|
347
|
-
rateLimits: [
|
|
348
|
-
{
|
|
349
|
-
name: "mobile-rpm",
|
|
350
|
-
limitType: "RPM",
|
|
351
|
-
limitTypeLabel: "RPM(每分钟请求数)",
|
|
352
|
-
limit: 200,
|
|
353
|
-
limitText: "200",
|
|
354
|
-
scopeAll: true,
|
|
355
|
-
scopeLabel: "全部授权路由",
|
|
356
|
-
status: "disabled",
|
|
357
|
-
},
|
|
358
|
-
],
|
|
359
|
-
createdAt: "2026-05-15 09:00",
|
|
360
|
-
updatedAt: "2026-08-20 18:00",
|
|
361
|
-
operator: "李四",
|
|
362
|
-
}),
|
|
363
|
-
derive({
|
|
364
|
-
code: "expired-trial",
|
|
365
|
-
name: "expired-trial",
|
|
366
|
-
tags: ["trial"],
|
|
367
|
-
description: "试用体验客户端(到期自动失效)",
|
|
368
|
-
status: "expired",
|
|
369
|
-
expiresAt: "2026-08-31 23:59:59",
|
|
370
|
-
appKeyId: "gw-ak-0a4f8c6b",
|
|
371
|
-
secretLastRotatedAt: "2026-07-01",
|
|
372
|
-
authRoutes: [authRouteSnapshot("general-chat")],
|
|
373
|
-
quotas: [
|
|
374
|
-
{
|
|
375
|
-
name: "lifetime-request",
|
|
376
|
-
quotaType: "lifetime",
|
|
377
|
-
quotaTypeLabel: "总配额",
|
|
378
|
-
metric: "REQUEST",
|
|
379
|
-
metricLabel: "Request",
|
|
380
|
-
limit: 10000,
|
|
381
|
-
limitText: "10,000",
|
|
382
|
-
mode: "hard",
|
|
383
|
-
modeLabel: "Hard Limit",
|
|
384
|
-
status: "enabled",
|
|
385
|
-
usageUsed: 10000,
|
|
386
|
-
usagePercent: 100,
|
|
387
|
-
},
|
|
388
|
-
],
|
|
389
|
-
rateLimits: [
|
|
390
|
-
{
|
|
391
|
-
name: "trial-rpm",
|
|
392
|
-
limitType: "RPM",
|
|
393
|
-
limitTypeLabel: "RPM(每分钟请求数)",
|
|
394
|
-
limit: 60,
|
|
395
|
-
limitText: "60",
|
|
396
|
-
scopeAll: true,
|
|
397
|
-
scopeLabel: "全部授权路由",
|
|
398
|
-
status: "enabled",
|
|
399
|
-
},
|
|
400
|
-
],
|
|
401
|
-
createdAt: "2026-07-01 09:00",
|
|
402
|
-
updatedAt: "2026-09-01 00:05",
|
|
403
|
-
operator: "张三",
|
|
404
|
-
}),
|
|
405
|
-
];
|
|
406
|
-
|
|
407
|
-
/** 快筛选项常量:状态(单选)与标签(多选) */
|
|
408
|
-
export const CLIENT_STATUS_OPTIONS: { value: string; label: string }[] = [
|
|
409
|
-
{ value: "all", label: "全部" },
|
|
410
|
-
{ value: "enabled", label: "启用" },
|
|
411
|
-
{ value: "disabled", label: "停用" },
|
|
412
|
-
{ value: "expired", label: "已过期" },
|
|
413
|
-
];
|
|
414
|
-
|
|
415
|
-
/** 标签快筛(按数据中出现顺序展示;多选取交集) */
|
|
416
|
-
export const CLIENT_TAG_FILTERS: { value: string; label: string }[] = [
|
|
417
|
-
...new Set(CLIENTS.flatMap((c) => c.tags)),
|
|
418
|
-
].map((t) => ({ value: t, label: t }));
|
|
419
|
-
|
|
420
|
-
/** 快筛计数:基于全量数据(构成口径,与当前筛选无关) */
|
|
421
|
-
function computeCounts(): ClientCounts {
|
|
422
|
-
return {
|
|
423
|
-
all: {
|
|
424
|
-
enabled: CLIENTS.filter((c) => c.status === "enabled").length,
|
|
425
|
-
total: CLIENTS.length,
|
|
426
|
-
},
|
|
427
|
-
status: {
|
|
428
|
-
enabled: CLIENTS.filter((c) => c.status === "enabled").length,
|
|
429
|
-
disabled: CLIENTS.filter((c) => c.status === "disabled").length,
|
|
430
|
-
expired: CLIENTS.filter((c) => c.status === "expired").length,
|
|
431
|
-
},
|
|
432
|
-
tags: CLIENT_TAG_FILTERS.reduce<Record<string, number>>((acc, t) => {
|
|
433
|
-
const key = t.value.replace(/-/g, "_");
|
|
434
|
-
acc[key] = CLIENTS.filter((c) => c.tags.includes(t.value)).length;
|
|
435
|
-
return acc;
|
|
436
|
-
}, {}),
|
|
437
|
-
};
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
/** 快筛 Chip 选项:由计数派生,文案在此预计算(表达式不支持复合文案拼接) */
|
|
441
|
-
function computeFilters(counts: ClientCounts): ClientListResult["filters"] {
|
|
442
|
-
return {
|
|
443
|
-
tags: [
|
|
444
|
-
{ value: "all", text: `全部 ${counts.all.total}` },
|
|
445
|
-
...CLIENT_TAG_FILTERS.map((t) => ({
|
|
446
|
-
value: t.value,
|
|
447
|
-
text: `${t.label} ${counts.tags[t.value.replace(/-/g, "_")]}`,
|
|
448
|
-
})),
|
|
449
|
-
],
|
|
450
|
-
};
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
/** client.list:状态单选 + 名称/标识模糊 + 标签多选取交集,按 Updated At 降序 */
|
|
454
|
-
export function queryClients(params: ClientListParams = {}): ClientListResult {
|
|
455
|
-
const status = params.status ?? "all";
|
|
456
|
-
const name = (params.name ?? "").trim().toLowerCase();
|
|
457
|
-
const code = (params.code ?? "").trim().toLowerCase();
|
|
458
|
-
const tags = params.tags ?? [];
|
|
459
|
-
const items = CLIENTS.filter(
|
|
460
|
-
(c) =>
|
|
461
|
-
(status === "all" || c.status === status) &&
|
|
462
|
-
(name === "" || c.name.toLowerCase().includes(name)) &&
|
|
463
|
-
(code === "" || c.code.toLowerCase().includes(code)) &&
|
|
464
|
-
(tags.length === 0 || tags.every((t) => c.tags.includes(t))),
|
|
465
|
-
).sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
|
|
466
|
-
const counts = computeCounts();
|
|
467
|
-
return { items, total: CLIENTS.length, counts, filters: computeFilters(counts) };
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
/** client.detail:按客户端标识取详情;未命中返回 undefined(页面做空态) */
|
|
471
|
-
export function getClient(code: string): ClientRecord | undefined {
|
|
472
|
-
return CLIENTS.find((c) => c.code === code);
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
/** 模板详情「已创建客户端」表:返回来源于该模板的客户端 */
|
|
476
|
-
export function clientsByTemplate(templateCode: string): ClientRecord[] {
|
|
477
|
-
return CLIENTS.filter((c) => c.templateCode === templateCode).sort((a, b) =>
|
|
478
|
-
b.updatedAt.localeCompare(a.updatedAt),
|
|
479
|
-
);
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
/** 全量客户端标识(静态导出 generateStaticParams 用) */
|
|
483
|
-
export const CLIENT_CODES: string[] = CLIENTS.map((c) => c.code);
|