@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,933 @@
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>详情页 · 标准参考范例 — v7.8.4</title>
7
+ <!--
8
+ ★ 详情页标准参考范例(Standard Detail Page Reference)
9
+ ─────────────────────────────────────────────────────────────
10
+ 用途:AI 生成详情页时的基础参考,展示完整页面骨架与组件组合
11
+ ─────────────────────────────────────────────────────────────
12
+ 布局:TWO_COL(Sidebar + ContentCard 单例容器)
13
+ Sidebar:完整 L2 框架(折叠/展开 240px↔68px)
14
+ 内容区模式:模式B + 模式C 组合(Card + Tabs)
15
+ 子类型:资源详情页
16
+ ─────────────────────────────────────────────────────────────
17
+ 组件清单:
18
+ • PageHeader — 面包屑模式 + 操作按钮组
19
+ • InfoCard — 顶部摘要卡片
20
+ • Tabs — 实例详情/监控/关联资源
21
+ • DescriptionList — 键值对列表,3列布局
22
+ • DescriptionItem — 6种交互模式展示
23
+ • Badge — 状态展示
24
+ • DropdownMenu — “更多”操作
25
+ • Tooltip — 长文本悬浮提示
26
+ ─────────────────────────────────────────────────────────────
27
+ 规范来源:pages/detail-page/SKILL.md v7.8.4
28
+ Tokens 版本:v7.8.4(间距与 v7.5 分层 padding 模型对齐 + v7.6 ContentCard/InfoCard 表面规则 + v7.8.4 字体族变量)
29
+ 组件规格:component-specs.json C26-DescriptionList
30
+ 表面边界:PageHeader / Tabs / Separator 的 border 为「功能性分割线」,不受 v7.6 surface 约束(见 SKILL.md §6.5.4)
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
+ /* Legacy 别名(v7.4 向后兼容) */
50
+ --gray-title: 220 9% 7%;
51
+ --gray-secondary: 216 4% 26%;
52
+ --gray-tertiary: 216 2% 45%;
53
+ --gray-border: 210 9% 91%;
54
+ --gray-fill: 220 18% 97%;
55
+ --gray-bg-dark: 220 18% 97%;
56
+ --gray-bg: 220 18% 97%;
57
+ --success: 142 76% 36%;
58
+ --success-bg: 152 82% 96%;
59
+ --success-border: 142 77% 73%;
60
+ --warning: 40 88% 48%;
61
+ --warning-bg: 43 100% 94%;
62
+ --destructive: 0 72% 51%;
63
+ --destructive-bg: 0 86% 97%;
64
+ --info: 221 83% 53%;
65
+ --info-bg: 214 100% 97%;
66
+ --background: 220 18% 97%;
67
+ --card: 0 0% 100%;
68
+ --card-foreground: 220 9% 7%;
69
+ --border: 210 9% 91%;
70
+ --ring: 218.6 100% 46.7%;
71
+ --sidebar: 220 18% 97%;
72
+ --sidebar-foreground: 220 9% 7%;
73
+ --sidebar-active: 210 12% 93%;
74
+ --sidebar-active-foreground: 220 9% 7%;
75
+ --sidebar-hover: 220 18% 97%;
76
+ --sidebar-group: 216 2% 45%;
77
+ --sidebar-item: 220 9% 7%;
78
+ --sidebar-item-muted: 216 4% 26%;
79
+ --sidebar-border: 210 9% 91%;
80
+ --radius: 1rem;
81
+ --radius-sm: 4px;
82
+ --radius-md: 8px;
83
+ --radius-lg: 12px;
84
+ --gap-xs: 4px;
85
+ --btn-padding-x: 16px;
86
+ --btn-padding-x-sm: 12px;
87
+ --button-gap: 8px;
88
+ --tabs-gap: 24px;
89
+ --card-gap: 16px;
90
+ --page-container-gap: 16px;
91
+ --page-container-padding: 16px;
92
+ --page-container-padding-left: 0px;
93
+ --card-padding-x: 20px;
94
+ --shadow-sm: 0 1px 2px rgba(0,0,0,0.05);
95
+ --font-size-base: 12px;
96
+ --font-size-lg: 14px;
97
+ --font-size-xl: 16px;
98
+ --font-size-2xl: 18px;
99
+ --font-size-page-header: 18px;
100
+ --font-sans: 'PingFang SC', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;
101
+ --font-mono: 'SF Mono', Monaco, 'Courier New', monospace;
102
+ --font-weight-normal: 400;
103
+ --font-weight-medium: 500;
104
+ --font-weight-black: 900;
105
+ --input-height: 32px;
106
+ --input-radius: 8px;
107
+ --layout-sidebar-width: 240px;
108
+ --duration-fast: 150ms;
109
+ --duration-normal: 200ms;
110
+ --easing-ease: ease;
111
+ }
112
+
113
+ body {
114
+ font-family: var(--font-sans);
115
+ font-size: var(--font-size-base);
116
+ color: hsl(var(--gray-primary));
117
+ background: hsl(var(--background));
118
+ min-height: 100vh;
119
+ }
120
+
121
+ /* ===== Sidebar ===== */
122
+ .sidebar {
123
+ position: fixed; top: 0; left: 0; bottom: 0;
124
+ width: var(--layout-sidebar-width);
125
+ background: hsl(var(--sidebar));
126
+ z-index: 100;
127
+ display: flex; flex-direction: column;
128
+ overflow: hidden;
129
+ transition: width 0.2s ease;
130
+ }
131
+ .sidebar-header {
132
+ height: 56px; padding: 0 16px;
133
+ display: flex; align-items: center; gap: var(--gap-xs);
134
+ flex-shrink: 0;
135
+ }
136
+ .sidebar-logo {
137
+ height: 28px; flex-shrink: 0;
138
+ display: flex; align-items: center;
139
+ overflow: hidden;
140
+ }
141
+ .sidebar-logo img {
142
+ height: 28px; width: auto; display: block;
143
+ }
144
+ .sidebar-logo .collapsed-logo {
145
+ display: none; width: 30px; height: 30px;
146
+ }
147
+ .sidebar-logo .expand-logo {
148
+ display: none; width: 18px; height: 18px;
149
+ color: hsl(var(--muted-foreground));
150
+ }
151
+ .sidebar-collapse-btn {
152
+ margin-left: auto; width: 18px; height: 18px;
153
+ background: none; border: none; padding: 0; cursor: pointer;
154
+ display: flex; align-items: center; justify-content: center;
155
+ color: hsl(var(--muted-foreground)); flex-shrink: 0;
156
+ }
157
+ .sidebar-collapse-btn svg { width: 18px; height: 18px; }
158
+
159
+ /* ===== Sidebar Collapsed State ===== */
160
+ .sidebar.collapsed { width: 68px; overflow: visible; }
161
+ .sidebar.collapsed .sidebar-header { padding: 0 12px; justify-content: center; }
162
+ .sidebar.collapsed .sidebar-logo { cursor: pointer; }
163
+ .sidebar.collapsed .sidebar-logo img { display: none; }
164
+ .sidebar.collapsed .sidebar-logo .collapsed-logo { display: block; }
165
+ .sidebar.collapsed .sidebar-logo:hover .collapsed-logo { display: none; }
166
+ .sidebar.collapsed .sidebar-logo:hover .expand-logo { display: block; }
167
+ .sidebar.collapsed .sidebar-collapse-btn { display: none; }
168
+ .sidebar.collapsed .sidebar-content { padding: 12px 0; overflow-y: auto; overflow-x: hidden; }
169
+ .sidebar.collapsed .sidebar-menu { padding: 0; }
170
+ .sidebar.collapsed .sidebar-menu > li { display: flex; justify-content: center; }
171
+ .sidebar.collapsed .sidebar-menu > li > a.sidebar-menu-item {
172
+ justify-content: center; padding: 0; width: 40px; height: 40px;
173
+ border-radius: var(--radius-md); position: relative; flex-shrink: 0;
174
+ gap: 0;
175
+ }
176
+ .sidebar.collapsed .sidebar-menu > li > a.sidebar-menu-item .item-icon { margin: 0; }
177
+ .sidebar.collapsed .sidebar-menu > li > a > span:not(.item-icon),
178
+ .sidebar.collapsed .sidebar-menu > li > a > .expand-icon,
179
+ .sidebar.collapsed .sidebar-menu-item:not(.item-icon):after { display: none; }
180
+ /* 隐藏文字节点(直接文本) */
181
+ .sidebar.collapsed .sidebar-menu > li > a { font-size: 0; }
182
+ .sidebar.collapsed .sidebar-menu > li > a > .item-icon { font-size: var(--font-size-lg); }
183
+ .sidebar.collapsed .sidebar-sub-menu { display: none !important; }
184
+ .sidebar.collapsed .sidebar-divider { margin: 0 14px; }
185
+ .sidebar.collapsed .sidebar-footer { padding: 12px 10px 16px; justify-content: center; }
186
+ .sidebar.collapsed .sidebar-username,
187
+ .sidebar.collapsed .sidebar-more { display: none; }
188
+
189
+ /* ===== Sidebar Collapsed Flyout (hover 浮层展示二级菜单) ===== */
190
+ .sidebar.collapsed .sidebar-menu > li { position: relative; }
191
+ .sidebar.collapsed .sidebar-menu > li:hover > .sidebar-flyout {
192
+ display: block;
193
+ }
194
+ .sidebar-flyout {
195
+ display: none;
196
+ position: absolute; left: 100%; top: 0;
197
+ min-width: 160px; padding: 4px;
198
+ background: hsl(var(--card));
199
+ border: 1px solid hsl(var(--gray-line));
200
+ border-radius: var(--radius-md);
201
+ box-shadow: 0 4px 12px rgba(0,0,0,0.08);
202
+ z-index: 200;
203
+ }
204
+ .sidebar-flyout .sidebar-menu-item {
205
+ height: 36px; padding: 0 12px;
206
+ font-size: var(--font-size-base) !important;
207
+ font-weight: var(--font-weight-normal);
208
+ color: hsl(var(--gray-primary));
209
+ border-radius: var(--radius-sm);
210
+ white-space: nowrap;
211
+ }
212
+ .sidebar-flyout .sidebar-menu-item:hover {
213
+ background: hsl(var(--gray-muted));
214
+ }
215
+
216
+ /* Main content 响应 sidebar 收起 */
217
+ .main-content {
218
+ margin-left: var(--layout-sidebar-width);
219
+ min-height: 100vh;
220
+ transition: margin-left 0.2s ease;
221
+ }
222
+ .sidebar.collapsed ~ .main-content { margin-left: 68px; }
223
+ .sidebar-product {
224
+ font-size: var(--font-size-xl); font-weight: var(--font-weight-black);
225
+ color: hsl(var(--sidebar-foreground)); letter-spacing: -0.025em;
226
+ white-space: nowrap; line-height: 1;
227
+ }
228
+ .sidebar-content {
229
+ flex: 1; overflow-y: auto; padding: 12px 0;
230
+ }
231
+ /* twoLevel 变体:去掉 sidebar-group-label,主菜单之间间距由 li padding 提供;保留 sidebar-group-label 样式以兼容其他页面。 */
232
+ .sidebar-group-label {
233
+ padding: 0 16px; height: 26px; line-height: 26px;
234
+ font-size: var(--font-size-base); font-weight: var(--font-weight-normal);
235
+ color: hsl(var(--sidebar-group));
236
+ }
237
+ .sidebar-group-label:not(:first-child) { margin-top: 16px; }
238
+ .sidebar-menu { list-style: none; padding: 0 8px; display: flex; flex-direction: column; gap: 2px; }
239
+ .sidebar-menu-item {
240
+ display: flex; align-items: center; gap: var(--button-gap);
241
+ padding: 0 12px; height: 40px;
242
+ border-radius: var(--radius-md);
243
+ font-size: var(--font-size-lg); font-weight: var(--font-weight-medium);
244
+ color: hsl(var(--sidebar-item-muted));
245
+ text-decoration: none; cursor: pointer;
246
+ transition: background var(--duration-fast), color var(--duration-fast);
247
+ white-space: nowrap;
248
+ }
249
+ .sidebar-menu-item:hover {
250
+ background: hsl(var(--sidebar-hover));
251
+ color: hsl(var(--sidebar-item));
252
+ }
253
+ .sidebar-menu-item.active {
254
+ background: hsl(var(--sidebar-active));
255
+ color: hsl(var(--sidebar-active-foreground));
256
+ }
257
+ .sidebar-menu-item .item-icon {
258
+ width: 16px; height: 16px; flex-shrink: 0;
259
+ display: flex; align-items: center; justify-content: center;
260
+ }
261
+ .sidebar-menu-item .expand-icon {
262
+ margin-left: auto; width: 16px; height: 16px;
263
+ transition: transform var(--duration-fast);
264
+ }
265
+ .sidebar-menu-item.expanded .expand-icon { transform: rotate(90deg); }
266
+ .sidebar-sub-menu {
267
+ list-style: none; padding: 0 0 0 24px;
268
+ display: none;
269
+ }
270
+ /* twoLevel 变体:子菜单与主菜单在同一列上下对齐。sub-menu 不再加左 padding,由子菜单项自身 padding-left = 12+16+8 = 36px 代替主菜单的 "padding+icon+gap",使文字起点 x 坐标与主菜单一致。 */
271
+ .sidebar-menu > li > .sidebar-sub-menu { padding-left: 0; }
272
+ .sidebar-sub-menu.show { display: block; }
273
+ .sidebar-sub-menu .sidebar-menu-item {
274
+ height: 36px; font-size: var(--font-size-base); font-weight: var(--font-weight-normal);
275
+ /* twoLevel 变体对齐规则:36px = 主菜单 padding-left(12) + item-icon(16) + gap(8),使文字与主菜单文字上下对齐。 */
276
+ padding-left: 36px;
277
+ }
278
+ .sidebar-divider {
279
+ height: 1px; background: hsl(var(--sidebar-border));
280
+ margin: 0 12px; flex-shrink: 0;
281
+ }
282
+ .sidebar-footer {
283
+ flex-shrink: 0; display: flex; align-items: center;
284
+ gap: var(--button-gap); padding: 12px 12px 16px 24px;
285
+ }
286
+ .sidebar-avatar {
287
+ width: 28px; height: 28px; border-radius: 50%;
288
+ background: hsl(var(--sidebar-active));
289
+ display: flex; align-items: center; justify-content: center;
290
+ font-size: var(--font-size-base); font-weight: 600;
291
+ color: hsl(var(--gray-primary)); flex-shrink: 0;
292
+ }
293
+ .sidebar-username {
294
+ flex: 1; font-size: var(--font-size-lg); font-weight: var(--font-weight-medium);
295
+ color: hsl(var(--sidebar-item)); overflow: hidden;
296
+ text-overflow: ellipsis; white-space: nowrap;
297
+ }
298
+ .sidebar-more {
299
+ width: 28px; height: 28px; border-radius: var(--radius-sm);
300
+ border: none; background: transparent; cursor: pointer;
301
+ display: flex; align-items: center; justify-content: center;
302
+ color: hsl(var(--muted-foreground));
303
+ }
304
+ .sidebar-more:hover { background: hsl(var(--sidebar-hover)); color: hsl(var(--gray-primary)); }
305
+
306
+ /* ===== Main Content ===== */
307
+
308
+ .page-container {
309
+ padding: var(--page-container-padding) var(--page-container-padding) var(--page-container-padding) var(--page-container-padding-left);
310
+ }
311
+ .card {
312
+ background: hsl(var(--card));
313
+ border-radius: var(--radius-lg);
314
+ /* v7.6:去掉 1px border,使用最弱阴影 var(--shadow-sm) */
315
+ box-shadow: var(--shadow-sm, 0 1px 2px rgba(0,0,0,0.05));
316
+ overflow: hidden;
317
+ display: flex; flex-direction: column;
318
+ min-height: calc(100vh - 40px);
319
+ padding: 0 var(--card-padding-x);
320
+ }
321
+
322
+ /* ===== PageHeader — Breadcrumb Mode ===== */
323
+ /* L2 面包屑模式:无 border、无 background、无 box-shadow;高度 64px,padding 由外层 Card 提供 */
324
+ .page-header {
325
+ height: 64px; padding: 0;
326
+ display: flex; align-items: center; justify-content: space-between;
327
+ flex-shrink: 0;
328
+ }
329
+ .page-header-left { display: flex; align-items: center; }
330
+ .breadcrumb {
331
+ display: flex; align-items: center; gap: 4px;
332
+ font-size: var(--font-size-page-header); font-weight: var(--font-weight-medium);
333
+ color: hsl(var(--gray-secondary-foreground));
334
+ }
335
+ .breadcrumb a { color: hsl(var(--gray-secondary-foreground)); text-decoration: none; }
336
+ .breadcrumb a:hover { color: hsl(var(--gray-primary)); }
337
+ .breadcrumb .separator { color: hsl(var(--muted-foreground)); display: flex; align-items: center; }
338
+ .breadcrumb .separator svg { width: 20px; height: 20px; }
339
+ .breadcrumb .current { color: hsl(var(--gray-primary)); }
340
+ .page-header-title {
341
+ font-size: var(--font-size-page-header); font-weight: var(--font-weight-medium);
342
+ color: hsl(var(--gray-primary)); line-height: 1.3;
343
+ }
344
+ .page-header-right { display: flex; align-items: center; gap: var(--button-gap); }
345
+
346
+ /* ===== Buttons ===== */
347
+ .btn {
348
+ display: inline-flex; align-items: center; justify-content: center; gap: var(--gap-xs);
349
+ height: var(--input-height); padding: 0 var(--btn-padding-x);
350
+ border-radius: var(--radius-md); font-size: var(--font-size-base);
351
+ font-weight: var(--font-weight-medium); border: none; cursor: pointer;
352
+ transition: background var(--duration-fast), opacity var(--duration-fast);
353
+ white-space: nowrap;
354
+ }
355
+ .btn-primary { background: hsl(var(--primary)); color: hsl(var(--primary-foreground)); }
356
+ .btn-primary:hover { background: hsl(var(--primary-hover)); }
357
+ .btn-outline { background: hsl(var(--card)); color: hsl(var(--gray-primary)); border: 1px solid hsl(var(--gray-line)); }
358
+ .btn-outline:hover { background: hsl(var(--gray-muted)); }
359
+ .btn-ghost { background: transparent; color: hsl(var(--gray-primary)); }
360
+ .btn-ghost:hover { background: hsl(var(--gray-muted)); }
361
+ .btn-destructive { background: transparent; color: hsl(var(--destructive)); border: 1px solid hsl(var(--destructive)); }
362
+ .btn-destructive:hover { background: hsl(var(--destructive-bg)); }
363
+ .btn-icon { width: var(--input-height); padding: 0; }
364
+
365
+ /* ===== InfoCard ===== */
366
+ /* 本例 InfoCard 采用「嵌入主卡内的分组区块」实现(仅 padding 控制间距,无分割线),非独立 Card 容器。
367
+ 如采用「独立 Card 容器」实现时,需跟随主卡 ContentCard 应用 v7.6 表面规则:
368
+ border: none + box-shadow: var(--shadow-sm) + border-radius: var(--radius-lg)。见 SKILL.md §6.5.3 */
369
+ .info-card {
370
+ padding: 16px 0;
371
+ }
372
+ .info-card-header {
373
+ display: flex; align-items: center; gap: 12px; margin-bottom: 12px;
374
+ }
375
+ .info-card-icon {
376
+ width: 40px; height: 40px; border-radius: var(--radius-md);
377
+ background: hsl(var(--info-bg));
378
+ display: flex; align-items: center; justify-content: center;
379
+ color: hsl(var(--primary));
380
+ }
381
+ .info-card-meta { flex: 1; }
382
+ .info-card-name { font-size: var(--font-size-xl); font-weight: var(--font-weight-medium); color: hsl(var(--gray-primary)); }
383
+ .info-card-desc { font-size: var(--font-size-base); color: hsl(var(--gray-secondary-foreground)); margin-top: 2px; }
384
+ .info-card-summary {
385
+ display: grid; grid-template-columns: repeat(4, 1fr); gap: 0;
386
+ }
387
+ .info-card-item {
388
+ padding: 8px 0;
389
+ }
390
+ .info-card-item-label { font-size: var(--font-size-base); color: hsl(var(--gray-secondary-foreground)); margin-bottom: 4px; }
391
+ .info-card-item-value { font-size: var(--font-size-lg); color: hsl(var(--gray-primary)); font-weight: var(--font-weight-medium); }
392
+
393
+ /* ===== Tabs ===== */
394
+ .tabs {
395
+ border-bottom: 1px solid hsl(var(--gray-line));
396
+ padding-top: 4px;
397
+ }
398
+ .tabs-list {
399
+ display: flex; gap: var(--tabs-gap); list-style: none;
400
+ }
401
+ .tab-item {
402
+ padding: 10px 0; font-size: var(--font-size-lg);
403
+ color: hsl(var(--gray-secondary-foreground)); cursor: pointer;
404
+ border-bottom: 2px solid transparent;
405
+ transition: color var(--duration-fast), border-color var(--duration-fast);
406
+ font-weight: var(--font-weight-normal);
407
+ }
408
+ .tab-item:hover { color: hsl(var(--gray-primary)); }
409
+ .tab-item.active {
410
+ color: hsl(var(--primary));
411
+ border-bottom-color: hsl(var(--primary));
412
+ font-weight: var(--font-weight-medium);
413
+ }
414
+ .tab-content { padding: 20px 0; }
415
+
416
+ /* ===== DescriptionList + DescriptionItem ===== */
417
+ /* C26 规格:row.height=36px, row.paddingY=8px, label.color=gray-secondary, value.color=gray-primary */
418
+ .description-list {
419
+ display: grid;
420
+ grid-template-columns: repeat(3, 1fr);
421
+ gap: 0;
422
+ }
423
+ .description-item {
424
+ display: flex; align-items: center;
425
+ height: 36px; padding: 8px 0;
426
+ gap: 12px;
427
+ }
428
+ .description-label {
429
+ min-width: 80px; max-width: 140px;
430
+ font-size: var(--font-size-base); color: hsl(var(--gray-secondary-foreground));
431
+ font-weight: var(--font-weight-normal);
432
+ flex-shrink: 0;
433
+ }
434
+ .description-value {
435
+ font-size: var(--font-size-base); color: hsl(var(--gray-primary));
436
+ font-weight: var(--font-weight-normal);
437
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
438
+ display: flex; align-items: center; gap: 4px;
439
+ }
440
+ .description-value.copyable { cursor: pointer; }
441
+ .description-value.copyable .copy-icon {
442
+ width: 16px; height: 16px; color: hsl(var(--muted-foreground));
443
+ opacity: 0; transition: opacity var(--duration-fast);
444
+ flex-shrink: 0;
445
+ }
446
+ .description-item:hover .description-value.copyable .copy-icon { opacity: 1; }
447
+ .description-value.copyable .copy-icon:hover { color: hsl(var(--primary)); }
448
+ .description-value.link { color: hsl(var(--primary)); cursor: pointer; }
449
+ .description-value.link:hover { text-decoration: underline; }
450
+ .description-value .empty-val { color: hsl(var(--gray-disabled)); }
451
+
452
+ /* ListSection 分组 */
453
+ .list-section { padding-top: 20px; }
454
+ .list-section:first-child { padding-top: 0; }
455
+ .list-section:not(:first-child) { border-top: 1px solid hsl(var(--gray-line)); }
456
+ .list-section-title {
457
+ font-size: var(--font-size-lg); font-weight: 600;
458
+ color: hsl(var(--gray-primary)); margin-bottom: 12px;
459
+ }
460
+
461
+ /* ===== Badge ===== */
462
+ .badge {
463
+ display: inline-flex; align-items: center; gap: 4px;
464
+ padding: 2px 8px; border-radius: var(--radius-sm);
465
+ font-size: var(--font-size-base); font-weight: var(--font-weight-medium);
466
+ line-height: 1.5;
467
+ }
468
+ .badge-success { background: hsl(var(--success-bg)); color: hsl(var(--success)); }
469
+ .badge-warning { background: hsl(var(--warning-bg)); color: hsl(var(--warning)); }
470
+ .badge-destructive { background: hsl(var(--destructive-bg)); color: hsl(var(--destructive)); }
471
+ .badge-dot {
472
+ width: 6px; height: 6px; border-radius: 50%;
473
+ }
474
+ .badge-success .badge-dot { background: hsl(var(--success)); }
475
+ .badge-warning .badge-dot { background: hsl(var(--warning)); }
476
+
477
+ /* ===== Tooltip ===== */
478
+ .tooltip-trigger { position: relative; }
479
+ .tooltip-trigger:hover .tooltip-content { display: block; }
480
+ .tooltip-content {
481
+ display: none; position: absolute; bottom: calc(100% + 6px); left: 50%;
482
+ transform: translateX(-50%);
483
+ background: hsl(var(--gray-primary)); color: hsl(var(--gray-white));
484
+ padding: 6px 10px; border-radius: var(--radius-sm);
485
+ font-size: var(--font-size-base); white-space: nowrap;
486
+ z-index: 500;
487
+ }
488
+ .tooltip-content::after {
489
+ content: ''; position: absolute; top: 100%; left: 50%;
490
+ transform: translateX(-50%);
491
+ border: 4px solid transparent; border-top-color: hsl(var(--gray-primary));
492
+ }
493
+
494
+ /* ===== DropdownMenu ===== */
495
+ .dropdown { position: relative; display: inline-block; }
496
+ .dropdown-menu {
497
+ display: none; position: absolute; top: calc(100% + 4px); right: 0;
498
+ min-width: 140px; padding: 4px;
499
+ background: hsl(var(--card)); border: 1px solid hsl(var(--gray-line));
500
+ border-radius: var(--radius-md);
501
+ box-shadow: 0 6px 24px rgba(0,0,0,0.1); z-index: 50;
502
+ }
503
+ .dropdown.open .dropdown-menu { display: block; }
504
+ .dropdown-item {
505
+ display: flex; align-items: center; gap: 8px;
506
+ padding: 8px 12px; border-radius: var(--radius-sm);
507
+ font-size: var(--font-size-base); color: hsl(var(--gray-primary));
508
+ cursor: pointer; transition: background var(--duration-fast);
509
+ }
510
+ .dropdown-item:hover { background: hsl(var(--gray-muted)); }
511
+ .dropdown-item.danger { color: hsl(var(--destructive)); }
512
+ .dropdown-item.danger:hover { background: hsl(var(--destructive-bg)); }
513
+
514
+ /* ===== Responsive ===== */
515
+ @media (max-width: 1199px) {
516
+ .description-list { grid-template-columns: repeat(2, 1fr); }
517
+ .info-card-summary { grid-template-columns: repeat(2, 1fr); }
518
+ }
519
+ @media (max-width: 768px) {
520
+ .description-list { grid-template-columns: 1fr; }
521
+ .info-card-summary { grid-template-columns: 1fr; }
522
+ }
523
+ </style>
524
+ </head>
525
+ <body>
526
+
527
+ <!-- ===== Sidebar ===== -->
528
+ <aside class="sidebar">
529
+ <div class="sidebar-header">
530
+ <div class="sidebar-logo" id="sidebarLogoArea">
531
+ <img src="./_assets/op-ai-gateway-logo.svg" alt="OP AI Gateway" />
532
+ <img class="collapsed-logo" src="./_assets/op-logo-collapsed.png" alt="OP" />
533
+ <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>
534
+ </div>
535
+ <button class="sidebar-collapse-btn" title="收起侧边栏">
536
+ <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>
537
+ </button>
538
+ </div>
539
+
540
+ <!-- sidebar:按 PRD 导航结构,L1 为一级菜单,L2 为二级子菜单。 -->
541
+ <div class="sidebar-content">
542
+ <ul class="sidebar-menu">
543
+ <!-- L1: AI 网关(叶子菜单,当前活跃) -->
544
+ <li><a class="sidebar-menu-item active" href="#">
545
+ <span class="item-icon">
546
+ <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>
547
+ </span>
548
+ AI 网关
549
+ </a></li>
550
+
551
+ <!-- L1: API 网关(父菜单) -->
552
+ <li>
553
+ <a class="sidebar-menu-item expanded" href="#" data-toggle="api-gateway">
554
+ <span class="item-icon">
555
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 6h16M4 12h16M4 18h16"/></svg>
556
+ </span>
557
+ API 网关
558
+ <span class="expand-icon">
559
+ <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>
560
+ </span>
561
+ </a>
562
+ <ul class="sidebar-sub-menu show" id="api-gateway">
563
+ <li><a class="sidebar-menu-item" href="#">实例管理</a></li>
564
+ <li><a class="sidebar-menu-item" href="#">共享实例管理</a></li>
565
+ </ul>
566
+ <div class="sidebar-flyout">
567
+ <a class="sidebar-menu-item" href="#">实例管理</a>
568
+ <a class="sidebar-menu-item" href="#">共享实例管理</a>
569
+ </div>
570
+ </li>
571
+
572
+ <!-- L1: 云原生网关(父菜单) -->
573
+ <li>
574
+ <a class="sidebar-menu-item" href="#" data-toggle="cloud-native-gw">
575
+ <span class="item-icon">
576
+ <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>
577
+ </span>
578
+ 云原生网关
579
+ <span class="expand-icon">
580
+ <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>
581
+ </span>
582
+ </a>
583
+ <ul class="sidebar-sub-menu" id="cloud-native-gw">
584
+ <li><a class="sidebar-menu-item" href="#">实例列表</a></li>
585
+ <li><a class="sidebar-menu-item" href="#">Nginx Ingress 迁移</a></li>
586
+ </ul>
587
+ <div class="sidebar-flyout">
588
+ <a class="sidebar-menu-item" href="#">实例列表</a>
589
+ <a class="sidebar-menu-item" href="#">Nginx Ingress 迁移</a>
590
+ </div>
591
+ </li>
592
+
593
+ <!-- L1: 集群管理(叶子菜单) -->
594
+ <li><a class="sidebar-menu-item" href="#">
595
+ <span class="item-icon">
596
+ <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>
597
+ </span>
598
+ 集群管理
599
+ </a></li>
600
+
601
+ <!-- L1: 级联管理(父菜单) -->
602
+ <li>
603
+ <a class="sidebar-menu-item" href="#" data-toggle="cascade-mgmt">
604
+ <span class="item-icon">
605
+ <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>
606
+ </span>
607
+ 级联管理
608
+ <span class="expand-icon">
609
+ <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>
610
+ </span>
611
+ </a>
612
+ <ul class="sidebar-sub-menu" id="cascade-mgmt">
613
+ <li><a class="sidebar-menu-item" href="#">级联网关</a></li>
614
+ <li><a class="sidebar-menu-item" href="#">级联链路</a></li>
615
+ </ul>
616
+ <div class="sidebar-flyout">
617
+ <a class="sidebar-menu-item" href="#">级联网关</a>
618
+ <a class="sidebar-menu-item" href="#">级联链路</a>
619
+ </div>
620
+ </li>
621
+
622
+ <!-- L1: 容灾管理(父菜单) -->
623
+ <li>
624
+ <a class="sidebar-menu-item" href="#" data-toggle="disaster-mgmt">
625
+ <span class="item-icon">
626
+ <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>
627
+ </span>
628
+ 容灾管理
629
+ <span class="expand-icon">
630
+ <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>
631
+ </span>
632
+ </a>
633
+ <ul class="sidebar-sub-menu" id="disaster-mgmt">
634
+ <li><a class="sidebar-menu-item" href="#">容灾网关实例</a></li>
635
+ </ul>
636
+ <div class="sidebar-flyout">
637
+ <a class="sidebar-menu-item" href="#">容灾网关实例</a>
638
+ </div>
639
+ </li>
640
+
641
+ <!-- L1: 认证授权(父菜单) -->
642
+ <li>
643
+ <a class="sidebar-menu-item" href="#" data-toggle="auth-mgmt">
644
+ <span class="item-icon">
645
+ <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>
646
+ </span>
647
+ 认证授权
648
+ <span class="expand-icon">
649
+ <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>
650
+ </span>
651
+ </a>
652
+ <ul class="sidebar-sub-menu" id="auth-mgmt">
653
+ <li><a class="sidebar-menu-item" href="#">用户管理</a></li>
654
+ <li><a class="sidebar-menu-item" href="#">角色管理</a></li>
655
+ <li><a class="sidebar-menu-item" href="#">权限插件</a></li>
656
+ <li><a class="sidebar-menu-item" href="#">访问凭证</a></li>
657
+ </ul>
658
+ <div class="sidebar-flyout">
659
+ <a class="sidebar-menu-item" href="#">用户管理</a>
660
+ <a class="sidebar-menu-item" href="#">角色管理</a>
661
+ <a class="sidebar-menu-item" href="#">权限插件</a>
662
+ <a class="sidebar-menu-item" href="#">访问凭证</a>
663
+ </div>
664
+ </li>
665
+ </ul>
666
+ </div>
667
+
668
+ <div class="sidebar-divider"></div>
669
+ <div class="sidebar-footer">
670
+ <div class="sidebar-avatar">A</div>
671
+ <span class="sidebar-username">admin</span>
672
+ <button class="sidebar-more">
673
+ <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>
674
+ </button>
675
+ </div>
676
+ </aside>
677
+
678
+ <!-- ===== Main Content ===== -->
679
+ <main class="main-content">
680
+ <div class="page-container">
681
+ <div class="card">
682
+
683
+ <!-- PageHeader — 仅面包屑模式,禁止标题组件 -->
684
+ <div class="page-header">
685
+ <div class="page-header-left">
686
+ <nav class="breadcrumb">
687
+ <a href="#">实例管理</a>
688
+ <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>
689
+ <a href="#">实例列表</a>
690
+ <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>
691
+ <span class="current">gateway-prod-01</span>
692
+ </nav>
693
+ </div>
694
+ <div class="page-header-right">
695
+ <button class="btn btn-primary">
696
+ <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>
697
+ 编辑
698
+ </button>
699
+ <button class="btn btn-outline">续费</button>
700
+ <div class="dropdown" id="moreDropdown">
701
+ <button class="btn btn-outline btn-icon" onclick="toggleDropdown()">
702
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="1"/><circle cx="12" cy="5" r="1"/><circle cx="12" cy="19" r="1"/></svg>
703
+ </button>
704
+ <div class="dropdown-menu">
705
+ <div class="dropdown-item">创建镜像</div>
706
+ <div class="dropdown-item">降配</div>
707
+ <div class="dropdown-item danger">释放实例</div>
708
+ </div>
709
+ </div>
710
+ <button class="btn btn-ghost btn-icon" title="返回列表">
711
+ <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>
712
+ </button>
713
+ </div>
714
+ </div>
715
+
716
+ <!-- InfoCard — 顶部摘要 -->
717
+ <div class="info-card">
718
+ <div class="info-card-header">
719
+ <div class="info-card-icon">
720
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21h8M12 17v4"/></svg>
721
+ </div>
722
+ <div class="info-card-meta">
723
+ <div class="info-card-name">gateway-prod-01</div>
724
+ <div class="info-card-desc">AI 网关生产环境主实例 · 华东2(上海)</div>
725
+ </div>
726
+ <span class="badge badge-success"><span class="badge-dot"></span>运行中</span>
727
+ </div>
728
+ <div class="info-card-summary">
729
+ <div class="info-card-item">
730
+ <div class="info-card-item-label">所属组织</div>
731
+ <div class="info-card-item-value">平台技术部</div>
732
+ </div>
733
+ <div class="info-card-item">
734
+ <div class="info-card-item-label">资源集</div>
735
+ <div class="info-card-item-value">prod-resource-group</div>
736
+ </div>
737
+ <div class="info-card-item">
738
+ <div class="info-card-item-label">创建人</div>
739
+ <div class="info-card-item-value">张三</div>
740
+ </div>
741
+ <div class="info-card-item">
742
+ <div class="info-card-item-label">创建时间</div>
743
+ <div class="info-card-item-value">2026-03-15 10:30</div>
744
+ </div>
745
+ </div>
746
+ </div>
747
+
748
+ <!-- Tabs -->
749
+ <div class="tabs">
750
+ <ul class="tabs-list">
751
+ <li class="tab-item active" onclick="switchTab(0)">实例详情</li>
752
+ <li class="tab-item" onclick="switchTab(1)">监控</li>
753
+ <li class="tab-item" onclick="switchTab(2)">关联资源</li>
754
+ <li class="tab-item" onclick="switchTab(3)">操作日志</li>
755
+ </ul>
756
+ </div>
757
+
758
+ <!-- Tab Content: 实例详情 -->
759
+ <div class="tab-content" id="tab-0">
760
+
761
+ <!-- ListSection: 基本信息 -->
762
+ <div class="list-section">
763
+ <div class="list-section-title">基本信息</div>
764
+ <div class="description-list">
765
+ <div class="description-item">
766
+ <span class="description-label">实例 ID</span>
767
+ <span class="description-value copyable tooltip-trigger">
768
+ gw-2ze4a9f8k3x7b1c0
769
+ <svg class="copy-icon" width="16" height="16" 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>
770
+ <span class="tooltip-content">点击复制实例 ID</span>
771
+ </span>
772
+ </div>
773
+ <div class="description-item">
774
+ <span class="description-label">实例名称</span>
775
+ <span class="description-value">gateway-prod-01</span>
776
+ </div>
777
+ <div class="description-item">
778
+ <span class="description-label">状态</span>
779
+ <span class="description-value"><span class="badge badge-success"><span class="badge-dot"></span>运行中</span></span>
780
+ </div>
781
+ <div class="description-item">
782
+ <span class="description-label">地域</span>
783
+ <span class="description-value">华东2(上海)</span>
784
+ </div>
785
+ <div class="description-item">
786
+ <span class="description-label">可用区</span>
787
+ <span class="description-value">可用区 G</span>
788
+ </div>
789
+ <div class="description-item">
790
+ <span class="description-label">实例规格</span>
791
+ <span class="description-value">gateway.s3.large</span>
792
+ </div>
793
+ <div class="description-item">
794
+ <span class="description-label">架构</span>
795
+ <span class="description-value">X86</span>
796
+ </div>
797
+ <div class="description-item">
798
+ <span class="description-label">计费方式</span>
799
+ <span class="description-value">包年包月</span>
800
+ </div>
801
+ <div class="description-item">
802
+ <span class="description-label">到期时间</span>
803
+ <span class="description-value"><span class="badge badge-warning"><span class="badge-dot"></span>2026-06-15(剩余 24 天)</span></span>
804
+ </div>
805
+ </div>
806
+ </div>
807
+
808
+ <!-- ListSection: 配置信息 -->
809
+ <div class="list-section">
810
+ <div class="list-section-title">配置信息</div>
811
+ <div class="description-list">
812
+ <div class="description-item">
813
+ <span class="description-label">vCPU</span>
814
+ <span class="description-value">8 核</span>
815
+ </div>
816
+ <div class="description-item">
817
+ <span class="description-label">内存</span>
818
+ <span class="description-value">16 GiB</span>
819
+ </div>
820
+ <div class="description-item">
821
+ <span class="description-label">最大 QPS</span>
822
+ <span class="description-value">10,000</span>
823
+ </div>
824
+ <div class="description-item">
825
+ <span class="description-label">最大连接数</span>
826
+ <span class="description-value">50,000</span>
827
+ </div>
828
+ <div class="description-item">
829
+ <span class="description-label">模型路由数</span>
830
+ <span class="description-value">128</span>
831
+ </div>
832
+ <div class="description-item">
833
+ <span class="description-label">流量限速</span>
834
+ <span class="description-value">1,000 req/s</span>
835
+ </div>
836
+ </div>
837
+ </div>
838
+
839
+ <!-- ListSection: 网络信息 -->
840
+ <div class="list-section">
841
+ <div class="list-section-title">网络信息</div>
842
+ <div class="description-list">
843
+ <div class="description-item">
844
+ <span class="description-label">VPC</span>
845
+ <span class="description-value link">vpc-2ze9f7k3x8b1a0c4</span>
846
+ </div>
847
+ <div class="description-item">
848
+ <span class="description-label">交换机</span>
849
+ <span class="description-value link">vsw-2ze4b8k1x9c0a7f3</span>
850
+ </div>
851
+ <div class="description-item">
852
+ <span class="description-label">私有 IP</span>
853
+ <span class="description-value copyable">
854
+ 172.16.0.100
855
+ <svg class="copy-icon" width="16" height="16" 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>
856
+ </span>
857
+ </div>
858
+ <div class="description-item">
859
+ <span class="description-label">公网 IP</span>
860
+ <span class="description-value copyable">
861
+ 47.100.23.156
862
+ <svg class="copy-icon" width="16" height="16" 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>
863
+ </span>
864
+ </div>
865
+ <div class="description-item">
866
+ <span class="description-label">安全组</span>
867
+ <span class="description-value link">sg-2ze5c9k4x0d2b8f1</span>
868
+ </div>
869
+ <div class="description-item">
870
+ <span class="description-label">域名</span>
871
+ <span class="description-value copyable tooltip-trigger">
872
+ gw-prod-01.ai-gateway.cn-shanghai...
873
+ <svg class="copy-icon" width="16" height="16" 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>
874
+ <span class="tooltip-content">gw-prod-01.ai-gateway.cn-shanghai.aliyuncs.com</span>
875
+ </span>
876
+ </div>
877
+ </div>
878
+ </div>
879
+
880
+ </div><!-- /tab-content -->
881
+
882
+ </div><!-- /card -->
883
+ </div><!-- /page-container -->
884
+ </main>
885
+
886
+ <script>
887
+ // Sidebar collapse toggle
888
+ const sidebar = document.querySelector('.sidebar');
889
+ document.querySelector('.sidebar-collapse-btn').addEventListener('click', function() {
890
+ sidebar.classList.toggle('collapsed');
891
+ });
892
+ // Sidebar expand via logo click (collapsed state)
893
+ document.getElementById('sidebarLogoArea').addEventListener('click', function() {
894
+ if (sidebar.classList.contains('collapsed')) {
895
+ sidebar.classList.remove('collapsed');
896
+ }
897
+ });
898
+
899
+ // Sidebar sub-menu toggle
900
+ document.querySelectorAll('.sidebar-menu-item[data-toggle]').forEach(item => {
901
+ item.addEventListener('click', function(e) {
902
+ e.preventDefault();
903
+ this.classList.toggle('expanded');
904
+ const targetId = this.getAttribute('data-toggle');
905
+ const target = document.getElementById(targetId);
906
+ if (target) target.classList.toggle('show');
907
+ });
908
+ });
909
+
910
+ function toggleDropdown() {
911
+ document.getElementById('moreDropdown').classList.toggle('open');
912
+ }
913
+
914
+ // Close dropdown on click outside
915
+ document.addEventListener('click', (e) => {
916
+ if (!e.target.closest('#moreDropdown')) {
917
+ document.getElementById('moreDropdown').classList.remove('open');
918
+ }
919
+ });
920
+
921
+ function switchTab(index) {
922
+ document.querySelectorAll('.tab-item').forEach((t, i) => {
923
+ t.classList.toggle('active', i === index);
924
+ });
925
+ // Simple demo: only tab-0 has content
926
+ document.querySelectorAll('.tab-content').forEach(c => c.style.display = 'none');
927
+ const target = document.getElementById('tab-' + index);
928
+ if (target) target.style.display = 'block';
929
+ }
930
+ </script>
931
+
932
+ </body>
933
+ </html>