@teamix-evo/skills 0.5.0 → 0.7.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 (75) hide show
  1. package/manifest.json +23 -37
  2. package/package.json +2 -2
  3. package/src/teamix-evo-design-opentrek/SKILL.md +210 -42
  4. package/src/teamix-evo-design-opentrek/boundaries.md +3 -3
  5. package/src/teamix-evo-design-opentrek/components.md +41 -40
  6. package/src/teamix-evo-design-opentrek/examples/detail-ai-gateway-1.html +1069 -0
  7. package/src/teamix-evo-design-opentrek/examples/detail-ai-gateway-instance.html +941 -0
  8. package/src/teamix-evo-design-opentrek/examples/detail-page-api-doc.html +906 -0
  9. package/src/teamix-evo-design-opentrek/examples/detail-page-config.html +993 -0
  10. package/src/teamix-evo-design-opentrek/examples/detail-page-monitor.html +1339 -0
  11. package/src/teamix-evo-design-opentrek/examples/detail-page.html +933 -0
  12. package/src/teamix-evo-design-opentrek/examples/settings-page.html +1119 -0
  13. package/src/teamix-evo-design-opentrek/examples/standard-card-list.html +1094 -0
  14. package/src/teamix-evo-design-opentrek/examples/standard-table-list.html +1361 -0
  15. package/src/teamix-evo-design-opentrek/examples/wizard-form-page.html +877 -0
  16. package/src/teamix-evo-design-opentrek/flows.md +85 -12
  17. package/src/teamix-evo-design-opentrek/foundations.md +9 -9
  18. package/src/teamix-evo-design-opentrek/generation-flow.md +15 -3
  19. package/src/teamix-evo-design-opentrek/pages/detail-page/SKILL.md +260 -0
  20. package/src/teamix-evo-design-opentrek/pages/detail-page/patterns/api-doc-detail.md +163 -0
  21. package/src/teamix-evo-design-opentrek/pages/detail-page/patterns/comparison-detail.md +100 -0
  22. package/src/teamix-evo-design-opentrek/pages/detail-page/patterns/monitor-detail.md +190 -0
  23. package/src/teamix-evo-design-opentrek/pages/detail-page/patterns/resource-detail.md +148 -0
  24. package/src/teamix-evo-design-opentrek/pages/form-page/SKILL.md +362 -0
  25. package/src/teamix-evo-design-opentrek/pages/list-page/SKILL.md +286 -0
  26. package/src/teamix-evo-design-opentrek/pages/list-page/_shared/action-column-spec.md +60 -0
  27. package/src/teamix-evo-design-opentrek/pages/list-page/_shared/column-meta-rules.md +117 -0
  28. package/src/teamix-evo-design-opentrek/pages/list-page/_shared/search-combo-spec.md +194 -0
  29. package/src/teamix-evo-design-opentrek/pages/list-page/_shared/state-action-pattern.md +51 -0
  30. package/src/teamix-evo-design-opentrek/pages/list-page/patterns/advanced-filter-list.md +94 -0
  31. package/src/teamix-evo-design-opentrek/pages/list-page/patterns/card-list.md +558 -0
  32. package/src/teamix-evo-design-opentrek/pages/list-page/patterns/drawer-list.md +76 -0
  33. package/src/teamix-evo-design-opentrek/pages/list-page/patterns/expandable-list.md +70 -0
  34. package/src/teamix-evo-design-opentrek/pages/list-page/patterns/l2-sidebar-list.md +73 -0
  35. package/src/teamix-evo-design-opentrek/pages/list-page/patterns/standard-list.md +198 -0
  36. package/src/teamix-evo-design-opentrek/patterns/color-mapping.md +1 -1
  37. package/src/teamix-evo-design-opentrek/patterns/detail-page.md +217 -152
  38. package/src/teamix-evo-design-opentrek/patterns/form-page.md +437 -231
  39. package/src/teamix-evo-design-opentrek/patterns/list-page.md +220 -292
  40. package/src/teamix-evo-design-opentrek/patterns/page-types.md +40 -130
  41. package/src/teamix-evo-design-opentrek/rules/_assets/OP_AGENT RUNTIME.svg +1 -0
  42. package/src/teamix-evo-design-opentrek/rules/_assets/OP_AI GATEWAY.svg +1 -0
  43. package/src/teamix-evo-design-opentrek/rules/_assets/OP_AI STUDIO.svg +1 -0
  44. package/src/teamix-evo-design-opentrek/rules/_assets/OP_DEV-2.svg +1 -0
  45. package/src/teamix-evo-design-opentrek/rules/_assets/OP_LOGO.svg +1 -0
  46. package/src/teamix-evo-design-opentrek/rules/_assets/OP_OPS.svg +1 -0
  47. package/src/teamix-evo-design-opentrek/rules/boundaries.rules.json +3 -3
  48. package/src/teamix-evo-design-opentrek/rules/business-mapping.json +124 -0
  49. package/src/teamix-evo-design-opentrek/rules/common-components.json +924 -0
  50. package/src/teamix-evo-design-opentrek/rules/component-specs.json +1083 -0
  51. package/src/teamix-evo-design-opentrek/rules/design-tokens.css +433 -0
  52. package/src/teamix-evo-design-opentrek/rules/design-tokens.json +2798 -0
  53. package/src/teamix-evo-design-opentrek/rules/layout-rules.json +218 -0
  54. package/src/teamix-evo-design-opentrek/rules/page-flow.json +351 -0
  55. package/src/teamix-evo-design-opentrek/rules/page-frame.json +241 -0
  56. package/src/teamix-evo-design-opentrek/rules/page-header-spec.md +123 -0
  57. package/src/teamix-evo-design-opentrek/rules/page-types.json +206 -0
  58. package/src/teamix-evo-design-opentrek/rules/sidebar-spec.md +217 -0
  59. package/src/teamix-evo-design-opentrek/rules/styling.json +188 -0
  60. package/src/teamix-evo-design-opentrek/rules/token-mapping.md +284 -0
  61. package/src/teamix-evo-design-uni-manager/SKILL.md +1 -1
  62. package/src/teamix-evo-design-uni-manager/boundaries.md +3 -3
  63. package/src/teamix-evo-design-uni-manager/brand.md +1 -1
  64. package/src/teamix-evo-design-uni-manager/components.md +30 -28
  65. package/src/teamix-evo-design-uni-manager/foundations.md +21 -21
  66. package/src/teamix-evo-design-uni-manager/generation-flow.md +3 -1
  67. package/src/teamix-evo-design-uni-manager/patterns/detail-page.md +1 -1
  68. package/src/teamix-evo-design-uni-manager/patterns/form-page.md +18 -18
  69. package/src/teamix-evo-design-uni-manager/patterns/list-page.md +29 -29
  70. package/src/teamix-evo-design-uni-manager/patterns/page-types.md +11 -11
  71. package/src/teamix-evo-design-uni-manager/philosophy.md +1 -1
  72. package/src/teamix-evo-design-uni-manager/rules/boundaries.rules.json +3 -3
  73. package/src/teamix-evo-manage/SKILL.md +288 -121
  74. package/src/teamix-evo-upgrade/SKILL.md +298 -0
  75. package/src/teamix-evo-design-opentrek/patterns/sidebar.md +0 -122
