@teamix-evo/skills 0.4.0 → 0.6.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.
Files changed (97) hide show
  1. package/README.md +7 -3
  2. package/manifest.json +3 -2
  3. package/package.json +2 -2
  4. package/src/teamix-evo-code-opentrek/SKILL.md +12 -10
  5. package/src/teamix-evo-code-opentrek/api-layering.md +8 -5
  6. package/src/teamix-evo-code-opentrek/checklist.md +2 -0
  7. package/src/teamix-evo-code-opentrek/error-and-loading.md +38 -25
  8. package/src/teamix-evo-code-opentrek/file-structure.md +63 -54
  9. package/src/teamix-evo-code-opentrek/forms-and-validation.md +14 -12
  10. package/src/teamix-evo-code-opentrek/reuse-first.md +2 -0
  11. package/src/teamix-evo-code-opentrek/routing-and-codesplit.md +23 -21
  12. package/src/teamix-evo-code-opentrek/testing.md +32 -28
  13. package/src/teamix-evo-code-uni-manager/SKILL.md +12 -10
  14. package/src/teamix-evo-code-uni-manager/api-layering.md +2 -0
  15. package/src/teamix-evo-code-uni-manager/checklist.md +2 -0
  16. package/src/teamix-evo-code-uni-manager/error-and-loading.md +3 -1
  17. package/src/teamix-evo-code-uni-manager/file-structure.md +2 -0
  18. package/src/teamix-evo-code-uni-manager/forms-and-validation.md +2 -0
  19. package/src/teamix-evo-code-uni-manager/reuse-first.md +3 -1
  20. package/src/teamix-evo-code-uni-manager/routing-and-codesplit.md +3 -1
  21. package/src/teamix-evo-code-uni-manager/testing.md +2 -0
  22. package/src/teamix-evo-design-opentrek/SKILL.md +213 -52
  23. package/src/teamix-evo-design-opentrek/boundaries.md +25 -5
  24. package/src/teamix-evo-design-opentrek/brand.md +7 -7
  25. package/src/teamix-evo-design-opentrek/checklist.md +15 -13
  26. package/src/teamix-evo-design-opentrek/components.md +89 -39
  27. package/src/teamix-evo-design-opentrek/examples/detail-ai-gateway-1.html +1069 -0
  28. package/src/teamix-evo-design-opentrek/examples/detail-ai-gateway-instance.html +941 -0
  29. package/src/teamix-evo-design-opentrek/examples/detail-page-api-doc.html +906 -0
  30. package/src/teamix-evo-design-opentrek/examples/detail-page-config.html +993 -0
  31. package/src/teamix-evo-design-opentrek/examples/detail-page-monitor.html +1339 -0
  32. package/src/teamix-evo-design-opentrek/examples/detail-page.html +933 -0
  33. package/src/teamix-evo-design-opentrek/examples/settings-page.html +1119 -0
  34. package/src/teamix-evo-design-opentrek/examples/standard-card-list.html +1094 -0
  35. package/src/teamix-evo-design-opentrek/examples/standard-table-list.html +1361 -0
  36. package/src/teamix-evo-design-opentrek/examples/wizard-form-page.html +877 -0
  37. package/src/teamix-evo-design-opentrek/flows.md +85 -12
  38. package/src/teamix-evo-design-opentrek/foundations.md +12 -9
  39. package/src/teamix-evo-design-opentrek/generation-flow.md +84 -14
  40. package/src/teamix-evo-design-opentrek/pages/detail-page/SKILL.md +260 -0
  41. package/src/teamix-evo-design-opentrek/pages/detail-page/patterns/api-doc-detail.md +163 -0
  42. package/src/teamix-evo-design-opentrek/pages/detail-page/patterns/comparison-detail.md +100 -0
  43. package/src/teamix-evo-design-opentrek/pages/detail-page/patterns/monitor-detail.md +190 -0
  44. package/src/teamix-evo-design-opentrek/pages/detail-page/patterns/resource-detail.md +148 -0
  45. package/src/teamix-evo-design-opentrek/pages/form-page/SKILL.md +362 -0
  46. package/src/teamix-evo-design-opentrek/pages/list-page/SKILL.md +286 -0
  47. package/src/teamix-evo-design-opentrek/pages/list-page/_shared/action-column-spec.md +60 -0
  48. package/src/teamix-evo-design-opentrek/pages/list-page/_shared/column-meta-rules.md +117 -0
  49. package/src/teamix-evo-design-opentrek/pages/list-page/_shared/search-combo-spec.md +194 -0
  50. package/src/teamix-evo-design-opentrek/pages/list-page/_shared/state-action-pattern.md +51 -0
  51. package/src/teamix-evo-design-opentrek/pages/list-page/patterns/advanced-filter-list.md +94 -0
  52. package/src/teamix-evo-design-opentrek/pages/list-page/patterns/card-list.md +558 -0
  53. package/src/teamix-evo-design-opentrek/pages/list-page/patterns/drawer-list.md +76 -0
  54. package/src/teamix-evo-design-opentrek/pages/list-page/patterns/expandable-list.md +70 -0
  55. package/src/teamix-evo-design-opentrek/pages/list-page/patterns/l2-sidebar-list.md +73 -0
  56. package/src/teamix-evo-design-opentrek/pages/list-page/patterns/standard-list.md +198 -0
  57. package/src/teamix-evo-design-opentrek/patterns/color-mapping.md +96 -0
  58. package/src/teamix-evo-design-opentrek/patterns/dashboard.md +2 -0
  59. package/src/teamix-evo-design-opentrek/patterns/detail-page.md +218 -152
  60. package/src/teamix-evo-design-opentrek/patterns/form-page.md +437 -228
  61. package/src/teamix-evo-design-opentrek/patterns/list-page.md +221 -260
  62. package/src/teamix-evo-design-opentrek/patterns/page-types.md +40 -125
  63. package/src/teamix-evo-design-opentrek/philosophy.md +7 -5
  64. package/src/teamix-evo-design-opentrek/rules/_assets/OP_AGENT RUNTIME.svg +1 -0
  65. package/src/teamix-evo-design-opentrek/rules/_assets/OP_AI GATEWAY.svg +1 -0
  66. package/src/teamix-evo-design-opentrek/rules/_assets/OP_AI STUDIO.svg +1 -0
  67. package/src/teamix-evo-design-opentrek/rules/_assets/OP_DEV-2.svg +1 -0
  68. package/src/teamix-evo-design-opentrek/rules/_assets/OP_LOGO.svg +1 -0
  69. package/src/teamix-evo-design-opentrek/rules/_assets/OP_OPS.svg +1 -0
  70. package/src/teamix-evo-design-opentrek/rules/boundaries.rules.json +3 -3
  71. package/src/teamix-evo-design-opentrek/rules/business-mapping.json +124 -0
  72. package/src/teamix-evo-design-opentrek/rules/common-components.json +924 -0
  73. package/src/teamix-evo-design-opentrek/rules/component-specs.json +1083 -0
  74. package/src/teamix-evo-design-opentrek/rules/design-tokens.css +433 -0
  75. package/src/teamix-evo-design-opentrek/rules/design-tokens.json +2798 -0
  76. package/src/teamix-evo-design-opentrek/rules/layout-rules.json +218 -0
  77. package/src/teamix-evo-design-opentrek/rules/page-flow.json +351 -0
  78. package/src/teamix-evo-design-opentrek/rules/page-frame.json +241 -0
  79. package/src/teamix-evo-design-opentrek/rules/page-header-spec.md +123 -0
  80. package/src/teamix-evo-design-opentrek/rules/page-types.json +206 -0
  81. package/src/teamix-evo-design-opentrek/rules/sidebar-spec.md +217 -0
  82. package/src/teamix-evo-design-opentrek/rules/styling.json +188 -0
  83. package/src/teamix-evo-design-opentrek/rules/token-mapping.md +284 -0
  84. package/src/teamix-evo-design-uni-manager/SKILL.md +18 -27
  85. package/src/teamix-evo-design-uni-manager/boundaries.md +7 -4
  86. package/src/teamix-evo-design-uni-manager/brand.md +1 -1
  87. package/src/teamix-evo-design-uni-manager/components.md +33 -28
  88. package/src/teamix-evo-design-uni-manager/foundations.md +24 -21
  89. package/src/teamix-evo-design-uni-manager/generation-flow.md +46 -8
  90. package/src/teamix-evo-design-uni-manager/patterns/dashboard.md +3 -1
  91. package/src/teamix-evo-design-uni-manager/patterns/detail-page.md +42 -13
  92. package/src/teamix-evo-design-uni-manager/patterns/form-page.md +67 -30
  93. package/src/teamix-evo-design-uni-manager/patterns/list-page.md +73 -40
  94. package/src/teamix-evo-design-uni-manager/patterns/page-types.md +14 -12
  95. package/src/teamix-evo-design-uni-manager/philosophy.md +4 -2
  96. package/src/teamix-evo-design-uni-manager/rules/boundaries.rules.json +3 -3
  97. package/src/teamix-evo-manage/SKILL.md +74 -66
