@pactor-app/skills 1.34.0 → 1.40.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-dsl/SKILL.md +28 -1
- package/pactor-dsl/references/dsl-authoring.md +174 -36
- package/pactor-prd/SKILL.md +20 -21
- package/pactor-prd/references/acceptance-checklist.md +1 -1
- package/pactor-prd/references/component-mapping.md +1 -1
- package/pactor-prd/references/data-api.md +37 -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.config.js +2 -2
- 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/components/index.ts +1 -4
- 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 +4 -4
- 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 +2 -6
- package/pactor-prd/references/mock-data-routes.md +0 -66
- package/pactor-prd/template/app/api/data/[...parts]/route.ts +0 -160
- package/pactor-prd/template/app/login.css +0 -122
- package/pactor-prd/template/src/pactor/components/chip-filter.tsx +0 -89
- package/pactor-prd/template/src/pactor/components/chip-node.tsx +0 -46
- 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/data-list-mock.ts +0 -84
- 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 -200
|
@@ -1,424 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Provider 演示数据服务(MVP mock,静态页面)。
|
|
3
|
-
* provider.list / provider.detail / provider.pullModels 注册为 Pactor
|
|
4
|
-
* service;接入真实后端后替换为 http / service 数据源,DSL 绑定路径保持不变。
|
|
5
|
-
* 数据形态对齐 PRD《01-Provider列表页》《02-Provider详情页》(§7.1)。
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
export type ProviderStatus = "enabled" | "disabled";
|
|
9
|
-
/** configured=已配置;pending=已创建但密钥未保存(模板导入待补齐);none=未配置密钥 */
|
|
10
|
-
export type KeyStatus = "configured" | "pending" | "none";
|
|
11
|
-
|
|
12
|
-
export interface ProviderModel {
|
|
13
|
-
code: string;
|
|
14
|
-
name: string;
|
|
15
|
-
type: string;
|
|
16
|
-
providerModelId: string;
|
|
17
|
-
pricing: string;
|
|
18
|
-
status: "ONLINE" | "OFFLINE";
|
|
19
|
-
routes: number;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export interface ProviderRecord {
|
|
23
|
-
code: string;
|
|
24
|
-
name: string;
|
|
25
|
-
/** 同名多实例区分展示名,如 DeepSeek (2) */
|
|
26
|
-
displayName: string;
|
|
27
|
-
/** Icon 白名单图标名 */
|
|
28
|
-
icon: string;
|
|
29
|
-
providerType: string;
|
|
30
|
-
protocol: string;
|
|
31
|
-
/** 类型/协议快筛聚合键(内置模板族) */
|
|
32
|
-
family: "openai" | "anthropic" | "gemini" | "dashscope";
|
|
33
|
-
status: ProviderStatus;
|
|
34
|
-
keyStatus: KeyStatus;
|
|
35
|
-
baseUrl: string;
|
|
36
|
-
region: string;
|
|
37
|
-
timeout: number;
|
|
38
|
-
proxy: string;
|
|
39
|
-
maskedKey: string;
|
|
40
|
-
lastTest: { time: string; ok: boolean; detail: string } | null;
|
|
41
|
-
capabilities: string[];
|
|
42
|
-
routes: { total: number; enabled: number };
|
|
43
|
-
/** 路由摘要(预计算:表达式不适合拼接复合文案) */
|
|
44
|
-
routeSummary: string;
|
|
45
|
-
models: ProviderModel[];
|
|
46
|
-
modelCount: number;
|
|
47
|
-
/** 启用状态模型数(getProvider 派生;停用确认弹层「影响范围」用) */
|
|
48
|
-
enabledModelCount?: number;
|
|
49
|
-
description: string;
|
|
50
|
-
capabilityExtension: string;
|
|
51
|
-
createdAt: string;
|
|
52
|
-
updatedAt: string;
|
|
53
|
-
operator: string;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export interface ProviderListParams {
|
|
57
|
-
keyword?: string;
|
|
58
|
-
/** all | enabled | disabled | pending | none */
|
|
59
|
-
status?: string;
|
|
60
|
-
types?: string[];
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/** 快筛 Chip 计数(数据构成口径,不随搜索/筛选变化):全部/类型 Chip 为「已启用/总数」,状态 Chip 仅对应数量 */
|
|
64
|
-
export interface ProviderCounts {
|
|
65
|
-
all: { enabled: number; total: number };
|
|
66
|
-
status: Record<"enabled" | "disabled" | "pending" | "none", number>;
|
|
67
|
-
types: Record<string, { enabled: number; total: number }>;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/** 快筛 Chip 选项(ChipFilter 组件入项;文案在接口侧预计算) */
|
|
71
|
-
export interface ProviderChipOption {
|
|
72
|
-
value: string;
|
|
73
|
-
text: string;
|
|
74
|
-
dot?: string;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export interface ProviderListResult {
|
|
78
|
-
items: ProviderRecord[];
|
|
79
|
-
total: number;
|
|
80
|
-
counts: ProviderCounts;
|
|
81
|
-
/** 快筛 Chip 组:status 单选(含「全部」)/ types 多选(无「全部」,不选即全部) */
|
|
82
|
-
filters: { status: ProviderChipOption[]; types: ProviderChipOption[] };
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/** 类型快筛的展示元数据(label / 色点),聚合键与 ProviderRecord.family 一致 */
|
|
86
|
-
const TYPE_CHIP_META: { value: string; label: string; dot: string }[] = [
|
|
87
|
-
{ value: "openai", label: "OpenAI", dot: "#3b82f6" },
|
|
88
|
-
{ value: "anthropic", label: "Anthropic", dot: "#b45309" },
|
|
89
|
-
{ value: "gemini", label: "Gemini", dot: "#1d4ed8" },
|
|
90
|
-
{ value: "dashscope", label: "DashScope", dot: "#8b5cf6" },
|
|
91
|
-
];
|
|
92
|
-
|
|
93
|
-
const PROVIDERS: ProviderRecord[] = [
|
|
94
|
-
{
|
|
95
|
-
code: "openai",
|
|
96
|
-
name: "OpenAI",
|
|
97
|
-
displayName: "OpenAI",
|
|
98
|
-
icon: "zap",
|
|
99
|
-
providerType: "商业",
|
|
100
|
-
protocol: "OpenAI Compatible",
|
|
101
|
-
family: "openai",
|
|
102
|
-
status: "enabled",
|
|
103
|
-
keyStatus: "configured",
|
|
104
|
-
baseUrl: "https://api.openai.com/v1",
|
|
105
|
-
region: "us-east",
|
|
106
|
-
timeout: 60000,
|
|
107
|
-
proxy: "",
|
|
108
|
-
maskedKey: "sk-••••••••••••••••••••••••",
|
|
109
|
-
lastTest: { time: "2026-09-05 14:18", ok: true, detail: "HTTP 200, 128ms" },
|
|
110
|
-
capabilities: ["chat", "images", "audio", "responses", "embeddings"],
|
|
111
|
-
routes: { total: 12, enabled: 8 },
|
|
112
|
-
routeSummary: "12 条路由 · 8 条启用",
|
|
113
|
-
models: [
|
|
114
|
-
{ code: "gpt-4o", name: "GPT-4o", type: "LLM", providerModelId: "gpt-4o-2024-08-06", pricing: "$2.5/M", status: "ONLINE", routes: 2 },
|
|
115
|
-
{ code: "gpt-4o-mini", name: "GPT-4o Mini", type: "LLM", providerModelId: "gpt-4o-mini", pricing: "$0.15/M", status: "ONLINE", routes: 1 },
|
|
116
|
-
{ code: "text-embedding-3", name: "Text Embedding 3", type: "Embedding", providerModelId: "text-embedding-3-large", pricing: "$0.1/M", status: "ONLINE", routes: 1 },
|
|
117
|
-
],
|
|
118
|
-
modelCount: 18,
|
|
119
|
-
description: "OpenAI 官方及兼容 API 供应商",
|
|
120
|
-
capabilityExtension: '{\n "supports_responses": true,\n "supports_streaming": true,\n "supports_tool_calls": true,\n \n "supports_responses1": true,\n "supports_streaming2": true,\n "supports_tool_calls3": true\n}',
|
|
121
|
-
createdAt: "2026-06-01 10:00",
|
|
122
|
-
updatedAt: "2026-09-05 14:20",
|
|
123
|
-
operator: "张三",
|
|
124
|
-
},
|
|
125
|
-
{
|
|
126
|
-
code: "azure-openai",
|
|
127
|
-
name: "Azure OpenAI",
|
|
128
|
-
displayName: "Azure OpenAI",
|
|
129
|
-
icon: "cloud",
|
|
130
|
-
providerType: "云服务",
|
|
131
|
-
protocol: "OpenAI Compatible",
|
|
132
|
-
family: "openai",
|
|
133
|
-
status: "enabled",
|
|
134
|
-
keyStatus: "configured",
|
|
135
|
-
baseUrl: "https://contoso.openai.azure.com/openai/v1",
|
|
136
|
-
region: "eastus",
|
|
137
|
-
timeout: 60000,
|
|
138
|
-
proxy: "",
|
|
139
|
-
maskedKey: "az-••••••••••••••••",
|
|
140
|
-
lastTest: { time: "2026-09-04 09:32", ok: true, detail: "HTTP 200, 210ms" },
|
|
141
|
-
capabilities: ["chat", "embeddings"],
|
|
142
|
-
routes: { total: 3, enabled: 2 },
|
|
143
|
-
routeSummary: "3 条路由 · 2 条启用",
|
|
144
|
-
models: [
|
|
145
|
-
{ code: "azure-gpt-4o", name: "Azure GPT-4o", type: "LLM", providerModelId: "gpt-4o", pricing: "$2.5/M", status: "ONLINE", routes: 2 },
|
|
146
|
-
],
|
|
147
|
-
modelCount: 5,
|
|
148
|
-
description: "微软 Azure 托管的 OpenAI 服务",
|
|
149
|
-
capabilityExtension: '{\n "supports_streaming": true\n}',
|
|
150
|
-
createdAt: "2026-06-12 11:30",
|
|
151
|
-
updatedAt: "2026-09-04 09:32",
|
|
152
|
-
operator: "李四",
|
|
153
|
-
},
|
|
154
|
-
{
|
|
155
|
-
code: "anthropic",
|
|
156
|
-
name: "Anthropic",
|
|
157
|
-
displayName: "Anthropic",
|
|
158
|
-
icon: "brain",
|
|
159
|
-
providerType: "商业",
|
|
160
|
-
protocol: "Anthropic Messages",
|
|
161
|
-
family: "anthropic",
|
|
162
|
-
status: "enabled",
|
|
163
|
-
keyStatus: "configured",
|
|
164
|
-
baseUrl: "https://api.anthropic.com/v1",
|
|
165
|
-
region: "",
|
|
166
|
-
timeout: 60000,
|
|
167
|
-
proxy: "",
|
|
168
|
-
maskedKey: "sk-ant-••••••••••••••••",
|
|
169
|
-
lastTest: { time: "2026-09-03 16:45", ok: true, detail: "HTTP 200, 156ms" },
|
|
170
|
-
capabilities: ["chat", "messages"],
|
|
171
|
-
routes: { total: 5, enabled: 3 },
|
|
172
|
-
routeSummary: "5 条路由 · 3 条启用",
|
|
173
|
-
models: [
|
|
174
|
-
{ code: "claude-sonnet-4-5", name: "Claude Sonnet 4.5", type: "LLM", providerModelId: "claude-sonnet-4-5-20250929", pricing: "$3/M", status: "ONLINE", routes: 2 },
|
|
175
|
-
{ code: "claude-haiku-4-5", name: "Claude Haiku 4.5", type: "LLM", providerModelId: "claude-haiku-4-5-20251001", pricing: "$0.8/M", status: "ONLINE", routes: 1 },
|
|
176
|
-
],
|
|
177
|
-
modelCount: 9,
|
|
178
|
-
description: "Anthropic Claude 系列模型",
|
|
179
|
-
capabilityExtension: '{\n "supports_messages": true,\n "supports_streaming": true\n}',
|
|
180
|
-
createdAt: "2026-06-20 14:00",
|
|
181
|
-
updatedAt: "2026-09-03 16:45",
|
|
182
|
-
operator: "张三",
|
|
183
|
-
},
|
|
184
|
-
{
|
|
185
|
-
code: "dashscope",
|
|
186
|
-
name: "阿里云百炼",
|
|
187
|
-
displayName: "阿里云百炼",
|
|
188
|
-
icon: "cloud",
|
|
189
|
-
providerType: "云服务",
|
|
190
|
-
protocol: "DashScope",
|
|
191
|
-
family: "dashscope",
|
|
192
|
-
status: "enabled",
|
|
193
|
-
keyStatus: "pending",
|
|
194
|
-
baseUrl: "https://dashscope.aliyuncs.com/compatible-mode/v1",
|
|
195
|
-
region: "cn-beijing",
|
|
196
|
-
timeout: 60000,
|
|
197
|
-
proxy: "",
|
|
198
|
-
maskedKey: "",
|
|
199
|
-
lastTest: null,
|
|
200
|
-
capabilities: ["chat", "images", "audio"],
|
|
201
|
-
routes: { total: 0, enabled: 0 },
|
|
202
|
-
routeSummary: "未关联路由",
|
|
203
|
-
models: [],
|
|
204
|
-
modelCount: 0,
|
|
205
|
-
description: "阿里云大模型服务平台(模板导入,待补齐 API Key)",
|
|
206
|
-
capabilityExtension: "{}",
|
|
207
|
-
createdAt: "2026-09-10 10:12",
|
|
208
|
-
updatedAt: "2026-09-10 10:12",
|
|
209
|
-
operator: "王五",
|
|
210
|
-
},
|
|
211
|
-
{
|
|
212
|
-
code: "deepseek",
|
|
213
|
-
name: "DeepSeek",
|
|
214
|
-
displayName: "DeepSeek (2)",
|
|
215
|
-
icon: "zap",
|
|
216
|
-
providerType: "商业",
|
|
217
|
-
protocol: "OpenAI Compatible",
|
|
218
|
-
family: "openai",
|
|
219
|
-
status: "enabled",
|
|
220
|
-
keyStatus: "pending",
|
|
221
|
-
baseUrl: "https://api.deepseek.com/v1",
|
|
222
|
-
region: "",
|
|
223
|
-
timeout: 60000,
|
|
224
|
-
proxy: "",
|
|
225
|
-
maskedKey: "",
|
|
226
|
-
lastTest: null,
|
|
227
|
-
capabilities: ["chat"],
|
|
228
|
-
routes: { total: 5, enabled: 0 },
|
|
229
|
-
routeSummary: "5 条路由 · 0 条启用",
|
|
230
|
-
models: [
|
|
231
|
-
{ code: "deepseek-chat", name: "DeepSeek Chat", type: "LLM", providerModelId: "deepseek-chat", pricing: "$0.27/M", status: "ONLINE", routes: 0 },
|
|
232
|
-
{ code: "deepseek-reasoner", name: "DeepSeek Reasoner", type: "LLM", providerModelId: "deepseek-reasoner", pricing: "$0.55/M", status: "OFFLINE", routes: 0 },
|
|
233
|
-
],
|
|
234
|
-
modelCount: 3,
|
|
235
|
-
description: "DeepSeek 官方 API(第二实例)",
|
|
236
|
-
capabilityExtension: '{\n "supports_streaming": true\n}',
|
|
237
|
-
createdAt: "2026-08-28 15:40",
|
|
238
|
-
updatedAt: "2026-09-08 11:05",
|
|
239
|
-
operator: "李四",
|
|
240
|
-
},
|
|
241
|
-
{
|
|
242
|
-
code: "volcengine",
|
|
243
|
-
name: "火山方舟",
|
|
244
|
-
displayName: "火山方舟",
|
|
245
|
-
icon: "zap",
|
|
246
|
-
providerType: "云服务",
|
|
247
|
-
protocol: "OpenAI Compatible",
|
|
248
|
-
family: "openai",
|
|
249
|
-
status: "disabled",
|
|
250
|
-
keyStatus: "pending",
|
|
251
|
-
baseUrl: "https://ark.cn-beijing.volces.com/api/v3",
|
|
252
|
-
region: "cn-beijing",
|
|
253
|
-
timeout: 60000,
|
|
254
|
-
proxy: "",
|
|
255
|
-
maskedKey: "",
|
|
256
|
-
lastTest: null,
|
|
257
|
-
capabilities: ["chat", "images"],
|
|
258
|
-
routes: { total: 0, enabled: 0 },
|
|
259
|
-
routeSummary: "未关联路由",
|
|
260
|
-
models: [],
|
|
261
|
-
modelCount: 0,
|
|
262
|
-
description: "字节跳动火山引擎方舟平台(模板导入,待补齐 API Key)",
|
|
263
|
-
capabilityExtension: "{}",
|
|
264
|
-
createdAt: "2026-09-09 09:20",
|
|
265
|
-
updatedAt: "2026-09-09 09:20",
|
|
266
|
-
operator: "王五",
|
|
267
|
-
},
|
|
268
|
-
{
|
|
269
|
-
code: "gemini",
|
|
270
|
-
name: "Google Gemini",
|
|
271
|
-
displayName: "Google Gemini",
|
|
272
|
-
icon: "star",
|
|
273
|
-
providerType: "商业",
|
|
274
|
-
protocol: "Gemini",
|
|
275
|
-
family: "gemini",
|
|
276
|
-
status: "disabled",
|
|
277
|
-
keyStatus: "none",
|
|
278
|
-
baseUrl: "https://generativelanguage.googleapis.com/v1beta",
|
|
279
|
-
region: "",
|
|
280
|
-
timeout: 60000,
|
|
281
|
-
proxy: "",
|
|
282
|
-
maskedKey: "",
|
|
283
|
-
lastTest: { time: "2026-08-30 20:10", ok: false, detail: "HTTP 401, 98ms" },
|
|
284
|
-
capabilities: ["chat", "generate"],
|
|
285
|
-
routes: { total: 2, enabled: 0 },
|
|
286
|
-
routeSummary: "2 条路由 · 0 条启用",
|
|
287
|
-
models: [],
|
|
288
|
-
modelCount: 0,
|
|
289
|
-
description: "Google Gemini 系列模型(未配置 API Key)",
|
|
290
|
-
capabilityExtension: "{}",
|
|
291
|
-
createdAt: "2026-08-30 20:00",
|
|
292
|
-
updatedAt: "2026-08-30 20:10",
|
|
293
|
-
operator: "张三",
|
|
294
|
-
},
|
|
295
|
-
];
|
|
296
|
-
|
|
297
|
-
export interface PullModelRow {
|
|
298
|
-
id: string;
|
|
299
|
-
name: string;
|
|
300
|
-
local: string;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
/** 上游 List Models 演示返回(本地状态 = 新增 / 已存在(跳过)) */
|
|
304
|
-
const UPSTREAM_MODELS: Record<string, PullModelRow[]> = {
|
|
305
|
-
openai: [
|
|
306
|
-
{ id: "gpt-4o-2024-08-06", name: "GPT-4o", local: "已存在(跳过)" },
|
|
307
|
-
{ id: "o1-preview", name: "o1 Preview", local: "新增" },
|
|
308
|
-
{ id: "dall-e-3", name: "DALL·E 3", local: "新增" },
|
|
309
|
-
{ id: "gpt-5", name: "GPT-5", local: "新增" },
|
|
310
|
-
],
|
|
311
|
-
anthropic: [
|
|
312
|
-
{ id: "claude-sonnet-4-5-20250929", name: "Claude Sonnet 4.5", local: "已存在(跳过)" },
|
|
313
|
-
{ id: "claude-opus-4-1", name: "Claude Opus 4.1", local: "新增" },
|
|
314
|
-
],
|
|
315
|
-
};
|
|
316
|
-
|
|
317
|
-
function matchesKeyword(p: ProviderRecord, keyword: string): boolean {
|
|
318
|
-
const k = keyword.trim().toLowerCase();
|
|
319
|
-
if (!k) return true;
|
|
320
|
-
return [p.name, p.code, p.baseUrl, ...p.capabilities]
|
|
321
|
-
.join(" ")
|
|
322
|
-
.toLowerCase()
|
|
323
|
-
.includes(k);
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
function matchesStatus(p: ProviderRecord, status?: string): boolean {
|
|
327
|
-
switch (status) {
|
|
328
|
-
case "enabled":
|
|
329
|
-
case "disabled":
|
|
330
|
-
return p.status === status;
|
|
331
|
-
case "pending":
|
|
332
|
-
return p.keyStatus === "pending";
|
|
333
|
-
case "none":
|
|
334
|
-
return p.keyStatus === "none";
|
|
335
|
-
default:
|
|
336
|
-
return true;
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
/** 快筛计数:基于全量数据(构成口径,与当前筛选无关) */
|
|
341
|
-
function computeCounts(): ProviderCounts {
|
|
342
|
-
const enabled = PROVIDERS.filter((p) => p.status === "enabled").length;
|
|
343
|
-
return {
|
|
344
|
-
all: { enabled, total: PROVIDERS.length },
|
|
345
|
-
status: {
|
|
346
|
-
enabled,
|
|
347
|
-
disabled: PROVIDERS.filter((p) => p.status === "disabled").length,
|
|
348
|
-
pending: PROVIDERS.filter((p) => p.keyStatus === "pending").length,
|
|
349
|
-
none: PROVIDERS.filter((p) => p.keyStatus === "none").length,
|
|
350
|
-
},
|
|
351
|
-
types: TYPE_CHIP_META.map((m) => m.value).reduce<
|
|
352
|
-
Record<string, { enabled: number; total: number }>
|
|
353
|
-
>((acc, family) => {
|
|
354
|
-
const inFamily = PROVIDERS.filter((p) => p.family === family);
|
|
355
|
-
acc[family] = {
|
|
356
|
-
enabled: inFamily.filter((p) => p.status === "enabled").length,
|
|
357
|
-
total: inFamily.length,
|
|
358
|
-
};
|
|
359
|
-
return acc;
|
|
360
|
-
}, {}),
|
|
361
|
-
};
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
/** 快筛 Chip 选项:由计数派生,文案在此预计算(表达式不支持字符串拼接以外的复合逻辑) */
|
|
365
|
-
function computeFilters(
|
|
366
|
-
counts: ProviderCounts,
|
|
367
|
-
): ProviderListResult["filters"] {
|
|
368
|
-
return {
|
|
369
|
-
status: [
|
|
370
|
-
{ value: "all", text: `全部 ${counts.all.enabled}/${counts.all.total}` },
|
|
371
|
-
{ value: "enabled", text: `已启用 ${counts.status.enabled}`, dot: "#22c55e" },
|
|
372
|
-
{ value: "disabled", text: `已停用 ${counts.status.disabled}`, dot: "#9ca3af" },
|
|
373
|
-
{ value: "pending", text: `待填密钥 ${counts.status.pending}`, dot: "#f59e0b" },
|
|
374
|
-
{ value: "none", text: `无密钥 ${counts.status.none}`, dot: "#ef4444" },
|
|
375
|
-
],
|
|
376
|
-
types: TYPE_CHIP_META.map((m) => ({
|
|
377
|
-
value: m.value,
|
|
378
|
-
text: `${m.label} ${counts.types[m.value].enabled}/${counts.types[m.value].total}`,
|
|
379
|
-
dot: m.dot,
|
|
380
|
-
})),
|
|
381
|
-
};
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
/** 启用状态模型数派生(列表 / 详情 / 停用确认弹层「影响范围」共用) */
|
|
385
|
-
function withEnabledModelCount(record: ProviderRecord): ProviderRecord {
|
|
386
|
-
return {
|
|
387
|
-
...record,
|
|
388
|
-
enabledModelCount: record.models.filter((m) => m.status === "ONLINE").length,
|
|
389
|
-
};
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
/** provider.list:搜索 + 状态/类型快筛取交集,即时过滤(防抖由调用侧控制) */
|
|
393
|
-
export function queryProviders(params: ProviderListParams = {}): ProviderListResult {
|
|
394
|
-
const keyword = params.keyword ?? "";
|
|
395
|
-
const status = params.status ?? "all";
|
|
396
|
-
const types = params.types ?? [];
|
|
397
|
-
const items = PROVIDERS.filter(
|
|
398
|
-
(p) =>
|
|
399
|
-
matchesKeyword(p, keyword) &&
|
|
400
|
-
matchesStatus(p, status) &&
|
|
401
|
-
(types.length === 0 || types.includes(p.family)),
|
|
402
|
-
).map(withEnabledModelCount);
|
|
403
|
-
const counts = computeCounts();
|
|
404
|
-
return { items, total: PROVIDERS.length, counts, filters: computeFilters(counts) };
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
/** provider.detail:按 Provider Code 取详情;未命中返回 undefined(页面做空态) */
|
|
408
|
-
export function getProvider(code: string): ProviderRecord | undefined {
|
|
409
|
-
const record = PROVIDERS.find((p) => p.code === code);
|
|
410
|
-
return record ? withEnabledModelCount(record) : undefined;
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
/** 全量 Provider Code(静态导出 generateStaticParams 用) */
|
|
414
|
-
export const PROVIDER_CODES: string[] = PROVIDERS.map((p) => p.code);
|
|
415
|
-
|
|
416
|
-
/** provider.pullModels:模拟上游 List Models(对齐 PRD「拉取」弹层) */
|
|
417
|
-
export function pullProviderModels(code: string): PullModelRow[] {
|
|
418
|
-
return (
|
|
419
|
-
UPSTREAM_MODELS[code] ?? [
|
|
420
|
-
{ id: `${code}-chat`, name: `${code} Chat`, local: "新增" },
|
|
421
|
-
{ id: `${code}-pro`, name: `${code} Pro`, local: "新增" },
|
|
422
|
-
]
|
|
423
|
-
);
|
|
424
|
-
}
|