@@ -0,0 +1,1119 @@
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=1400">
6
+ <title>配置表单页 · 标准参考范例 — v7.8.4</title>
7
+ <!--
8
+ ★ 配置表单页标准参考范例(Standard Settings Form Reference)
9
+ ─────────────────────────────────────────────────────────────
10
+ 用途:AI 生成配置/创建表单页时的基础参考,展示分组表单骨架与组件组合
11
+ ─────────────────────────────────────────────────────────────
12
+ 布局:TWO_COL(Sidebar + ContentCard 单例容器)
13
+ Sidebar:完整 L1 框架(折叠/展开 240px↔68px / flyout / sub-menu)
14
+ 内容区模式:D-FORM(settings-form 分组表单)
15
+ ─────────────────────────────────────────────────────────────
16
+ 组件清单:
17
+ • Breadcrumb — 2级面包屑(L2 模式,禁止标题组件)
18
+ • Settings Section — 分组表单(title + description + form-rows)
19
+ • Form Controls — Input / Select / Stepper / Switch
20
+ • Settings Footer — 固定底栏(取消 + 提交)
21
+ ─────────────────────────────────────────────────────────────
22
+ 规范来源:pages/form-page/SKILL.md
23
+ Tokens 版本:v7.8.4
24
+ -->
25
+ <style>
26
+ /* ===== Reset & v7 Design Tokens ===== */
27
+ *, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
28
+ :root {
29
+ /* Primary */
30
+ --primary: 218.6 100% 46.7%;
31
+ --primary-foreground: 0 0% 100%;
32
+ --primary-hover: 218.6 100% 42%;
33
+
34
+ /* Gray (v7.4) */
35
+ --gray-primary: 220 9% 7%;
36
+ --gray-primary-foreground: 210 33% 99%;
37
+ --gray-secondary-foreground: 216 4% 26%;
38
+ --muted-foreground: 216 2% 45%;
39
+ --gray-disabled: 210 3% 63%;
40
+ --gray-line: 210 9% 91%;
41
+ --gray-sidebar-accent: 210 12% 93%;
42
+ --gray-muted: 220 18% 97%;
43
+ --gray-white: 0 0% 100%;
44
+ /* Legacy 别名(v7.4 向后兼容) */
45
+ --gray-title: 220 9% 7%;
46
+ --gray-secondary: 216 4% 26%;
47
+ --gray-tertiary: 216 2% 45%;
48
+ --gray-border: 210 9% 91%;
49
+ --gray-fill: 220 18% 97%;
50
+ --gray-bg: 220 18% 97%;
51
+
52
+ /* Feedback */
53
+ --success: 142 76% 36%;
54
+ --success-bg: 145 65% 95%;
55
+ --success-border: 142 72% 73%;
56
+ --warning: 40 88% 48%;
57
+ --warning-bg: 40 95% 93%;
58
+ --warning-border: 44 92% 70%;
59
+ --destructive: 0 72% 51%;
60
+ --destructive-bg: 0 93% 96%;
61
+ --destructive-border: 0 91% 82%;
62
+ --info: 217 91% 60%;
63
+ --info-bg: 214 85% 95%;
64
+ --info-border: 214 89% 82%;
65
+
66
+ /* Semantic */
67
+ --background: 220 18% 97%;
68
+ --card: 0 0% 100%;
69
+ --ring: 218.6 100% 46.7%;
70
+ --sidebar: 220 18% 97%;
71
+ --sidebar-foreground: 220 9% 7%;
72
+ --sidebar-active: 210 12% 93%;
73
+ --sidebar-active-foreground: 220 9% 7%;
74
+ --sidebar-hover: 220 18% 97%;
75
+ --sidebar-group: 216 2% 45%;
76
+ --sidebar-item: 220 9% 7%;
77
+ --sidebar-item-muted: 216 4% 26%;
78
+ --sidebar-border: 210 9% 91%;
79
+
80
+ /* Radius */
81
+ --radius-sm: 4px;
82
+ --radius-md: 8px;
83
+ --radius: 12px;
84
+ --radius-lg: 16px;
85
+
86
+ /* Spacing */
87
+ --gap-xs: 4px;
88
+ --gap-sm: 8px;
89
+ --gap-md: 12px;
90
+ --gap-lg: 16px;
91
+ --gap-xl: 20px;
92
+ --gap-2xl: 24px;
93
+ --btn-padding-x: 16px;
94
+ --btn-padding-x-sm: 12px;
95
+ --button-gap: 8px;
96
+ --tabs-gap: 24px;
97
+
98
+ /* Typography */
99
+ --font-size-xs: 12px;
100
+ --font-size-base: 12px;
101
+ --font-size-sm: 13px;
102
+ --font-size-lg: 14px;
103
+ --font-size-xl: 16px;
104
+ --font-size-2xl: 18px;
105
+ --font-size-page-header: 18px;
106
+ --font-sans: 'PingFang SC', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;
107
+ --font-mono: 'SF Mono', Monaco, 'Courier New', monospace;
108
+ --font-weight-normal: 400;
109
+ --font-weight-medium: 500;
110
+ --font-weight-semibold: 600;
111
+ --font-weight-black: 900;
112
+
113
+ /* Layout(分层模型 v7.5)*/
114
+ --layout-sidebar-width: 240px;
115
+ --sidebar-collapsed-width: 68px;
116
+ --page-container-padding: 16px; /* 层级 1:PageContainer 外层间距(v7.5 由 20→16) */
117
+ --page-container-padding-left: 0px; /* sidebar 与内容区之间无间距 */
118
+ --card-padding-x: 20px; /* 层级 2:白卡容器内部左右内边距(v7.5 由 24→20;独立于 page-container-padding) */
119
+ --shadow-sm: 0 1px 2px rgba(0,0,0,0.05); /* v7.6 ContentCard 唯一阴影源(无边框方案) */
120
+ --card-gap: 16px;
121
+
122
+ /* Transitions */
123
+ --duration-fast: 150ms;
124
+ --duration-normal: 200ms;
125
+ --easing-ease: ease;
126
+ }
127
+
128
+ body {
129
+ font-family: var(--font-sans);
130
+ font-size: var(--font-size-lg);
131
+ color: hsl(var(--gray-primary));
132
+ background: hsl(var(--background));
133
+ line-height: 1.5;
134
+ }
135
+
136
+ /* ===== Sidebar (v7 fixed positioning, twoLevel variant) ===== */
137
+ .sidebar {
138
+ position: fixed;
139
+ top: 0; left: 0; bottom: 0;
140
+ width: var(--layout-sidebar-width);
141
+ background: hsl(var(--sidebar));
142
+ z-index: 100;
143
+ display: flex;
144
+ flex-direction: column;
145
+ overflow: hidden;
146
+ transition: width 0.2s ease;
147
+ }
148
+
149
+ /* Sidebar Header */
150
+ .sidebar-header {
151
+ height: 56px; padding: 0 16px;
152
+ display: flex; align-items: center; gap: var(--gap-xs);
153
+ flex-shrink: 0;
154
+ }
155
+ .sidebar-logo {
156
+ height: 28px; flex-shrink: 0;
157
+ display: flex; align-items: center;
158
+ overflow: hidden;
159
+ }
160
+ .sidebar-logo img {
161
+ height: 28px; width: auto; display: block;
162
+ }
163
+ .sidebar-logo .collapsed-logo {
164
+ display: none; width: 30px; height: 30px;
165
+ }
166
+ .sidebar-logo .expand-logo {
167
+ display: none; width: 18px; height: 18px;
168
+ color: hsl(var(--muted-foreground));
169
+ }
170
+ .sidebar-collapse-btn {
171
+ margin-left: auto; width: 18px; height: 18px;
172
+ background: none; border: none; padding: 0; cursor: pointer;
173
+ display: flex; align-items: center; justify-content: center;
174
+ color: hsl(var(--muted-foreground)); flex-shrink: 0;
175
+ }
176
+ .sidebar-collapse-btn svg { width: 18px; height: 18px; }
177
+
178
+ /* Sidebar Content */
179
+ .sidebar-content {
180
+ flex: 1;
181
+ flex-shrink: 0;
182
+ overflow-y: auto;
183
+ padding: 12px 0;
184
+ }
185
+ .sidebar-menu {
186
+ list-style: none;
187
+ padding: 0 8px;
188
+ display: flex;
189
+ flex-direction: column;
190
+ gap: 2px;
191
+ }
192
+ .sidebar-menu-item {
193
+ display: flex;
194
+ align-items: center;
195
+ gap: var(--button-gap);
196
+ padding: 0 12px;
197
+ height: 40px;
198
+ border-radius: var(--radius-md);
199
+ font-size: var(--font-size-lg);
200
+ font-weight: var(--font-weight-medium);
201
+ color: hsl(var(--sidebar-item-muted));
202
+ text-decoration: none;
203
+ cursor: pointer;
204
+ transition: background var(--duration-fast), color var(--duration-fast);
205
+ white-space: nowrap;
206
+ }
207
+ .sidebar-menu-item:hover {
208
+ background: hsl(var(--sidebar-hover));
209
+ color: hsl(var(--sidebar-item));
210
+ }
211
+ .sidebar-menu-item.active {
212
+ background: hsl(var(--sidebar-active));
213
+ color: hsl(var(--sidebar-active-foreground));
214
+ }
215
+
216
+ /* 展开箭头 */
217
+ .sidebar-menu-item .expand-icon {
218
+ margin-left: auto;
219
+ width: 16px;
220
+ height: 16px;
221
+ transition: transform var(--duration-fast);
222
+ }
223
+ .sidebar-menu-item.expanded .expand-icon {
224
+ transform: rotate(90deg);
225
+ }
226
+
227
+ /* 子菜单容器 - twoLevel变体对齐规则 */
228
+ .sidebar-sub-menu {
229
+ list-style: none;
230
+ padding: 0 0 0 24px;
231
+ display: none;
232
+ }
233
+ .sidebar-menu > li > .sidebar-sub-menu {
234
+ padding-left: 0;
235
+ }
236
+ .sidebar-sub-menu.show {
237
+ display: block;
238
+ }
239
+
240
+ /* 子菜单项:36px = padding(12) + icon(16) + gap(8) */
241
+ .sidebar-sub-menu .sidebar-menu-item {
242
+ padding-left: 36px;
243
+ height: 36px;
244
+ font-size: var(--font-size-base);
245
+ font-weight: var(--font-weight-normal);
246
+ }
247
+
248
+ /* 图标 */
249
+ .item-icon {
250
+ width: 16px;
251
+ height: 16px;
252
+ display: flex;
253
+ align-items: center;
254
+ justify-content: center;
255
+ flex-shrink: 0;
256
+ }
257
+ .item-icon svg {
258
+ width: 16px;
259
+ height: 16px;
260
+ }
261
+
262
+ /* ===== Sidebar Collapsed State ===== */
263
+ .sidebar.collapsed { width: 68px; overflow: visible; }
264
+ .sidebar.collapsed .sidebar-header { padding: 0 12px; justify-content: center; }
265
+ .sidebar.collapsed .sidebar-logo { cursor: pointer; }
266
+ .sidebar.collapsed .sidebar-logo img { display: none; }
267
+ .sidebar.collapsed .sidebar-logo .collapsed-logo { display: block; }
268
+ .sidebar.collapsed .sidebar-logo:hover .collapsed-logo { display: none; }
269
+ .sidebar.collapsed .sidebar-logo:hover .expand-logo { display: block; }
270
+ .sidebar.collapsed .sidebar-collapse-btn { display: none; }
271
+ .sidebar.collapsed .sidebar-content { padding: 12px 0; overflow-y: auto; overflow-x: hidden; }
272
+ .sidebar.collapsed .sidebar-menu { padding: 0; }
273
+ .sidebar.collapsed .sidebar-menu > li { display: flex; justify-content: center; }
274
+ .sidebar.collapsed .sidebar-menu > li > a.sidebar-menu-item {
275
+ justify-content: center; padding: 0; width: 40px; height: 40px;
276
+ border-radius: var(--radius-md); position: relative; flex-shrink: 0;
277
+ gap: 0;
278
+ }
279
+ .sidebar.collapsed .sidebar-menu > li > a.sidebar-menu-item .item-icon { margin: 0; }
280
+ .sidebar.collapsed .sidebar-menu > li > a.sidebar-menu-item > span:not(.item-icon),
281
+ .sidebar.collapsed .sidebar-menu > li > a.sidebar-menu-item > .expand-icon,
282
+ .sidebar.collapsed .sidebar-menu > li > a.sidebar-menu-item:not(.item-icon):after { display: none; }
283
+ /* 隐藏文字节点(直接文本) */
284
+ .sidebar.collapsed .sidebar-menu > li > a { font-size: 0; }
285
+ .sidebar.collapsed .sidebar-menu > li > a > .item-icon { font-size: var(--font-size-lg); }
286
+ .sidebar.collapsed .sidebar-sub-menu { display: none !important; }
287
+ .sidebar.collapsed .sidebar-divider { margin: 0 14px; }
288
+ .sidebar.collapsed .sidebar-footer { padding: 12px 10px 16px; justify-content: center; }
289
+ .sidebar.collapsed .sidebar-username,
290
+ .sidebar.collapsed .sidebar-more { display: none; }
291
+
292
+ /* ===== Sidebar Collapsed Flyout (hover 浮层展示二级菜单) ===== */
293
+ .sidebar.collapsed .sidebar-menu > li { position: relative; }
294
+ .sidebar.collapsed .sidebar-menu > li:hover > .sidebar-flyout {
295
+ display: block;
296
+ }
297
+ .sidebar-flyout {
298
+ display: none;
299
+ position: absolute; left: 100%; top: 0;
300
+ min-width: 160px; padding: 4px;
301
+ background: hsl(var(--card));
302
+ border: 1px solid hsl(var(--gray-line));
303
+ border-radius: var(--radius-md);
304
+ box-shadow: 0 4px 12px rgba(0,0,0,0.08);
305
+ z-index: 200;
306
+ }
307
+ .sidebar-flyout .sidebar-menu-item {
308
+ height: 36px; padding: 0 12px;
309
+ font-size: var(--font-size-base) !important;
310
+ font-weight: var(--font-weight-normal);
311
+ color: hsl(var(--gray-primary));
312
+ border-radius: var(--radius-sm);
313
+ white-space: nowrap;
314
+ }
315
+ .sidebar-flyout .sidebar-menu-item:hover {
316
+ background: hsl(var(--gray-muted));
317
+ }
318
+
319
+ /* Sidebar Separator */
320
+ .sidebar-divider {
321
+ height: 1px;
322
+ background: hsl(var(--sidebar-border));
323
+ margin: 0 12px;
324
+ flex-shrink: 0;
325
+ }
326
+
327
+ /* Sidebar Footer */
328
+ .sidebar-footer {
329
+ flex-shrink: 0;
330
+ display: flex;
331
+ align-items: center;
332
+ gap: 8px;
333
+ padding: 12px 12px 16px 24px;
334
+ }
335
+ .sidebar-avatar {
336
+ width: 28px; height: 28px; border-radius: 50%;
337
+ background: hsl(var(--sidebar-active));
338
+ display: flex; align-items: center; justify-content: center;
339
+ font-size: var(--font-size-base); font-weight: 600;
340
+ color: hsl(var(--gray-primary)); flex-shrink: 0;
341
+ }
342
+ .sidebar-username {
343
+ flex: 1; font-size: var(--font-size-lg); font-weight: var(--font-weight-medium);
344
+ color: hsl(var(--sidebar-item)); overflow: hidden;
345
+ text-overflow: ellipsis; white-space: nowrap;
346
+ }
347
+ .sidebar-more {
348
+ width: 28px; height: 28px; border-radius: var(--radius-sm);
349
+ border: none; background: transparent; cursor: pointer;
350
+ display: flex; align-items: center; justify-content: center;
351
+ color: hsl(var(--muted-foreground));
352
+ }
353
+ .sidebar-more:hover { background: hsl(var(--sidebar-hover)); color: hsl(var(--gray-primary)); }
354
+
355
+ /* ===== PageContainer ===== */
356
+ .page-container {
357
+ margin-left: var(--layout-sidebar-width);
358
+ padding: var(--page-container-padding) var(--page-container-padding) var(--page-container-padding) var(--page-container-padding-left);
359
+ min-height: 100vh;
360
+ transition: margin-left 0.2s ease;
361
+ }
362
+ .sidebar.collapsed ~ .page-container { margin-left: 68px; }
363
+
364
+ /* ===== Breadcrumb ===== */
365
+ .breadcrumb {
366
+ display: flex;
367
+ align-items: center;
368
+ gap: 4px;
369
+ font-size: var(--font-size-2xl);
370
+ font-weight: var(--font-weight-medium);
371
+ color: hsl(var(--gray-secondary-foreground));
372
+ padding: 0;
373
+ height: 64px;
374
+ flex-shrink: 0;
375
+ margin-bottom: 0; /* Breadcrumb 底边直接与 section 顶边贴合 */
376
+ }
377
+ .breadcrumb a {
378
+ color: hsl(var(--gray-secondary-foreground));
379
+ text-decoration: none;
380
+ max-width: 160px;
381
+ overflow: hidden;
382
+ text-overflow: ellipsis;
383
+ white-space: nowrap;
384
+ }
385
+ .breadcrumb a:hover { color: hsl(var(--gray-primary)); }
386
+ .breadcrumb-sep {
387
+ display: flex;
388
+ align-items: center;
389
+ color: hsl(var(--muted-foreground));
390
+ }
391
+ .breadcrumb-sep svg { width: 20px; height: 20px; }
392
+ .breadcrumb-current {
393
+ color: hsl(var(--gray-primary));
394
+ font-weight: var(--font-weight-medium);
395
+ cursor: default;
396
+ }
397
+
398
+ /* ===== PageHeader — L2面包屑模式下禁止标题组件,已移除 ===== */
399
+
400
+ /* ===== ContentWrapper + Card (白卡容器) ===== */
401
+ .content-wrapper {
402
+ /* wraps the card */
403
+ }
404
+ .card {
405
+ background: hsl(var(--card));
406
+ border-radius: var(--radius-lg);
407
+ /* v7.6:去掉 1px border,使用最弱阴影 var(--shadow-sm) */
408
+ box-shadow: var(--shadow-sm, 0 1px 2px rgba(0,0,0,0.05));
409
+ overflow: hidden;
410
+ display: flex;
411
+ flex-direction: column;
412
+ max-height: calc(100vh - 2 * var(--page-container-padding));
413
+ padding-left: var(--card-padding-x);
414
+ padding-right: var(--card-padding-x);
415
+ }
416
+ .card-scrollable {
417
+ overflow-y: auto;
418
+ flex: 1 1 auto;
419
+ min-height: 0;
420
+ }
421
+
422
+ /* ===== Section (分区) ===== */
423
+ .settings-section {
424
+ padding: var(--card-gap) 0;
425
+ }
426
+ .settings-section + .settings-section {
427
+ border-top: 1px solid hsl(var(--gray-line));
428
+ }
429
+ .section-title {
430
+ font-size: var(--font-size-xl);
431
+ font-weight: var(--font-weight-semibold);
432
+ color: hsl(var(--gray-primary));
433
+ margin-bottom: var(--gap-lg);
434
+ }
435
+ .section-desc {
436
+ font-size: var(--font-size-sm);
437
+ color: hsl(var(--gray-secondary-foreground));
438
+ margin-bottom: var(--gap-xl);
439
+ }
440
+
441
+ /* ===== Form Row ===== */
442
+ .form-row {
443
+ display: flex;
444
+ align-items: center;
445
+ gap: var(--gap-2xl);
446
+ padding: 12px 0;
447
+ }
448
+ .form-row + .form-row {
449
+ border-top: none;
450
+ }
451
+ .form-label {
452
+ width: 140px;
453
+ flex-shrink: 0;
454
+ font-size: var(--font-size-lg);
455
+ font-weight: var(--font-weight-medium);
456
+ color: hsl(var(--gray-primary));
457
+ }
458
+ .form-label .required {
459
+ color: hsl(var(--destructive));
460
+ margin-left: 2px;
461
+ }
462
+ .form-control {
463
+ flex: 1;
464
+ min-width: 0;
465
+ max-width: 400px;
466
+ }
467
+
468
+ /* ===== Input ===== */
469
+ .input {
470
+ height: 32px;
471
+ padding: 0 8px;
472
+ border: 1px solid hsl(var(--gray-line));
473
+ border-radius: var(--radius-md);
474
+ font-size: var(--font-size-base);
475
+ color: hsl(var(--gray-primary));
476
+ background: hsl(var(--card));
477
+ outline: none;
478
+ transition: border-color var(--duration-fast), box-shadow var(--duration-fast);
479
+ width: 100%;
480
+ }
481
+ .input:focus {
482
+ border-color: hsl(var(--primary));
483
+ box-shadow: 0 0 0 2px hsl(var(--ring) / 0.2);
484
+ }
485
+ .input::placeholder { color: hsl(var(--muted-foreground)); }
486
+ .input[disabled] {
487
+ background: hsl(var(--gray-muted));
488
+ color: hsl(var(--gray-disabled));
489
+ cursor: not-allowed;
490
+ }
491
+ textarea.input {
492
+ height: auto;
493
+ padding: 8px 12px;
494
+ resize: vertical;
495
+ min-height: 80px;
496
+ }
497
+ /* ===== Custom Select (@teamix-evo/ui C23-Select) ===== */
498
+ .select-wrapper {
499
+ position: relative;
500
+ width: 100%;
501
+ }
502
+ .select-trigger {
503
+ height: 32px;
504
+ padding: 0 8px;
505
+ padding-right: 28px;
506
+ border: 1px solid hsl(var(--gray-line));
507
+ border-radius: var(--radius-md);
508
+ background: hsl(var(--card));
509
+ font-size: var(--font-size-base);
510
+ color: hsl(var(--gray-primary));
511
+ display: flex;
512
+ align-items: center;
513
+ width: 100%;
514
+ cursor: pointer;
515
+ outline: none;
516
+ transition: border-color var(--duration-fast), box-shadow var(--duration-fast);
517
+ position: relative;
518
+ }
519
+ .select-trigger:focus {
520
+ border-color: hsl(var(--primary));
521
+ box-shadow: 0 0 0 2px hsl(var(--ring) / 0.2);
522
+ }
523
+ .select-trigger::after {
524
+ content: '';
525
+ position: absolute;
526
+ right: 7px;
527
+ top: 50%;
528
+ transform: translateY(-50%);
529
+ width: 14px;
530
+ height: 14px;
531
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%231A1A1A' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' opacity='0.8'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
532
+ background-size: contain;
533
+ background-repeat: no-repeat;
534
+ pointer-events: none;
535
+ }
536
+ .select-trigger.placeholder {
537
+ color: hsl(var(--muted-foreground));
538
+ }
539
+ .select-content {
540
+ display: none;
541
+ position: absolute;
542
+ z-index: 50;
543
+ top: calc(100% + 4px);
544
+ left: 0;
545
+ right: 0;
546
+ background: hsl(var(--card));
547
+ border: 1px solid hsl(var(--gray-line));
548
+ border-radius: var(--radius-md);
549
+ box-shadow: 0 6px 24px rgba(0,0,0,0.1);
550
+ padding: 8px;
551
+ min-width: 100%;
552
+ }
553
+ .select-content.show {
554
+ display: block;
555
+ }
556
+ .select-item {
557
+ height: 32px;
558
+ padding: 0 8px;
559
+ border-radius: var(--radius-sm);
560
+ font-size: var(--font-size-base);
561
+ color: hsl(var(--gray-primary));
562
+ display: flex;
563
+ align-items: center;
564
+ cursor: pointer;
565
+ user-select: none;
566
+ }
567
+ .select-item:hover {
568
+ background: hsl(var(--gray-muted));
569
+ }
570
+ .select-item.selected {
571
+ color: hsl(var(--primary));
572
+ font-weight: var(--font-weight-medium);
573
+ }
574
+ .select-item[data-disabled] {
575
+ opacity: 0.45;
576
+ pointer-events: none;
577
+ cursor: not-allowed;
578
+ }
579
+
580
+ /* ===== Switch ===== */
581
+ .switch {
582
+ position: relative;
583
+ width: 28px;
584
+ height: 16px;
585
+ cursor: pointer;
586
+ }
587
+ .switch input { display: none; }
588
+ .switch-track {
589
+ position: absolute;
590
+ inset: 0;
591
+ background: hsl(var(--gray-line));
592
+ border-radius: 8px;
593
+ transition: background var(--duration-fast);
594
+ }
595
+ .switch input:checked + .switch-track {
596
+ background: hsl(var(--success));
597
+ }
598
+ .switch-thumb {
599
+ position: absolute;
600
+ top: 2px; left: 2px;
601
+ width: 12px; height: 12px;
602
+ background: white;
603
+ border-radius: 50%;
604
+ box-shadow: 0 1px 3px rgba(0,0,0,0.15);
605
+ transition: transform var(--duration-fast);
606
+ pointer-events: none;
607
+ }
608
+ .switch input:checked ~ .switch-thumb {
609
+ transform: translateX(12px);
610
+ }
611
+
612
+ /* ===== Buttons ===== */
613
+ .btn {
614
+ display: inline-flex;
615
+ align-items: center;
616
+ justify-content: center;
617
+ height: 36px;
618
+ padding: 0 var(--btn-padding-x);
619
+ border-radius: var(--radius-md);
620
+ font-size: var(--font-size-lg);
621
+ font-weight: var(--font-weight-medium);
622
+ cursor: pointer;
623
+ border: 1px solid transparent;
624
+ transition: all var(--duration-fast);
625
+ white-space: nowrap;
626
+ gap: 6px;
627
+ }
628
+ .btn-primary {
629
+ background: hsl(var(--primary));
630
+ color: hsl(var(--primary-foreground));
631
+ }
632
+ .btn-primary:hover { background: hsl(var(--primary-hover)); }
633
+ .btn-secondary {
634
+ background: hsl(var(--card));
635
+ color: hsl(var(--gray-primary));
636
+ border-color: hsl(var(--gray-line));
637
+ }
638
+ .btn-secondary:hover { background: hsl(var(--gray-muted)); }
639
+ .btn-ghost {
640
+ background: transparent;
641
+ color: hsl(var(--gray-secondary-foreground));
642
+ border: none;
643
+ }
644
+ .btn-ghost:hover { background: hsl(var(--gray-muted)); color: hsl(var(--gray-primary)); }
645
+ .btn-danger {
646
+ background: hsl(var(--destructive));
647
+ color: white;
648
+ }
649
+ .btn-danger:hover { background: hsl(var(--destructive) / 0.9); }
650
+ .btn:disabled {
651
+ opacity: 0.5;
652
+ cursor: not-allowed;
653
+ }
654
+
655
+ /* ===== Action footer (SubmitBar) — justify-content: flex-end,行动点居右 ===== */
656
+ .settings-footer {
657
+ display: flex;
658
+ gap: var(--gap-sm);
659
+ height: 72px;
660
+ align-items: center;
661
+ border-top: 1px solid hsl(var(--gray-line));
662
+ background: hsl(var(--card));
663
+ justify-content: flex-end;
664
+ flex-shrink: 0;
665
+ z-index: 10;
666
+ /* 分割线出血:负外边距抵消 Card.paddingX,使 border-top 延伸到 Card 左右边缘 */
667
+ margin-left: calc(-1 * var(--card-padding-x));
668
+ margin-right: calc(-1 * var(--card-padding-x));
669
+ padding-left: var(--card-padding-x);
670
+ padding-right: var(--card-padding-x);
671
+ }
672
+
673
+ /* ===== Stepper ===== */
674
+ .stepper {
675
+ display: flex;
676
+ align-items: center;
677
+ gap: 0;
678
+ }
679
+ .stepper-btn {
680
+ width: 32px;
681
+ height: 32px;
682
+ border: 1px solid hsl(var(--border, var(--gray-line)));
683
+ background: hsl(var(--card));
684
+ cursor: pointer;
685
+ display: flex;
686
+ align-items: center;
687
+ justify-content: center;
688
+ font-size: 16px;
689
+ color: hsl(var(--gray-primary));
690
+ }
691
+ .stepper-btn:first-child { border-radius: var(--radius-md) 0 0 var(--radius-md); }
692
+ .stepper-btn:last-child { border-radius: 0 var(--radius-md) var(--radius-md) 0; }
693
+ .stepper input {
694
+ width: 60px;
695
+ height: 32px;
696
+ text-align: center;
697
+ border: 1px solid hsl(var(--gray-line));
698
+ border-left: none;
699
+ border-right: none;
700
+ font-size: var(--font-size-lg);
701
+ color: hsl(var(--gray-primary));
702
+ outline: none;
703
+ }
704
+
705
+ /* ===== Optional Tag ===== */
706
+ .optional-tag {
707
+ font-size: 12px;
708
+ color: hsl(var(--gray-secondary-foreground));
709
+ font-weight: normal;
710
+ margin-left: 4px;
711
+ }
712
+
713
+ /* ===== Form Description ===== */
714
+ .form-description {
715
+ font-size: 13px;
716
+ color: hsl(var(--gray-secondary-foreground));
717
+ margin-top: 4px;
718
+ }
719
+ </style>
720
+ </head>
721
+ <body>
722
+
723
+ <!-- ===== Sidebar (v7: fixed, ul>li>a, pill items) ===== -->
724
+ <aside class="sidebar">
725
+ <div class="sidebar-header">
726
+ <div class="sidebar-logo" id="sidebarLogoArea">
727
+ <img src="./_assets/op-ai-gateway-logo.svg" alt="OP AI Gateway" />
728
+ <img class="collapsed-logo" src="./_assets/op-logo-collapsed.png" alt="OP" />
729
+ <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>
730
+ </div>
731
+ <button class="sidebar-collapse-btn" title="收起侧边栏">
732
+ <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>
733
+ </button>
734
+ </div>
735
+
736
+ <!-- sidebar:按 PRD 导航结构,L1 为一级菜单,L2 为二级子菜单。 -->
737
+ <div class="sidebar-content">
738
+ <ul class="sidebar-menu">
739
+ <!-- L1: AI 网关(叶子菜单,当前活跃) -->
740
+ <li><a class="sidebar-menu-item active" href="#">
741
+ <span class="item-icon">
742
+ <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>
743
+ </span>
744
+ AI 网关
745
+ </a></li>
746
+
747
+ <!-- L1: API 网关(父菜单) -->
748
+ <li>
749
+ <a class="sidebar-menu-item expanded" href="#" data-toggle="api-gateway">
750
+ <span class="item-icon">
751
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 6h16M4 12h16M4 18h16"/></svg>
752
+ </span>
753
+ API 网关
754
+ <span class="expand-icon">
755
+ <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>
756
+ </span>
757
+ </a>
758
+ <ul class="sidebar-sub-menu show" id="api-gateway">
759
+ <li><a class="sidebar-menu-item" href="#">实例管理</a></li>
760
+ <li><a class="sidebar-menu-item" href="#">共享实例管理</a></li>
761
+ </ul>
762
+ <div class="sidebar-flyout">
763
+ <a class="sidebar-menu-item" href="#">实例管理</a>
764
+ <a class="sidebar-menu-item" href="#">共享实例管理</a>
765
+ </div>
766
+ </li>
767
+
768
+ <!-- L1: 云原生网关(父菜单) -->
769
+ <li>
770
+ <a class="sidebar-menu-item" href="#" data-toggle="cloud-native-gw">
771
+ <span class="item-icon">
772
+ <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>
773
+ </span>
774
+ 云原生网关
775
+ <span class="expand-icon">
776
+ <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>
777
+ </span>
778
+ </a>
779
+ <ul class="sidebar-sub-menu" id="cloud-native-gw">
780
+ <li><a class="sidebar-menu-item" href="#">实例列表</a></li>
781
+ <li><a class="sidebar-menu-item" href="#">Nginx Ingress 迁移</a></li>
782
+ </ul>
783
+ <div class="sidebar-flyout">
784
+ <a class="sidebar-menu-item" href="#">实例列表</a>
785
+ <a class="sidebar-menu-item" href="#">Nginx Ingress 迁移</a>
786
+ </div>
787
+ </li>
788
+
789
+ <!-- L1: 集群管理(叶子菜单) -->
790
+ <li><a class="sidebar-menu-item" href="#">
791
+ <span class="item-icon">
792
+ <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>
793
+ </span>
794
+ 集群管理
795
+ </a></li>
796
+
797
+ <!-- L1: 级联管理(父菜单) -->
798
+ <li>
799
+ <a class="sidebar-menu-item" href="#" data-toggle="cascade-mgmt">
800
+ <span class="item-icon">
801
+ <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>
802
+ </span>
803
+ 级联管理
804
+ <span class="expand-icon">
805
+ <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>
806
+ </span>
807
+ </a>
808
+ <ul class="sidebar-sub-menu" id="cascade-mgmt">
809
+ <li><a class="sidebar-menu-item" href="#">级联网关</a></li>
810
+ <li><a class="sidebar-menu-item" href="#">级联链路</a></li>
811
+ </ul>
812
+ <div class="sidebar-flyout">
813
+ <a class="sidebar-menu-item" href="#">级联网关</a>
814
+ <a class="sidebar-menu-item" href="#">级联链路</a>
815
+ </div>
816
+ </li>
817
+
818
+ <!-- L1: 容灾管理(父菜单) -->
819
+ <li>
820
+ <a class="sidebar-menu-item" href="#" data-toggle="disaster-mgmt">
821
+ <span class="item-icon">
822
+ <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>
823
+ </span>
824
+ 容灾管理
825
+ <span class="expand-icon">
826
+ <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>
827
+ </span>
828
+ </a>
829
+ <ul class="sidebar-sub-menu" id="disaster-mgmt">
830
+ <li><a class="sidebar-menu-item" href="#">容灾网关实例</a></li>
831
+ </ul>
832
+ <div class="sidebar-flyout">
833
+ <a class="sidebar-menu-item" href="#">容灾网关实例</a>
834
+ </div>
835
+ </li>
836
+
837
+ <!-- L1: 认证授权(父菜单) -->
838
+ <li>
839
+ <a class="sidebar-menu-item" href="#" data-toggle="auth-mgmt">
840
+ <span class="item-icon">
841
+ <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>
842
+ </span>
843
+ 认证授权
844
+ <span class="expand-icon">
845
+ <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>
846
+ </span>
847
+ </a>
848
+ <ul class="sidebar-sub-menu" id="auth-mgmt">
849
+ <li><a class="sidebar-menu-item" href="#">用户管理</a></li>
850
+ <li><a class="sidebar-menu-item" href="#">角色管理</a></li>
851
+ <li><a class="sidebar-menu-item" href="#">权限插件</a></li>
852
+ <li><a class="sidebar-menu-item" href="#">访问凭证</a></li>
853
+ </ul>
854
+ <div class="sidebar-flyout">
855
+ <a class="sidebar-menu-item" href="#">用户管理</a>
856
+ <a class="sidebar-menu-item" href="#">角色管理</a>
857
+ <a class="sidebar-menu-item" href="#">权限插件</a>
858
+ <a class="sidebar-menu-item" href="#">访问凭证</a>
859
+ </div>
860
+ </li>
861
+ </ul>
862
+ </div>
863
+
864
+ <div class="sidebar-divider"></div>
865
+
866
+ <div class="sidebar-footer">
867
+ <div class="sidebar-avatar">A</div>
868
+ <span class="sidebar-username">admin</span>
869
+ <button class="sidebar-more">
870
+ <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>
871
+ </button>
872
+ </div>
873
+ </aside>
874
+
875
+ <!-- ===== PageContainer ===== -->
876
+ <div class="page-container">
877
+
878
+ <!-- ContentWrapper + Card -->
879
+ <div class="content-wrapper">
880
+ <div class="card">
881
+ <!-- 可滚动区域,Breadcrumb + PageHeader 在白卡内顶部 -->
882
+ <div class="card-scrollable" id="cardScrollable">
883
+
884
+ <!-- Breadcrumb (两级) — L2面包屑模式,禁止标题组件 -->
885
+ <nav class="breadcrumb">
886
+ <a href="#">AI 网关</a>
887
+ <span class="breadcrumb-sep"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="9 18 15 12 9 6"/></svg></span>
888
+ <span class="breadcrumb-current">创建实例</span>
889
+ </nav>
890
+
891
+ <!-- 分组 1: 基本信息 -->
892
+ <div class="settings-section">
893
+ <h2 class="section-title">基本信息</h2>
894
+ <p class="section-desc">配置实例的基本属性</p>
895
+
896
+ <div class="form-row">
897
+ <div class="form-label">实例类型<span class="required">*</span></div>
898
+ <div class="form-control">
899
+ <div class="select-wrapper">
900
+ <button type="button" class="select-trigger" data-value="AI网关">AI网关</button>
901
+ <div class="select-content">
902
+ <div class="select-item selected" data-value="AI网关">AI网关</div>
903
+ <div class="select-item" data-value="API网关">API网关</div>
904
+ </div>
905
+ </div>
906
+ </div>
907
+ </div>
908
+
909
+ <div class="form-row">
910
+ <div class="form-label">实例名称<span class="required">*</span></div>
911
+ <div class="form-control">
912
+ <input class="input" type="text" placeholder="请输入实例名称(小写字母、数字、连字符)">
913
+ </div>
914
+ </div>
915
+
916
+ <div class="form-row">
917
+ <div class="form-label">实例规格<span class="required">*</span></div>
918
+ <div class="form-control">
919
+ <div class="select-wrapper">
920
+ <button type="button" class="select-trigger" data-value="mini">mini</button>
921
+ <div class="select-content">
922
+ <div class="select-item selected" data-value="mini">mini</div>
923
+ <div class="select-item" data-value="small">small</div>
924
+ <div class="select-item" data-value="standard">standard</div>
925
+ <div class="select-item" data-value="large">large</div>
926
+ </div>
927
+ </div>
928
+ </div>
929
+ </div>
930
+
931
+ <div class="form-row">
932
+ <div class="form-label">实例节点数<span class="required">*</span></div>
933
+ <div class="form-control">
934
+ <div class="stepper">
935
+ <button class="stepper-btn">-</button><input type="number" value="1" min="1"><button class="stepper-btn">+</button>
936
+ </div>
937
+ </div>
938
+ </div>
939
+ </div>
940
+
941
+ <!-- 分组 2: 集群配置 -->
942
+ <div class="settings-section">
943
+ <h2 class="section-title">集群配置</h2>
944
+ <p class="section-desc">选择实例部署的集群和命名空间</p>
945
+
946
+ <div class="form-row">
947
+ <div class="form-label">集群<span class="required">*</span></div>
948
+ <div class="form-control">
949
+ <div class="select-wrapper">
950
+ <button type="button" class="select-trigger placeholder" data-value="">请选择集群</button>
951
+ <div class="select-content">
952
+ <div class="select-item" data-value="cluster-prod-01">cluster-prod-01</div>
953
+ <div class="select-item" data-value="cluster-staging-02">cluster-staging-02</div>
954
+ </div>
955
+ </div>
956
+ </div>
957
+ </div>
958
+
959
+ <div class="form-row">
960
+ <div class="form-label">命名空间<span class="required">*</span></div>
961
+ <div class="form-control">
962
+ <div class="select-wrapper">
963
+ <button type="button" class="select-trigger placeholder" data-value="">请选择命名空间</button>
964
+ <div class="select-content">
965
+ <div class="select-item" data-value="default">default</div>
966
+ <div class="select-item" data-value="higress-system">higress-system</div>
967
+ <div class="select-item" data-value="istio-system">istio-system</div>
968
+ </div>
969
+ </div>
970
+ </div>
971
+ </div>
972
+
973
+ <div class="form-row">
974
+ <div class="form-label">Ingress 类名<span class="required">*</span></div>
975
+ <div class="form-control">
976
+ <input class="input" type="text" placeholder="请输入 IngressClass 名称">
977
+ </div>
978
+ </div>
979
+
980
+ <div class="form-row">
981
+ <div class="form-label">镜像拉取密钥</div>
982
+ <div class="form-control">
983
+ <input class="input" type="text" placeholder="请输入 imagePullSecret 名称(可选)">
984
+ </div>
985
+ </div>
986
+
987
+ <div class="form-row">
988
+ <div class="form-label">服务暴露方式</div>
989
+ <div class="form-control">
990
+ <div class="select-wrapper">
991
+ <button type="button" class="select-trigger" data-value="LoadBalancer(负载均衡)">LoadBalancer(负载均衡)</button>
992
+ <div class="select-content">
993
+ <div class="select-item selected" data-value="LoadBalancer(负载均衡)">LoadBalancer(负载均衡)</div>
994
+ <div class="select-item" data-value="NodePort(节点端口)">NodePort(节点端口)</div>
995
+ <div class="select-item" data-value="ClusterIP(集群内部)">ClusterIP(集群内部)</div>
996
+ </div>
997
+ </div>
998
+ </div>
999
+ </div>
1000
+ </div>
1001
+
1002
+ <!-- 分组 3: 可观测性配置 -->
1003
+ <div class="settings-section">
1004
+ <h2 class="section-title">可观测性配置</h2>
1005
+ <p class="section-desc">启用日志和监控服务</p>
1006
+
1007
+ <div class="form-row">
1008
+ <div class="form-label">日志服务</div>
1009
+ <div class="form-control">
1010
+ <div style="display: flex; align-items: center; gap: 8px;">
1011
+ <label class="switch">
1012
+ <input type="checkbox" checked>
1013
+ <span class="switch-track"></span>
1014
+ <span class="switch-thumb"></span>
1015
+ </label>
1016
+ <div class="form-description" style="margin: 0;">开启后为实例采集运行日志</div>
1017
+ </div>
1018
+ </div>
1019
+ </div>
1020
+
1021
+ <div class="form-row">
1022
+ <div class="form-label">Prometheus 监控</div>
1023
+ <div class="form-control">
1024
+ <div style="display: flex; align-items: center; gap: 8px;">
1025
+ <label class="switch">
1026
+ <input type="checkbox" checked>
1027
+ <span class="switch-track"></span>
1028
+ <span class="switch-thumb"></span>
1029
+ </label>
1030
+ <div class="form-description" style="margin: 0;">启用 Prometheus 指标采集</div>
1031
+ </div>
1032
+ </div>
1033
+ </div>
1034
+ </div>
1035
+
1036
+ </div><!-- /.card-scrollable -->
1037
+
1038
+ <!-- Footer -->
1039
+ <div class="settings-footer">
1040
+ <button class="btn btn-secondary">取消</button>
1041
+ <button class="btn btn-primary">提交</button>
1042
+ </div>
1043
+ </div><!-- /.card -->
1044
+ </div><!-- /.content-wrapper -->
1045
+ </div><!-- /.page-container -->
1046
+
1047
+ <script>
1048
+ // Sidebar collapse toggle
1049
+ const sidebar = document.querySelector('.sidebar');
1050
+ document.querySelector('.sidebar-collapse-btn').addEventListener('click', function() {
1051
+ sidebar.classList.toggle('collapsed');
1052
+ });
1053
+ // Sidebar expand via logo click (collapsed state)
1054
+ document.getElementById('sidebarLogoArea').addEventListener('click', function() {
1055
+ if (sidebar.classList.contains('collapsed')) {
1056
+ sidebar.classList.remove('collapsed');
1057
+ }
1058
+ });
1059
+
1060
+ // Sidebar expand toggle
1061
+ document.querySelectorAll('.sidebar-menu-item[data-toggle]').forEach(item => {
1062
+ item.addEventListener('click', function(e) {
1063
+ e.preventDefault();
1064
+ this.classList.toggle('expanded');
1065
+ const targetId = this.getAttribute('data-toggle');
1066
+ const target = document.getElementById(targetId);
1067
+ if (target) target.classList.toggle('show');
1068
+ });
1069
+ });
1070
+
1071
+ // Custom Select component
1072
+ document.querySelectorAll('.select-wrapper').forEach(wrapper => {
1073
+ const trigger = wrapper.querySelector('.select-trigger');
1074
+ const content = wrapper.querySelector('.select-content');
1075
+ const items = wrapper.querySelectorAll('.select-item');
1076
+
1077
+ trigger.addEventListener('click', function(e) {
1078
+ e.stopPropagation();
1079
+ // Close all other selects
1080
+ document.querySelectorAll('.select-content.show').forEach(c => {
1081
+ if (c !== content) c.classList.remove('show');
1082
+ });
1083
+ content.classList.toggle('show');
1084
+ });
1085
+
1086
+ items.forEach(item => {
1087
+ if (item.hasAttribute('data-disabled')) return;
1088
+ item.addEventListener('click', function() {
1089
+ items.forEach(i => i.classList.remove('selected'));
1090
+ this.classList.add('selected');
1091
+ trigger.textContent = this.textContent;
1092
+ trigger.dataset.value = this.dataset.value;
1093
+ trigger.classList.remove('placeholder');
1094
+ content.classList.remove('show');
1095
+ });
1096
+ });
1097
+ });
1098
+
1099
+ // Close selects on outside click
1100
+ document.addEventListener('click', function(e) {
1101
+ if (!e.target.closest('.select-wrapper')) {
1102
+ document.querySelectorAll('.select-content.show').forEach(c => c.classList.remove('show'));
1103
+ }
1104
+ });
1105
+
1106
+ // Stepper buttons
1107
+ document.querySelectorAll('.stepper-btn').forEach(btn => {
1108
+ btn.addEventListener('click', function() {
1109
+ const input = this.parentElement.querySelector('input[type="number"]');
1110
+ const min = parseInt(input.min) || 1;
1111
+ let val = parseInt(input.value) || min;
1112
+ if (this.textContent.trim() === '+') val++;
1113
+ else if (val > min) val--;
1114
+ input.value = val;
1115
+ });
1116
+ });
1117
+ </script>
1118
+ </body>
1119
+ </html>