@@ -0,0 +1,906 @@
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>API 文档详情页 · 标准参考范例 — v7.8.4</title>
7
+ <!--
8
+ ★ API 文档详情页标准参考范例(API Doc Detail Page Reference)
9
+ ─────────────────────────────────────────────────────────────
10
+ 页面类型:DetailPage
11
+ 子类型:ApiDocDetailPage
12
+ 版本:v7.7
13
+ 场景:模型 API 接口文档详情
14
+ ─────────────────────────────────────────────────────────────
15
+ 布局:TWO_COL(Sidebar + ContentCard 单例容器)
16
+ Sidebar:完整 L2 框架(折叠/展开 240px↔68px)
17
+ 内容区模式:模式B + 模式C 组合(Card + Tabs)
18
+ ─────────────────────────────────────────────────────────────
19
+ 组件清单:
20
+ • PageHeader — 面包屑模式 + 操作按钮组
21
+ • ApiEndpoint — HTTP 方法 + 路径 + 状态
22
+ • DescriptionList — 键值对列表,3列布局
23
+ • Tabs — 请求参数/响应参数/请求示例/响应示例
24
+ • ParameterTable — 可展开嵌套参数表
25
+ • CodeBlock — 多语言代码示例
26
+ • Badge — 状态/类型展示
27
+ ─────────────────────────────────────────────────────────────
28
+ 规范来源:pages/detail-page/SKILL.md v7.8.4
29
+ Tokens 版本:v7.8.4(v7.6 ContentCard 表面规则 + v7.8.4 字体族变量 + ApiEndpoint/ParameterTable/CodeBlock 组件)
30
+ 表面边界:PageHeader / Tabs / Separator 的 border 为「功能性分割线」,不受 v7.6 surface 约束
31
+ -->
32
+ <style>
33
+ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
34
+
35
+ :root {
36
+ --primary: 218.6 100% 46.7%;
37
+ --primary-foreground: 0 0% 100%;
38
+ --primary-hover: 218.6 100% 42%;
39
+ --primary-click: 218.6 100% 37.5%;
40
+ --gray-primary: 220 9% 7%;
41
+ --gray-primary-foreground: 210 33% 99%;
42
+ --gray-secondary-foreground: 216 4% 26%;
43
+ --muted-foreground: 216 2% 45%;
44
+ --gray-disabled: 210 3% 63%;
45
+ --gray-line: 210 9% 91%;
46
+ --gray-sidebar-accent: 210 12% 93%;
47
+ --gray-muted: 220 18% 97%;
48
+ --gray-white: 0 0% 100%;
49
+ --gray-title: 220 9% 7%;
50
+ --gray-secondary: 216 4% 26%;
51
+ --gray-tertiary: 216 2% 45%;
52
+ --gray-border: 210 9% 91%;
53
+ --gray-fill: 220 18% 97%;
54
+ --success: 142 76% 36%;
55
+ --success-bg: 152 82% 96%;
56
+ --warning: 40 88% 48%;
57
+ --warning-bg: 43 100% 94%;
58
+ --destructive: 0 72% 51%;
59
+ --destructive-bg: 0 86% 97%;
60
+ --info: 221 83% 53%;
61
+ --info-bg: 214 100% 97%;
62
+ --background: 220 18% 97%;
63
+ --card: 0 0% 100%;
64
+ --card-foreground: 220 9% 7%;
65
+ --border: 210 9% 91%;
66
+ --ring: 218.6 100% 46.7%;
67
+ --sidebar: 220 18% 97%;
68
+ --sidebar-foreground: 220 9% 7%;
69
+ --sidebar-active: 210 12% 93%;
70
+ --sidebar-active-foreground: 220 9% 7%;
71
+ --sidebar-hover: 220 18% 97%;
72
+ --sidebar-item: 220 9% 7%;
73
+ --sidebar-item-muted: 216 4% 26%;
74
+ --sidebar-border: 210 9% 91%;
75
+ --sidebar-group: 216 2% 45%;
76
+ --radius-sm: 4px;
77
+ --radius-md: 8px;
78
+ --radius-lg: 12px;
79
+ --gap-xs: 4px;
80
+ --btn-padding-x: 16px;
81
+ --btn-padding-x-sm: 12px;
82
+ --button-gap: 8px;
83
+ --tabs-gap: 24px;
84
+ --card-gap: 16px;
85
+ --page-container-padding: 16px;
86
+ --page-container-padding-left: 0px;
87
+ --card-padding-x: 20px;
88
+ --shadow-sm: 0 1px 2px rgba(0,0,0,0.05);
89
+ --font-size-base: 12px;
90
+ --font-size-lg: 14px;
91
+ --font-size-xl: 16px;
92
+ --font-size-2xl: 18px;
93
+ --font-size-page-header: 18px;
94
+ --font-sans: 'PingFang SC', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;
95
+ --font-mono: 'SF Mono', Monaco, 'Courier New', monospace;
96
+ --font-weight-normal: 400;
97
+ --font-weight-medium: 500;
98
+ --font-weight-black: 900;
99
+ --input-height: 32px;
100
+ --input-radius: 8px;
101
+ --layout-sidebar-width: 240px;
102
+ --duration-fast: 150ms;
103
+ --duration-normal: 200ms;
104
+ --easing-ease: ease;
105
+ }
106
+
107
+ body {
108
+ font-family: var(--font-sans);
109
+ font-size: var(--font-size-base);
110
+ color: hsl(var(--gray-primary));
111
+ background: hsl(var(--background));
112
+ min-height: 100vh;
113
+ }
114
+
115
+ /* ===== Sidebar ===== */
116
+ .sidebar {
117
+ position: fixed; top: 0; left: 0; bottom: 0;
118
+ width: var(--layout-sidebar-width);
119
+ background: hsl(var(--sidebar));
120
+ z-index: 100;
121
+ display: flex; flex-direction: column;
122
+ overflow: hidden;
123
+ transition: width 0.2s ease;
124
+ }
125
+ .sidebar-header {
126
+ height: 56px; padding: 0 16px;
127
+ display: flex; align-items: center; gap: var(--gap-xs);
128
+ flex-shrink: 0;
129
+ }
130
+ .sidebar-logo {
131
+ height: 28px; flex-shrink: 0;
132
+ display: flex; align-items: center;
133
+ overflow: hidden;
134
+ }
135
+ .sidebar-logo img {
136
+ height: 28px; width: auto; display: block;
137
+ }
138
+ .sidebar-logo .collapsed-logo {
139
+ display: none; width: 30px; height: 30px;
140
+ }
141
+ .sidebar-logo .expand-logo {
142
+ display: none; width: 18px; height: 18px;
143
+ color: hsl(var(--muted-foreground));
144
+ }
145
+ .sidebar-collapse-btn {
146
+ margin-left: auto; width: 18px; height: 18px;
147
+ background: none; border: none; padding: 0; cursor: pointer;
148
+ display: flex; align-items: center; justify-content: center;
149
+ color: hsl(var(--muted-foreground)); flex-shrink: 0;
150
+ }
151
+ .sidebar-collapse-btn svg { width: 18px; height: 18px; }
152
+
153
+ /* ===== Sidebar Collapsed State ===== */
154
+ .sidebar.collapsed { width: 68px; overflow: visible; }
155
+ .sidebar.collapsed .sidebar-header { padding: 0 12px; justify-content: center; }
156
+ .sidebar.collapsed .sidebar-logo { cursor: pointer; }
157
+ .sidebar.collapsed .sidebar-logo img { display: none; }
158
+ .sidebar.collapsed .sidebar-logo .collapsed-logo { display: block; }
159
+ .sidebar.collapsed .sidebar-logo:hover .collapsed-logo { display: none; }
160
+ .sidebar.collapsed .sidebar-logo:hover .expand-logo { display: block; }
161
+ .sidebar.collapsed .sidebar-collapse-btn { display: none; }
162
+ .sidebar.collapsed .sidebar-content { padding: 12px 0; overflow-y: auto; overflow-x: hidden; }
163
+ .sidebar.collapsed .sidebar-menu { padding: 0; }
164
+ .sidebar.collapsed .sidebar-menu > li { display: flex; justify-content: center; }
165
+ .sidebar.collapsed .sidebar-menu > li > a.sidebar-menu-item {
166
+ justify-content: center; padding: 0; width: 40px; height: 40px;
167
+ border-radius: var(--radius-md); position: relative; flex-shrink: 0;
168
+ gap: 0;
169
+ }
170
+ .sidebar.collapsed .sidebar-menu > li > a.sidebar-menu-item .item-icon { margin: 0; }
171
+ .sidebar.collapsed .sidebar-menu > li > a > span:not(.item-icon),
172
+ .sidebar.collapsed .sidebar-menu > li > a > .expand-icon,
173
+ .sidebar.collapsed .sidebar-menu-item:not(.item-icon):after { display: none; }
174
+ /* 隐藏文字节点(直接文本) */
175
+ .sidebar.collapsed .sidebar-menu > li > a { font-size: 0; }
176
+ .sidebar.collapsed .sidebar-menu > li > a > .item-icon { font-size: var(--font-size-lg); }
177
+ .sidebar.collapsed .sidebar-sub-menu { display: none !important; }
178
+ .sidebar.collapsed .sidebar-divider { margin: 0 14px; }
179
+ .sidebar.collapsed .sidebar-footer { padding: 12px 10px 16px; justify-content: center; }
180
+ .sidebar.collapsed .sidebar-username,
181
+ .sidebar.collapsed .sidebar-more { display: none; }
182
+
183
+ /* ===== Sidebar Collapsed Flyout (hover 浮层展示二级菜单) ===== */
184
+ .sidebar.collapsed .sidebar-menu > li { position: relative; }
185
+ .sidebar.collapsed .sidebar-menu > li:hover > .sidebar-flyout {
186
+ display: block;
187
+ }
188
+ .sidebar-flyout {
189
+ display: none;
190
+ position: absolute; left: 100%; top: 0;
191
+ min-width: 160px; padding: 4px;
192
+ background: hsl(var(--card));
193
+ border: 1px solid hsl(var(--gray-line));
194
+ border-radius: var(--radius-md);
195
+ box-shadow: 0 4px 12px rgba(0,0,0,0.08);
196
+ z-index: 200;
197
+ }
198
+ .sidebar-flyout .sidebar-menu-item {
199
+ height: 36px; padding: 0 12px;
200
+ font-size: var(--font-size-base) !important;
201
+ font-weight: var(--font-weight-normal);
202
+ color: hsl(var(--gray-primary));
203
+ border-radius: var(--radius-sm);
204
+ white-space: nowrap;
205
+ }
206
+ .sidebar-flyout .sidebar-menu-item:hover {
207
+ background: hsl(var(--gray-muted));
208
+ }
209
+
210
+ /* Main content 响应 sidebar 收起 */
211
+ .main-content {
212
+ margin-left: var(--layout-sidebar-width);
213
+ min-height: 100vh;
214
+ transition: margin-left 0.2s ease;
215
+ }
216
+ .sidebar.collapsed ~ .main-content { margin-left: 68px; }
217
+ .sidebar-product {
218
+ font-size: var(--font-size-xl); font-weight: var(--font-weight-black);
219
+ color: hsl(var(--sidebar-foreground)); letter-spacing: -0.025em;
220
+ white-space: nowrap; line-height: 1;
221
+ }
222
+ .sidebar-content {
223
+ flex: 1; overflow-y: auto; padding: 12px 0;
224
+ }
225
+ /* twoLevel 变体:去掉 sidebar-group-label,主菜单之间间距由 li padding 提供;保留 sidebar-group-label 样式以兼容其他页面。 */
226
+ .sidebar-group-label {
227
+ padding: 0 16px; height: 26px; line-height: 26px;
228
+ font-size: var(--font-size-base); font-weight: var(--font-weight-normal);
229
+ color: hsl(var(--sidebar-group));
230
+ }
231
+ .sidebar-group-label:not(:first-child) { margin-top: 16px; }
232
+ .sidebar-menu { list-style: none; padding: 0 8px; display: flex; flex-direction: column; gap: 2px; }
233
+ .sidebar-menu-item {
234
+ display: flex; align-items: center; gap: var(--button-gap);
235
+ padding: 0 12px; height: 40px;
236
+ border-radius: var(--radius-md);
237
+ font-size: var(--font-size-lg); font-weight: var(--font-weight-medium);
238
+ color: hsl(var(--sidebar-item-muted));
239
+ text-decoration: none; cursor: pointer;
240
+ transition: background var(--duration-fast), color var(--duration-fast);
241
+ white-space: nowrap;
242
+ }
243
+ .sidebar-menu-item:hover {
244
+ background: hsl(var(--sidebar-hover));
245
+ color: hsl(var(--sidebar-item));
246
+ }
247
+ .sidebar-menu-item.active {
248
+ background: hsl(var(--sidebar-active));
249
+ color: hsl(var(--sidebar-active-foreground));
250
+ }
251
+ .sidebar-menu-item .item-icon {
252
+ width: 16px; height: 16px; flex-shrink: 0;
253
+ display: flex; align-items: center; justify-content: center;
254
+ }
255
+ .sidebar-menu-item .expand-icon {
256
+ margin-left: auto; width: 16px; height: 16px;
257
+ transition: transform var(--duration-fast);
258
+ }
259
+ .sidebar-menu-item.expanded .expand-icon { transform: rotate(90deg); }
260
+ .sidebar-sub-menu {
261
+ list-style: none; padding: 0 0 0 24px;
262
+ display: none;
263
+ }
264
+ /* twoLevel 变体:子菜单与主菜单在同一列上下对齐。sub-menu 不再加左 padding,由子菜单项自身 padding-left = 12+16+8 = 36px 代替主菜单的 "padding+icon+gap",使文字起点 x 坐标与主菜单一致。 */
265
+ .sidebar-menu > li > .sidebar-sub-menu { padding-left: 0; }
266
+ .sidebar-sub-menu.show { display: block; }
267
+ .sidebar-sub-menu .sidebar-menu-item {
268
+ height: 36px; font-size: var(--font-size-base); font-weight: var(--font-weight-normal);
269
+ /* twoLevel 变体对齐规则:36px = 主菜单 padding-left(12) + item-icon(16) + gap(8),使文字与主菜单文字上下对齐。 */
270
+ padding-left: 36px;
271
+ }
272
+ .sidebar-divider {
273
+ height: 1px; background: hsl(var(--sidebar-border));
274
+ margin: 0 12px; flex-shrink: 0;
275
+ }
276
+ .sidebar-footer {
277
+ flex-shrink: 0; display: flex; align-items: center;
278
+ gap: var(--button-gap); padding: 12px 12px 16px 24px;
279
+ }
280
+ .sidebar-avatar {
281
+ width: 28px; height: 28px; border-radius: 50%;
282
+ background: hsl(var(--sidebar-active));
283
+ display: flex; align-items: center; justify-content: center;
284
+ font-size: var(--font-size-base); font-weight: 600;
285
+ color: hsl(var(--gray-primary)); flex-shrink: 0;
286
+ }
287
+ .sidebar-username {
288
+ flex: 1; font-size: var(--font-size-lg); font-weight: var(--font-weight-medium);
289
+ color: hsl(var(--sidebar-item)); overflow: hidden;
290
+ text-overflow: ellipsis; white-space: nowrap;
291
+ }
292
+ .sidebar-more {
293
+ width: 28px; height: 28px; border-radius: var(--radius-sm);
294
+ border: none; background: transparent; cursor: pointer;
295
+ display: flex; align-items: center; justify-content: center;
296
+ color: hsl(var(--muted-foreground));
297
+ }
298
+ .sidebar-more:hover { background: hsl(var(--sidebar-hover)); color: hsl(var(--gray-primary)); }
299
+
300
+ /* ===== Main Content ===== */
301
+ .page-container { padding: var(--page-container-padding) var(--page-container-padding) var(--page-container-padding) var(--page-container-padding-left); }
302
+ .card {
303
+ background: hsl(var(--card));
304
+ border-radius: var(--radius-lg);
305
+ box-shadow: var(--shadow-sm, 0 1px 2px rgba(0,0,0,0.05));
306
+ overflow: hidden;
307
+ display: flex; flex-direction: column;
308
+ min-height: calc(100vh - 40px);
309
+ padding: 0 var(--card-padding-x);
310
+ }
311
+
312
+ /* ===== PageHeader — Breadcrumb Mode ===== */
313
+ /* L2 面包屑模式:无 border、无 background、无 box-shadow;高度 64px,padding 由外层 Card 提供 */
314
+ .page-header {
315
+ height: 64px; padding: 0;
316
+ display: flex; align-items: center; justify-content: space-between;
317
+ flex-shrink: 0;
318
+ }
319
+ .page-header-left { display: flex; align-items: center; }
320
+ .breadcrumb { display: flex; align-items: center; gap: 4px; font-size: var(--font-size-page-header); font-weight: var(--font-weight-medium); color: hsl(var(--gray-secondary-foreground)); }
321
+ .breadcrumb a { color: hsl(var(--gray-secondary-foreground)); text-decoration: none; }
322
+ .breadcrumb a:hover { color: hsl(var(--gray-primary)); }
323
+ .breadcrumb .separator { color: hsl(var(--muted-foreground)); display: flex; align-items: center; }
324
+ .breadcrumb .separator svg { width: 20px; height: 20px; }
325
+ .breadcrumb .current { color: hsl(var(--gray-primary)); }
326
+ .page-header-right { display: flex; align-items: center; gap: var(--button-gap); }
327
+
328
+ /* ===== Buttons ===== */
329
+ .btn {
330
+ display: inline-flex; align-items: center; justify-content: center; gap: var(--gap-xs);
331
+ height: var(--input-height); padding: 0 var(--btn-padding-x);
332
+ border-radius: var(--radius-md); font-size: var(--font-size-base);
333
+ font-weight: var(--font-weight-medium); border: none; cursor: pointer;
334
+ transition: background var(--duration-fast), opacity var(--duration-fast);
335
+ white-space: nowrap;
336
+ }
337
+ .btn-primary { background: hsl(var(--primary)); color: hsl(var(--primary-foreground)); }
338
+ .btn-primary:hover { background: hsl(var(--primary-hover)); }
339
+ .btn-outline { background: hsl(var(--card)); color: hsl(var(--gray-primary)); border: 1px solid hsl(var(--gray-line)); }
340
+ .btn-outline:hover { background: hsl(var(--gray-muted)); }
341
+ .btn-ghost { background: transparent; color: hsl(var(--gray-primary)); }
342
+ .btn-ghost:hover { background: hsl(var(--gray-muted)); }
343
+ .btn-icon { width: var(--input-height); padding: 0; }
344
+
345
+ /* ===== ApiEndpoint ===== */
346
+ .api-endpoint {
347
+ height: 48px; background: hsl(var(--gray-muted));
348
+ border-radius: var(--radius-md); padding: 0 16px;
349
+ display: flex; align-items: center; gap: 12px;
350
+ margin: 16px 0;
351
+ }
352
+ .method-badge {
353
+ display: inline-flex; align-items: center; justify-content: center;
354
+ padding: 2px 8px; border-radius: var(--radius-sm);
355
+ font-size: var(--font-size-base); font-weight: 600;
356
+ color: hsl(var(--gray-white)); line-height: 1.5;
357
+ }
358
+ .method-post { background: hsl(var(--success)); }
359
+ .method-get { background: hsl(var(--primary)); }
360
+ .method-delete { background: hsl(var(--destructive)); }
361
+ .api-path { font-family: var(--font-mono); font-size: var(--font-size-lg); font-weight: var(--font-weight-medium); color: hsl(var(--gray-primary)); }
362
+ .api-copy-btn { width: 24px; height: 24px; background: none; border: none; cursor: pointer; color: hsl(var(--muted-foreground)); opacity: 0; transition: opacity var(--duration-fast); display: flex; align-items: center; justify-content: center; }
363
+ .api-endpoint:hover .api-copy-btn { opacity: 1; }
364
+ .api-copy-btn:hover { color: hsl(var(--primary)); }
365
+ .api-status { margin-left: auto; }
366
+ .badge { display: inline-flex; align-items: center; gap: 4px; padding: 2px 8px; border-radius: var(--radius-sm); font-size: var(--font-size-base); font-weight: var(--font-weight-medium); line-height: 1.5; }
367
+ .badge-success { background: hsl(var(--success-bg)); color: hsl(var(--success)); }
368
+ .badge-dot { width: 6px; height: 6px; border-radius: 50%; }
369
+ .badge-success .badge-dot { background: hsl(var(--success)); }
370
+
371
+ /* ===== DescriptionList ===== */
372
+ .description-list { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0; }
373
+ .description-item { display: flex; align-items: center; height: 36px; padding: 8px 0; gap: 12px; }
374
+ .description-label { min-width: 72px; max-width: 140px; font-size: var(--font-size-base); color: hsl(var(--gray-secondary-foreground)); font-weight: var(--font-weight-normal); flex-shrink: 0; }
375
+ .description-value { font-size: var(--font-size-base); color: hsl(var(--gray-primary)); font-weight: var(--font-weight-normal); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: flex; align-items: center; gap: 4px; }
376
+ .description-value.link { color: hsl(var(--primary)); cursor: pointer; }
377
+ .description-value.link:hover { text-decoration: underline; }
378
+ .description-section { padding: 16px 0; }
379
+
380
+ /* ===== Tabs ===== */
381
+ .tabs { border-bottom: 1px solid hsl(var(--gray-line)); padding-top: 4px; }
382
+ .tabs-list { display: flex; gap: var(--tabs-gap); list-style: none; }
383
+ .tab-item {
384
+ padding: 10px 0; font-size: var(--font-size-lg);
385
+ color: hsl(var(--gray-secondary-foreground)); cursor: pointer;
386
+ border-bottom: 2px solid transparent;
387
+ transition: color var(--duration-fast), border-color var(--duration-fast);
388
+ font-weight: var(--font-weight-normal);
389
+ }
390
+ .tab-item:hover { color: hsl(var(--gray-primary)); }
391
+ .tab-item.active { color: hsl(var(--primary)); border-bottom-color: hsl(var(--primary)); font-weight: var(--font-weight-medium); }
392
+ .tab-content { padding: 16px 0; display: none; }
393
+ .tab-content.active { display: block; }
394
+
395
+ /* ===== ParameterTable ===== */
396
+ .param-table { width: 100%; border-collapse: collapse; }
397
+ .param-table th {
398
+ height: 36px; background: hsl(var(--gray-muted));
399
+ font-size: var(--font-size-base); font-weight: var(--font-weight-medium);
400
+ color: hsl(var(--gray-secondary-foreground)); text-align: left; padding: 0 12px;
401
+ }
402
+ .param-table th:first-child { border-radius: var(--radius-sm) 0 0 var(--radius-sm); }
403
+ .param-table th:last-child { border-radius: 0 var(--radius-sm) var(--radius-sm) 0; }
404
+ .param-table td { height: 40px; padding: 0 12px; font-size: 13px; border-bottom: 1px solid hsl(var(--gray-line)); vertical-align: middle; }
405
+ .param-name { font-family: var(--font-mono); font-size: 13px; color: hsl(var(--gray-primary)); font-weight: var(--font-weight-medium); }
406
+ .param-toggle { cursor: pointer; user-select: none; display: inline-flex; align-items: center; gap: 4px; }
407
+ .param-toggle .arrow { font-size: 10px; color: hsl(var(--muted-foreground)); transition: transform var(--duration-fast); display: inline-block; }
408
+ .param-toggle .arrow.expanded { transform: rotate(90deg); }
409
+ .type-badge {
410
+ display: inline-flex; padding: 1px 6px; border-radius: var(--radius-sm);
411
+ font-size: 11px; font-weight: var(--font-weight-medium); line-height: 1.6;
412
+ }
413
+ .type-string { background: hsl(214 100% 97%); color: hsl(218 100% 47%); }
414
+ .type-number { background: hsl(152 82% 96%); color: hsl(142 76% 36%); }
415
+ .type-boolean { background: hsl(43 100% 94%); color: hsl(40 88% 48%); }
416
+ .type-object { background: hsl(270 100% 97%); color: hsl(262 83% 58%); }
417
+ .type-array { background: hsl(180 40% 94%); color: hsl(180 60% 40%); }
418
+ .param-required { color: hsl(var(--destructive)); font-weight: 600; }
419
+ .param-optional { color: hsl(var(--gray-disabled)); }
420
+ .param-desc { color: hsl(var(--muted-foreground)); }
421
+ .param-child { display: none; }
422
+ .param-child.show { display: table-row; }
423
+ .param-child td:first-child { position: relative; }
424
+ .param-indent-1 { padding-left: 24px !important; }
425
+ .param-indent-2 { padding-left: 48px !important; }
426
+ .param-indent-1::before, .param-indent-2::before {
427
+ content: ''; position: absolute; left: 20px; top: 0; bottom: 0;
428
+ width: 1px; background: hsl(var(--gray-line));
429
+ }
430
+ .param-indent-2::before { left: 44px; }
431
+
432
+ /* ===== CodeBlock ===== */
433
+ .code-block { background: hsl(var(--gray-muted)); border-radius: var(--radius-md); position: relative; overflow: hidden; }
434
+ .code-tabs { display: flex; gap: 0; border-bottom: 1px solid hsl(var(--gray-line)); padding: 0 16px; }
435
+ .code-tab {
436
+ padding: 8px 12px; font-size: var(--font-size-base); cursor: pointer;
437
+ color: hsl(var(--gray-secondary-foreground)); border-bottom: 2px solid transparent;
438
+ transition: color var(--duration-fast), border-color var(--duration-fast);
439
+ }
440
+ .code-tab:hover { color: hsl(var(--gray-primary)); }
441
+ .code-tab.active { color: hsl(var(--primary)); border-bottom-color: hsl(var(--primary)); font-weight: var(--font-weight-medium); }
442
+ .code-content { padding: 16px; overflow-x: auto; }
443
+ .code-content pre {
444
+ font-family: var(--font-mono);
445
+ font-size: 13px; line-height: 1.6;
446
+ color: hsl(var(--gray-primary)); white-space: pre; margin: 0;
447
+ }
448
+ .code-copy-btn {
449
+ position: absolute; top: 44px; right: 12px;
450
+ width: 24px; height: 24px; background: hsl(var(--card));
451
+ border: 1px solid hsl(var(--gray-line)); border-radius: var(--radius-sm);
452
+ cursor: pointer; display: flex; align-items: center; justify-content: center;
453
+ color: hsl(var(--muted-foreground)); opacity: 0; transition: opacity var(--duration-fast);
454
+ }
455
+ .code-block:hover .code-copy-btn { opacity: 1; }
456
+ .code-copy-btn:hover { color: hsl(var(--primary)); border-color: hsl(var(--primary)); }
457
+ .code-panel { display: none; }
458
+ .code-panel.active { display: block; }
459
+
460
+ /* ===== Responsive ===== */
461
+ @media (max-width: 1199px) { .description-list { grid-template-columns: repeat(2, 1fr); } }
462
+ @media (max-width: 768px) { .description-list { grid-template-columns: 1fr; } }
463
+ </style>
464
+ </head>
465
+ <body>
466
+
467
+ <!-- ===== Sidebar ===== -->
468
+ <aside class="sidebar">
469
+ <div class="sidebar-header">
470
+ <div class="sidebar-logo" id="sidebarLogoArea">
471
+ <img src="./_assets/op-ai-gateway-logo.svg" alt="OP AI Gateway" />
472
+ <img class="collapsed-logo" src="./_assets/op-logo-collapsed.png" alt="OP" />
473
+ <svg class="expand-logo" viewBox="0 0 1024 1024" fill="currentColor" width="18" height="18"><path d="M151.68 616.96l82.56-82.56c12.8-12.8 12.8-32.64 0-45.44L151.68 406.4c-19.84-19.84-54.4-5.76-54.4 22.4v165.76c-0.64 28.16 33.92 42.88 54.4 22.4zM128.64 288h768c14.08 0 32-14.08 32-32s-17.92-32-32-32h-768c-14.08 0-32 14.08-32 32s17.92 32 32 32zM896.64 736h-768c-14.08 0-32 14.08-32 32s17.92 32 32 32h768c14.08 0 32-14.08 32-32s-17.28-32-32-32zM896.64 480h-480c-14.08 0-32 14.08-32 32s17.92 32 32 32h480c14.08 0 32-14.08 32-32s-17.28-32-32-32z"/></svg>
474
+ </div>
475
+ <button class="sidebar-collapse-btn" title="收起侧边栏">
476
+ <svg viewBox="0 0 1024 1024" fill="currentColor" width="18" height="18"><path d="M874.24 406.4l-82.56 82.56c-12.8 12.8-12.8 32.64 0 45.44l82.56 82.56c19.84 19.84 54.4 5.76 54.4-22.4V428.8c0-28.16-33.92-42.88-54.4-22.4zM128.64 288h768c14.08 0 32-14.08 32-32s-17.92-32-32-32h-768c-14.08 0-32 14.08-32 32s17.92 32 32 32zM896.64 736h-768c-14.08 0-32 14.08-32 32s17.92 32 32 32h768c14.08 0 32-14.08 32-32s-17.28-32-32-32zM128.64 544h480c14.08 0 32-14.08 32-32s-17.92-32-32-32h-480c-14.08 0-32 14.08-32 32s17.92 32 32 32z"/></svg>
477
+ </button>
478
+ </div>
479
+
480
+ <!-- sidebar:按 PRD 导航结构,L1 为一级菜单,L2 为二级子菜单。 -->
481
+ <div class="sidebar-content">
482
+ <ul class="sidebar-menu">
483
+ <!-- L1: AI 网关(叶子菜单,当前活跃) -->
484
+ <li><a class="sidebar-menu-item active" href="#">
485
+ <span class="item-icon">
486
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/></svg>
487
+ </span>
488
+ AI 网关
489
+ </a></li>
490
+
491
+ <!-- L1: API 网关(父菜单) -->
492
+ <li>
493
+ <a class="sidebar-menu-item expanded" href="#" data-toggle="api-gateway">
494
+ <span class="item-icon">
495
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 6h16M4 12h16M4 18h16"/></svg>
496
+ </span>
497
+ API 网关
498
+ <span class="expand-icon">
499
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 18l6-6-6-6"/></svg>
500
+ </span>
501
+ </a>
502
+ <ul class="sidebar-sub-menu show" id="api-gateway">
503
+ <li><a class="sidebar-menu-item" href="#">实例管理</a></li>
504
+ <li><a class="sidebar-menu-item" href="#">共享实例管理</a></li>
505
+ </ul>
506
+ <div class="sidebar-flyout">
507
+ <a class="sidebar-menu-item" href="#">实例管理</a>
508
+ <a class="sidebar-menu-item" href="#">共享实例管理</a>
509
+ </div>
510
+ </li>
511
+
512
+ <!-- L1: 云原生网关(父菜单) -->
513
+ <li>
514
+ <a class="sidebar-menu-item" href="#" data-toggle="cloud-native-gw">
515
+ <span class="item-icon">
516
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 10h-1.26A8 8 0 109 20h9a5 5 0 000-10z"/></svg>
517
+ </span>
518
+ 云原生网关
519
+ <span class="expand-icon">
520
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 18l6-6-6-6"/></svg>
521
+ </span>
522
+ </a>
523
+ <ul class="sidebar-sub-menu" id="cloud-native-gw">
524
+ <li><a class="sidebar-menu-item" href="#">实例列表</a></li>
525
+ <li><a class="sidebar-menu-item" href="#">Nginx Ingress 迁移</a></li>
526
+ </ul>
527
+ <div class="sidebar-flyout">
528
+ <a class="sidebar-menu-item" href="#">实例列表</a>
529
+ <a class="sidebar-menu-item" href="#">Nginx Ingress 迁移</a>
530
+ </div>
531
+ </li>
532
+
533
+ <!-- L1: 集群管理(叶子菜单) -->
534
+ <li><a class="sidebar-menu-item" href="#">
535
+ <span class="item-icon">
536
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="3"/><path d="M12 1v4M12 19v4M4.22 4.22l2.83 2.83M16.95 16.95l2.83 2.83M1 12h4M19 12h4M4.22 19.78l2.83-2.83M16.95 7.05l2.83-2.83"/></svg>
537
+ </span>
538
+ 集群管理
539
+ </a></li>
540
+
541
+ <!-- L1: 级联管理(父菜单) -->
542
+ <li>
543
+ <a class="sidebar-menu-item" href="#" data-toggle="cascade-mgmt">
544
+ <span class="item-icon">
545
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 6v12M12 3v18M20 6v12M2 6h4M10 3h4M18 6h4M2 12h4M10 9h4M18 12h4M2 18h4M10 21h4M18 18h4"/></svg>
546
+ </span>
547
+ 级联管理
548
+ <span class="expand-icon">
549
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 18l6-6-6-6"/></svg>
550
+ </span>
551
+ </a>
552
+ <ul class="sidebar-sub-menu" id="cascade-mgmt">
553
+ <li><a class="sidebar-menu-item" href="#">级联网关</a></li>
554
+ <li><a class="sidebar-menu-item" href="#">级联链路</a></li>
555
+ </ul>
556
+ <div class="sidebar-flyout">
557
+ <a class="sidebar-menu-item" href="#">级联网关</a>
558
+ <a class="sidebar-menu-item" href="#">级联链路</a>
559
+ </div>
560
+ </li>
561
+
562
+ <!-- L1: 容灾管理(父菜单) -->
563
+ <li>
564
+ <a class="sidebar-menu-item" href="#" data-toggle="disaster-mgmt">
565
+ <span class="item-icon">
566
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>
567
+ </span>
568
+ 容灾管理
569
+ <span class="expand-icon">
570
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 18l6-6-6-6"/></svg>
571
+ </span>
572
+ </a>
573
+ <ul class="sidebar-sub-menu" id="disaster-mgmt">
574
+ <li><a class="sidebar-menu-item" href="#">容灾网关实例</a></li>
575
+ </ul>
576
+ <div class="sidebar-flyout">
577
+ <a class="sidebar-menu-item" href="#">容灾网关实例</a>
578
+ </div>
579
+ </li>
580
+
581
+ <!-- L1: 认证授权(父菜单) -->
582
+ <li>
583
+ <a class="sidebar-menu-item" href="#" data-toggle="auth-mgmt">
584
+ <span class="item-icon">
585
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0110 0v4"/></svg>
586
+ </span>
587
+ 认证授权
588
+ <span class="expand-icon">
589
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 18l6-6-6-6"/></svg>
590
+ </span>
591
+ </a>
592
+ <ul class="sidebar-sub-menu" id="auth-mgmt">
593
+ <li><a class="sidebar-menu-item" href="#">用户管理</a></li>
594
+ <li><a class="sidebar-menu-item" href="#">角色管理</a></li>
595
+ <li><a class="sidebar-menu-item" href="#">权限插件</a></li>
596
+ <li><a class="sidebar-menu-item" href="#">访问凭证</a></li>
597
+ </ul>
598
+ <div class="sidebar-flyout">
599
+ <a class="sidebar-menu-item" href="#">用户管理</a>
600
+ <a class="sidebar-menu-item" href="#">角色管理</a>
601
+ <a class="sidebar-menu-item" href="#">权限插件</a>
602
+ <a class="sidebar-menu-item" href="#">访问凭证</a>
603
+ </div>
604
+ </li>
605
+ </ul>
606
+ </div>
607
+
608
+ <div class="sidebar-divider"></div>
609
+ <div class="sidebar-footer">
610
+ <div class="sidebar-avatar">A</div>
611
+ <span class="sidebar-username">admin</span>
612
+ <button class="sidebar-more">
613
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><circle cx="12" cy="5" r="2"/><circle cx="12" cy="12" r="2"/><circle cx="12" cy="19" r="2"/></svg>
614
+ </button>
615
+ </div>
616
+ </aside>
617
+
618
+ <!-- ===== Main Content ===== -->
619
+ <main class="main-content">
620
+ <div class="page-container">
621
+ <div class="card">
622
+
623
+ <!-- PageHeader — 面包屑模式 -->
624
+ <div class="page-header">
625
+ <div class="page-header-left">
626
+ <nav class="breadcrumb">
627
+ <a href="#">模型 API</a>
628
+ <span class="separator"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 18l6-6-6-6"/></svg></span>
629
+ <a href="#">API 列表</a>
630
+ <span class="separator"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 18l6-6-6-6"/></svg></span>
631
+ <span class="current">chat-completions</span>
632
+ </nav>
633
+ </div>
634
+ <div class="page-header-right">
635
+ <button class="btn btn-primary">在线调试</button>
636
+ <button class="btn btn-outline">
637
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>
638
+ 编辑
639
+ </button>
640
+ <button class="btn btn-ghost btn-icon" title="关闭">
641
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 6L6 18M6 6l12 12"/></svg>
642
+ </button>
643
+ </div>
644
+ </div>
645
+
646
+ <!-- ApiEndpoint -->
647
+ <div class="api-endpoint">
648
+ <span class="method-badge method-post">POST</span>
649
+ <span class="api-path">/v1/chat/completions</span>
650
+ <button class="api-copy-btn" title="复制路径">
651
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
652
+ </button>
653
+ <span class="api-status"><span class="badge badge-success"><span class="badge-dot"></span>已发布</span></span>
654
+ </div>
655
+
656
+ <!-- DescriptionList: 基本信息 -->
657
+ <div class="description-section">
658
+ <div class="description-list">
659
+ <div class="description-item"><span class="description-label">所属服务</span><span class="description-value link">gpt-4o-service</span></div>
660
+ <div class="description-item"><span class="description-label">关联模型</span><span class="description-value">GPT-4o</span></div>
661
+ <div class="description-item"><span class="description-label">创建时间</span><span class="description-value">2026-03-15 10:00:00</span></div>
662
+ <div class="description-item"><span class="description-label">调用次数</span><span class="description-value">1,258,432</span></div>
663
+ <div class="description-item"><span class="description-label">平均延迟</span><span class="description-value">856ms</span></div>
664
+ <div class="description-item"><span class="description-label">认证方式</span><span class="description-value">Bearer Token</span></div>
665
+ <div class="description-item"><span class="description-label">限流策略</span><span class="description-value link">100 RPM / 消费者</span></div>
666
+ <div class="description-item"><span class="description-label">超时设置</span><span class="description-value">60s</span></div>
667
+ <div class="description-item"><span class="description-label">描述</span><span class="description-value">OpenAI 兼容的聊天补全接口</span></div>
668
+ </div>
669
+ </div>
670
+
671
+ <!-- Tabs -->
672
+ <div class="tabs">
673
+ <ul class="tabs-list">
674
+ <li class="tab-item active" onclick="switchTab(0)">请求参数</li>
675
+ <li class="tab-item" onclick="switchTab(1)">响应参数</li>
676
+ <li class="tab-item" onclick="switchTab(2)">请求示例</li>
677
+ <li class="tab-item" onclick="switchTab(3)">响应示例</li>
678
+ </ul>
679
+ </div>
680
+
681
+ <!-- Tab 0: 请求参数 -->
682
+ <div class="tab-content active" id="tab-0">
683
+ <table class="param-table">
684
+ <thead><tr><th style="width:200px">参数名</th><th style="width:80px">类型</th><th style="width:60px">必填</th><th>说明</th></tr></thead>
685
+ <tbody>
686
+ <tr><td><span class="param-name">model</span></td><td><span class="type-badge type-string">string</span></td><td><span class="param-required">*</span></td><td class="param-desc">模型名称,如 "gpt-4o"</td></tr>
687
+ <tr><td><span class="param-name param-toggle" onclick="toggleParam('req-messages')">
688
+ <span class="arrow" id="arrow-req-messages">▶</span> messages
689
+ </span></td><td><span class="type-badge type-array">array</span></td><td><span class="param-required">*</span></td><td class="param-desc">消息列表</td></tr>
690
+ <tr class="param-child" data-group="req-messages"><td class="param-indent-1"><span class="param-name">role</span></td><td><span class="type-badge type-string">string</span></td><td><span class="param-required">*</span></td><td class="param-desc">角色: system / user / assistant</td></tr>
691
+ <tr class="param-child" data-group="req-messages"><td class="param-indent-1"><span class="param-name">content</span></td><td><span class="type-badge type-string">string</span></td><td><span class="param-required">*</span></td><td class="param-desc">消息内容</td></tr>
692
+ <tr><td><span class="param-name">temperature</span></td><td><span class="type-badge type-number">number</span></td><td><span class="param-optional">选填</span></td><td class="param-desc">温度参数,0-2,默认 1</td></tr>
693
+ <tr><td><span class="param-name">max_tokens</span></td><td><span class="type-badge type-number">number</span></td><td><span class="param-optional">选填</span></td><td class="param-desc">最大输出 token 数</td></tr>
694
+ <tr><td><span class="param-name">stream</span></td><td><span class="type-badge type-boolean">boolean</span></td><td><span class="param-optional">选填</span></td><td class="param-desc">是否流式输出,默认 false</td></tr>
695
+ <tr><td><span class="param-name">top_p</span></td><td><span class="type-badge type-number">number</span></td><td><span class="param-optional">选填</span></td><td class="param-desc">核采样参数,0-1</td></tr>
696
+ <tr><td><span class="param-name">frequency_penalty</span></td><td><span class="type-badge type-number">number</span></td><td><span class="param-optional">选填</span></td><td class="param-desc">频率惩罚,-2.0 到 2.0</td></tr>
697
+ </tbody>
698
+ </table>
699
+ </div>
700
+
701
+ <!-- Tab 1: 响应参数 -->
702
+ <div class="tab-content" id="tab-1">
703
+ <table class="param-table">
704
+ <thead><tr><th style="width:200px">参数名</th><th style="width:80px">类型</th><th style="width:60px">必填</th><th>说明</th></tr></thead>
705
+ <tbody>
706
+ <tr><td><span class="param-name">id</span></td><td><span class="type-badge type-string">string</span></td><td>—</td><td class="param-desc">请求唯一标识</td></tr>
707
+ <tr><td><span class="param-name">object</span></td><td><span class="type-badge type-string">string</span></td><td>—</td><td class="param-desc">固定为 "chat.completion"</td></tr>
708
+ <tr><td><span class="param-name">created</span></td><td><span class="type-badge type-number">number</span></td><td>—</td><td class="param-desc">Unix 时间戳</td></tr>
709
+ <tr><td><span class="param-name">model</span></td><td><span class="type-badge type-string">string</span></td><td>—</td><td class="param-desc">实际使用的模型</td></tr>
710
+ <tr><td><span class="param-name param-toggle" onclick="toggleParam('res-choices')">
711
+ <span class="arrow" id="arrow-res-choices">▶</span> choices
712
+ </span></td><td><span class="type-badge type-array">array</span></td><td>—</td><td class="param-desc">返回结果列表</td></tr>
713
+ <tr class="param-child" data-group="res-choices"><td class="param-indent-1"><span class="param-name">index</span></td><td><span class="type-badge type-number">number</span></td><td>—</td><td class="param-desc">结果索引</td></tr>
714
+ <tr class="param-child" data-group="res-choices"><td class="param-indent-1"><span class="param-name param-toggle" onclick="toggleParam('res-message')">
715
+ <span class="arrow" id="arrow-res-message">▶</span> message
716
+ </span></td><td><span class="type-badge type-object">object</span></td><td>—</td><td class="param-desc">消息对象</td></tr>
717
+ <tr class="param-child" data-group="res-message"><td class="param-indent-2"><span class="param-name">role</span></td><td><span class="type-badge type-string">string</span></td><td>—</td><td class="param-desc">"assistant"</td></tr>
718
+ <tr class="param-child" data-group="res-message"><td class="param-indent-2"><span class="param-name">content</span></td><td><span class="type-badge type-string">string</span></td><td>—</td><td class="param-desc">回复内容</td></tr>
719
+ <tr class="param-child" data-group="res-choices"><td class="param-indent-1"><span class="param-name">finish_reason</span></td><td><span class="type-badge type-string">string</span></td><td>—</td><td class="param-desc">结束原因</td></tr>
720
+ <tr><td><span class="param-name param-toggle" onclick="toggleParam('res-usage')">
721
+ <span class="arrow" id="arrow-res-usage">▶</span> usage
722
+ </span></td><td><span class="type-badge type-object">object</span></td><td>—</td><td class="param-desc">Token 用量</td></tr>
723
+ <tr class="param-child" data-group="res-usage"><td class="param-indent-1"><span class="param-name">prompt_tokens</span></td><td><span class="type-badge type-number">number</span></td><td>—</td><td class="param-desc">提示词 token 数</td></tr>
724
+ <tr class="param-child" data-group="res-usage"><td class="param-indent-1"><span class="param-name">completion_tokens</span></td><td><span class="type-badge type-number">number</span></td><td>—</td><td class="param-desc">补全 token 数</td></tr>
725
+ <tr class="param-child" data-group="res-usage"><td class="param-indent-1"><span class="param-name">total_tokens</span></td><td><span class="type-badge type-number">number</span></td><td>—</td><td class="param-desc">总 token 数</td></tr>
726
+ </tbody>
727
+ </table>
728
+ </div>
729
+
730
+ <!-- Tab 2: 请求示例 -->
731
+ <div class="tab-content" id="tab-2">
732
+ <div class="code-block">
733
+ <div class="code-tabs">
734
+ <span class="code-tab active" onclick="switchCodeTab(this, 'code-req')">curl</span>
735
+ <span class="code-tab" onclick="switchCodeTab(this, 'code-req')">Python</span>
736
+ <span class="code-tab" onclick="switchCodeTab(this, 'code-req')">Node.js</span>
737
+ <span class="code-tab" onclick="switchCodeTab(this, 'code-req')">Java</span>
738
+ </div>
739
+ <button class="code-copy-btn" title="复制代码">
740
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
741
+ </button>
742
+ <div class="code-content">
743
+ <div class="code-panel active" data-group="code-req"><pre>curl -X POST https://api.ai-gateway.com/v1/chat/completions \
744
+ -H "Authorization: Bearer sk-xxxx" \
745
+ -H "Content-Type: application/json" \
746
+ -d '{
747
+ "model": "gpt-4o",
748
+ "messages": [
749
+ {"role": "system", "content": "You are a helpful assistant."},
750
+ {"role": "user", "content": "Hello!"}
751
+ ],
752
+ "temperature": 0.7
753
+ }'</pre></div>
754
+ <div class="code-panel" data-group="code-req"><pre>import requests
755
+
756
+ response = requests.post(
757
+ "https://api.ai-gateway.com/v1/chat/completions",
758
+ headers={
759
+ "Authorization": "Bearer sk-xxxx",
760
+ "Content-Type": "application/json"
761
+ },
762
+ json={
763
+ "model": "gpt-4o",
764
+ "messages": [
765
+ {"role": "system", "content": "You are a helpful assistant."},
766
+ {"role": "user", "content": "Hello!"}
767
+ ],
768
+ "temperature": 0.7
769
+ }
770
+ )
771
+ print(response.json())</pre></div>
772
+ <div class="code-panel" data-group="code-req"><pre>const response = await fetch(
773
+ 'https://api.ai-gateway.com/v1/chat/completions',
774
+ {
775
+ method: 'POST',
776
+ headers: {
777
+ 'Authorization': 'Bearer sk-xxxx',
778
+ 'Content-Type': 'application/json'
779
+ },
780
+ body: JSON.stringify({
781
+ model: 'gpt-4o',
782
+ messages: [
783
+ { role: 'system', content: 'You are a helpful assistant.' },
784
+ { role: 'user', content: 'Hello!' }
785
+ ],
786
+ temperature: 0.7
787
+ })
788
+ }
789
+ );
790
+ const data = await response.json();
791
+ console.log(data);</pre></div>
792
+ <div class="code-panel" data-group="code-req"><pre>import java.net.http.*;
793
+ import java.net.URI;
794
+
795
+ HttpClient client = HttpClient.newHttpClient();
796
+
797
+ String body = """
798
+ {
799
+ "model": "gpt-4o",
800
+ "messages": [
801
+ {"role": "system", "content": "You are a helpful assistant."},
802
+ {"role": "user", "content": "Hello!"}
803
+ ],
804
+ "temperature": 0.7
805
+ }
806
+ """;
807
+
808
+ HttpRequest request = HttpRequest.newBuilder()
809
+ .uri(URI.create("https://api.ai-gateway.com/v1/chat/completions"))
810
+ .header("Authorization", "Bearer sk-xxxx")
811
+ .header("Content-Type", "application/json")
812
+ .POST(HttpRequest.BodyPublishers.ofString(body))
813
+ .build();
814
+
815
+ HttpResponse&lt;String&gt; response = client.send(
816
+ request, HttpResponse.BodyHandlers.ofString());
817
+ System.out.println(response.body());</pre></div>
818
+ </div>
819
+ </div>
820
+ </div>
821
+
822
+ <!-- Tab 3: 响应示例 -->
823
+ <div class="tab-content" id="tab-3">
824
+ <div class="code-block">
825
+ <div class="code-tabs">
826
+ <span class="code-tab active">JSON</span>
827
+ </div>
828
+ <button class="code-copy-btn" title="复制代码">
829
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
830
+ </button>
831
+ <div class="code-content">
832
+ <div class="code-panel active"><pre>{
833
+ "id": "chatcmpl-abc123",
834
+ "object": "chat.completion",
835
+ "created": 1716825600,
836
+ "model": "gpt-4o",
837
+ "choices": [
838
+ {
839
+ "index": 0,
840
+ "message": {
841
+ "role": "assistant",
842
+ "content": "Hello! How can I help you today?"
843
+ },
844
+ "finish_reason": "stop"
845
+ }
846
+ ],
847
+ "usage": {
848
+ "prompt_tokens": 12,
849
+ "completion_tokens": 9,
850
+ "total_tokens": 21
851
+ }
852
+ }</pre></div>
853
+ </div>
854
+ </div>
855
+ </div>
856
+
857
+ </div><!-- /card -->
858
+ </div><!-- /page-container -->
859
+ </main>
860
+
861
+ <script>
862
+ // Sidebar collapse toggle
863
+ const sidebar = document.querySelector('.sidebar');
864
+ document.querySelector('.sidebar-collapse-btn').addEventListener('click', function() {
865
+ sidebar.classList.toggle('collapsed');
866
+ });
867
+ // Sidebar expand via logo click (collapsed state)
868
+ document.getElementById('sidebarLogoArea').addEventListener('click', function() {
869
+ if (sidebar.classList.contains('collapsed')) {
870
+ sidebar.classList.remove('collapsed');
871
+ }
872
+ });
873
+ // Sidebar sub-menu toggle
874
+ document.querySelectorAll('.sidebar-menu-item[data-toggle]').forEach(item => {
875
+ item.addEventListener('click', function(e) {
876
+ e.preventDefault();
877
+ this.classList.toggle('expanded');
878
+ const targetId = this.getAttribute('data-toggle');
879
+ const target = document.getElementById(targetId);
880
+ if (target) target.classList.toggle('show');
881
+ });
882
+ });
883
+
884
+ function switchTab(index) {
885
+ document.querySelectorAll('.tab-item').forEach((t, i) => t.classList.toggle('active', i === index));
886
+ document.querySelectorAll('.tab-content').forEach((c, i) => c.classList.toggle('active', i === index));
887
+ }
888
+
889
+ function toggleParam(group) {
890
+ const arrow = document.getElementById('arrow-' + group);
891
+ const rows = document.querySelectorAll('[data-group="' + group + '"]');
892
+ const expanded = arrow.classList.toggle('expanded');
893
+ rows.forEach(r => r.classList.toggle('show', expanded));
894
+ }
895
+
896
+ function switchCodeTab(el, group) {
897
+ const parent = el.closest('.code-block');
898
+ parent.querySelectorAll('.code-tab').forEach(t => t.classList.remove('active'));
899
+ el.classList.add('active');
900
+ const panels = parent.querySelectorAll('.code-panel[data-group="' + group + '"]');
901
+ const idx = Array.from(el.parentElement.children).indexOf(el);
902
+ panels.forEach((p, i) => p.classList.toggle('active', i === idx));
903
+ }
904
+ </script>
905
+ </body>
906
+ </html>