vue-agent-start 0.1.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 (169) hide show
  1. package/package.json +30 -0
  2. package/pnpm-workspace.yaml +3 -0
  3. package/src/agent-flow/adapter/backend.ts +99 -0
  4. package/src/agent-flow/components/ChatIframePanel.vue +773 -0
  5. package/src/agent-flow/components/DatasetItemCard.vue +313 -0
  6. package/src/agent-flow/components/MemoryWindow.vue +104 -0
  7. package/src/agent-flow/components/PromptEditor.vue +804 -0
  8. package/src/agent-flow/components/PromptEditorTagPanel.vue +460 -0
  9. package/src/agent-flow/components/SvgIcon.vue +32 -0
  10. package/src/agent-flow/components/ToolItemCard.vue +169 -0
  11. package/src/agent-flow/components/VariableCard.vue +161 -0
  12. package/src/agent-flow/components/VariableSelector.vue +162 -0
  13. package/src/agent-flow/components/chat-iframe-types.ts +35 -0
  14. package/src/agent-flow/components/stubs/DatasetChooser.vue +70 -0
  15. package/src/agent-flow/components/stubs/Embedding.vue +22 -0
  16. package/src/agent-flow/components/stubs/ModelSelect.vue +24 -0
  17. package/src/agent-flow/components/stubs/RestfulSelectCard.vue +24 -0
  18. package/src/agent-flow/components/stubs/ToolChooser.vue +96 -0
  19. package/src/agent-flow/components/stubs/TriggersItemCard.vue +126 -0
  20. package/src/agent-flow/components/stubs/VariableModal.vue +115 -0
  21. package/src/agent-flow/index.ts +73 -0
  22. package/src/agent-flow/stores/workflow.ts +72 -0
  23. package/src/agent-flow/utils/langUtils.ts +173 -0
  24. package/src/agent-flow/workflow/Ability.vue +65 -0
  25. package/src/agent-flow/workflow/AuthorizationItem.vue +101 -0
  26. package/src/agent-flow/workflow/ConversationVar.vue +42 -0
  27. package/src/agent-flow/workflow/CustomEdge.vue +94 -0
  28. package/src/agent-flow/workflow/EnvironmentVar.vue +40 -0
  29. package/src/agent-flow/workflow/FlowDesigner.vue +2802 -0
  30. package/src/agent-flow/workflow/Icon.vue +179 -0
  31. package/src/agent-flow/workflow/NodeConfig.vue +509 -0
  32. package/src/agent-flow/workflow/NodeConfigCard.vue +460 -0
  33. package/src/agent-flow/workflow/NodeHandle.vue +147 -0
  34. package/src/agent-flow/workflow/NodeHeaderToolbar.vue +77 -0
  35. package/src/agent-flow/workflow/NodeHoverToolbar.vue +176 -0
  36. package/src/agent-flow/workflow/OutputItemCard.vue +668 -0
  37. package/src/agent-flow/workflow/ParamTableItem.vue +200 -0
  38. package/src/agent-flow/workflow/StructTable.vue +202 -0
  39. package/src/agent-flow/workflow/VarInsertField.vue +517 -0
  40. package/src/agent-flow/workflow/VarSelectField.vue +223 -0
  41. package/src/agent-flow/workflow/VariableSelectorItem.vue +48 -0
  42. package/src/agent-flow/workflow/WfField.vue +206 -0
  43. package/src/agent-flow/workflow/_config-base.css +470 -0
  44. package/src/agent-flow/workflow/composables/useNode.js +55 -0
  45. package/src/agent-flow/workflow/index.vue +53 -0
  46. package/src/agent-flow/workflow/nodeCard/AgentNodeCard.vue +180 -0
  47. package/src/agent-flow/workflow/nodeCard/AnswerNodeCard.vue +65 -0
  48. package/src/agent-flow/workflow/nodeCard/ClassifierCard.vue +152 -0
  49. package/src/agent-flow/workflow/nodeCard/CodeNodeCard.vue +139 -0
  50. package/src/agent-flow/workflow/nodeCard/ConditionNodeCard.vue +323 -0
  51. package/src/agent-flow/workflow/nodeCard/DocumentExtractorCard.vue +83 -0
  52. package/src/agent-flow/workflow/nodeCard/EndNodeCard.vue +123 -0
  53. package/src/agent-flow/workflow/nodeCard/HttpNodeCard.vue +451 -0
  54. package/src/agent-flow/workflow/nodeCard/HumanInputCard.vue +152 -0
  55. package/src/agent-flow/workflow/nodeCard/IterationCard.vue +66 -0
  56. package/src/agent-flow/workflow/nodeCard/KnowledgeRetrievalCard.vue +48 -0
  57. package/src/agent-flow/workflow/nodeCard/LLMNodeCard.vue +206 -0
  58. package/src/agent-flow/workflow/nodeCard/ListOperatorCard.vue +188 -0
  59. package/src/agent-flow/workflow/nodeCard/ParameterExtractorCard.vue +352 -0
  60. package/src/agent-flow/workflow/nodeCard/ServiceApiNodeCard.vue +188 -0
  61. package/src/agent-flow/workflow/nodeCard/StartNodeCard.vue +216 -0
  62. package/src/agent-flow/workflow/nodeCard/VariableAssignerCard.vue +125 -0
  63. package/src/agent-flow/workflow/nodeCard/VariableNodeCard.vue +121 -0
  64. package/src/agent-flow/workflow/nodes/AgentNode.vue +122 -0
  65. package/src/agent-flow/workflow/nodes/AnswerNode.vue +99 -0
  66. package/src/agent-flow/workflow/nodes/ClassifierNode.vue +199 -0
  67. package/src/agent-flow/workflow/nodes/CodeNode.vue +152 -0
  68. package/src/agent-flow/workflow/nodes/ConditionNode.vue +232 -0
  69. package/src/agent-flow/workflow/nodes/DocumentExtractorNode.vue +96 -0
  70. package/src/agent-flow/workflow/nodes/EndNode.vue +119 -0
  71. package/src/agent-flow/workflow/nodes/FileUploadNode.vue +97 -0
  72. package/src/agent-flow/workflow/nodes/HttpNode.vue +204 -0
  73. package/src/agent-flow/workflow/nodes/HumanInputNode.vue +110 -0
  74. package/src/agent-flow/workflow/nodes/IterationNode.vue +98 -0
  75. package/src/agent-flow/workflow/nodes/KnowledgeRetrievalNode.vue +253 -0
  76. package/src/agent-flow/workflow/nodes/LLMNode.vue +134 -0
  77. package/src/agent-flow/workflow/nodes/ListOperatorNode.vue +111 -0
  78. package/src/agent-flow/workflow/nodes/LoopNode.vue +94 -0
  79. package/src/agent-flow/workflow/nodes/ParameterExtractorNode.vue +147 -0
  80. package/src/agent-flow/workflow/nodes/ServiceApiNode.vue +161 -0
  81. package/src/agent-flow/workflow/nodes/StartNode.vue +199 -0
  82. package/src/agent-flow/workflow/nodes/TemplateNode.vue +103 -0
  83. package/src/agent-flow/workflow/nodes/UserInputNode.vue +92 -0
  84. package/src/agent-flow/workflow/nodes/VariableAssignerNode.vue +145 -0
  85. package/src/agent-flow/workflow/nodes/VariableNode.vue +130 -0
  86. package/src/agent-flow/workflow/nodes/_node-base.css +338 -0
  87. package/src/agent-flow/workflow/utils/node_card_form.ts +335 -0
  88. package/src/agent-flow/workflow/utils/node_config.ts +63 -0
  89. package/src/agent-flow/workflow/utils/workflow_utils.ts +151 -0
  90. package/src/agent-studio/adapters/springAgentStart.ts +390 -0
  91. package/src/agent-studio/api/index.ts +1 -0
  92. package/src/agent-studio/api/types.ts +173 -0
  93. package/src/agent-studio/components/AgentApiDocs.vue +500 -0
  94. package/src/agent-studio/components/AgentAppsPage.vue +1601 -0
  95. package/src/agent-studio/components/AgentCardGrid.vue +259 -0
  96. package/src/agent-studio/components/AgentChatPage.vue +553 -0
  97. package/src/agent-studio/components/AgentDebugPanel.vue +350 -0
  98. package/src/agent-studio/components/AgentLogsPanel.vue +391 -0
  99. package/src/agent-studio/components/AgentMonitorPanel.vue +204 -0
  100. package/src/agent-studio/components/AgentOrchestrate.vue +505 -0
  101. package/src/agent-studio/components/AgentPromptEditor.vue +237 -0
  102. package/src/agent-studio/components/AgentStudioShell.vue +227 -0
  103. package/src/agent-studio/components/AgentToolsPanel.vue +394 -0
  104. package/src/agent-studio/components/AgentVariablesPanel.vue +205 -0
  105. package/src/agent-studio/components/ApiKeyManager.vue +251 -0
  106. package/src/agent-studio/components/AppDesignDrawer.vue +3391 -0
  107. package/src/agent-studio/components/CreateAppModal.vue +737 -0
  108. package/src/agent-studio/components/SparkChart.vue +200 -0
  109. package/src/agent-studio/components/VariableEditorModal.vue +499 -0
  110. package/src/agent-studio/composables/useAgentStudio.ts +347 -0
  111. package/src/agent-studio/index.ts +60 -0
  112. package/src/agent-studio/panels/DrawerFlowDesigner.vue +203 -0
  113. package/src/agent-studio/panels/LogAnnotationPanel.vue +490 -0
  114. package/src/agent-studio/panels/MonitorPanel.vue +535 -0
  115. package/src/agent-studio/types.ts +242 -0
  116. package/src/index.ts +155 -0
  117. package/src/knowledge-hub/adapters/springAgentStart.ts +472 -0
  118. package/src/knowledge-hub/components/AddDocumentsWizard.vue +1452 -0
  119. package/src/knowledge-hub/components/CreateDatasetWizard.vue +1723 -0
  120. package/src/knowledge-hub/components/DatasetCardGrid.vue +467 -0
  121. package/src/knowledge-hub/components/DatasetDetailDrawer.vue +888 -0
  122. package/src/knowledge-hub/components/DatasetPicker.vue +65 -0
  123. package/src/knowledge-hub/components/DatasetPickerModal.vue +526 -0
  124. package/src/knowledge-hub/components/DatasetSettingsPanel.vue +908 -0
  125. package/src/knowledge-hub/components/DatasetSidebar.vue +781 -0
  126. package/src/knowledge-hub/components/DocumentChunksView.vue +802 -0
  127. package/src/knowledge-hub/components/DocumentTable.vue +552 -0
  128. package/src/knowledge-hub/components/HitTestingPanel.vue +74 -0
  129. package/src/knowledge-hub/components/KnowledgeApp.vue +66 -0
  130. package/src/knowledge-hub/components/KnowledgeHubApp.vue +504 -0
  131. package/src/knowledge-hub/components/RecallTestingPanelV2.vue +515 -0
  132. package/src/knowledge-hub/components/RetrievalConfigPopover.vue +270 -0
  133. package/src/knowledge-hub/components/RetrievalMethodPicker.vue +547 -0
  134. package/src/knowledge-hub/components/RetrievedList.vue +24 -0
  135. package/src/knowledge-hub/components/internal/KhDialog.vue +195 -0
  136. package/src/knowledge-hub/composables/useKnowledge.ts +89 -0
  137. package/src/knowledge-hub/i18n/index.ts +2 -0
  138. package/src/knowledge-hub/i18n/messages.ts +422 -0
  139. package/src/knowledge-hub/i18n/useKhI18n.ts +107 -0
  140. package/src/knowledge-hub/index.ts +46 -0
  141. package/src/knowledge-hub/styles/index.css +4 -0
  142. package/src/knowledge-hub/styles/tokens.css +138 -0
  143. package/src/knowledge-hub/types/api.ts +213 -0
  144. package/src/knowledge-hub/types/dataset.ts +88 -0
  145. package/src/knowledge-hub/types/document.ts +45 -0
  146. package/src/knowledge-hub/types/index.ts +9 -0
  147. package/src/knowledge-hub/types/retrieval.ts +46 -0
  148. package/src/provider-hub/components/CredentialForm.vue +103 -0
  149. package/src/provider-hub/components/DefaultModelsPanel.vue +270 -0
  150. package/src/provider-hub/components/GroupedModelSelect.vue +445 -0
  151. package/src/provider-hub/components/ModelCardGrid.vue +332 -0
  152. package/src/provider-hub/components/ModelParameterDrawer.vue +739 -0
  153. package/src/provider-hub/components/ModelPickerPopover.vue +1282 -0
  154. package/src/provider-hub/components/ProviderApp.vue +159 -0
  155. package/src/provider-hub/components/ProviderCredentialModal.vue +321 -0
  156. package/src/provider-hub/components/ProviderGallery.vue +131 -0
  157. package/src/provider-hub/components/ProviderHubShell.vue +1992 -0
  158. package/src/provider-hub/components/ProviderIcon.vue +130 -0
  159. package/src/provider-hub/composables/useProviderHub.ts +358 -0
  160. package/src/provider-hub/index.ts +43 -0
  161. package/src/provider-hub/svg/MiniMax.svg +1 -0
  162. package/src/provider-hub/svg/Volcengine.svg +1 -0
  163. package/src/provider-hub/svg/Zhipu.svg +1 -0
  164. package/src/provider-hub/svg/deepseek.svg +1 -0
  165. package/src/provider-hub/svg/moonshot.svg +1 -0
  166. package/src/provider-hub/svg/openai.svg +1 -0
  167. package/src/provider-hub/svg/qwen.svg +1 -0
  168. package/src/provider-hub/svg/siliconflow.svg +1 -0
  169. package/src/provider-hub/types.ts +256 -0
@@ -0,0 +1,445 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * GroupedModelSelect — brand-icon dropdown that groups model options by
4
+ * provider, with a search box and collapsible provider sections.
5
+ *
6
+ * The knowledge-hub Embedding-model picker was the first user of this pattern;
7
+ * this component is the extracted, reusable form so 系统默认模型 (rerank / TTS
8
+ * / speech-to-text rows), agent-studio model pickers, and anything else that
9
+ * wants "brand-grouped model dropdown" can share the same UX.
10
+ *
11
+ * Contract:
12
+ * options: flat list of { id, label, providerName?, providerLabel?, isDefault? }
13
+ * modelValue: currently-selected id (v-model target)
14
+ * emit 'update:modelValue' + 'change' when the user picks an option
15
+ *
16
+ * Options without a `providerName` land in a single "其他" bucket so legacy
17
+ * lists (that never carried provider metadata) still render.
18
+ */
19
+ import { computed, onBeforeUnmount, onMounted, ref } from 'vue';
20
+
21
+ import ProviderIcon from './ProviderIcon.vue';
22
+
23
+ export interface GroupedModelSelectOption {
24
+ id: string;
25
+ label: string;
26
+ /** Provider name used to look up the brand icon + group by. */
27
+ providerName?: string;
28
+ /** Human-readable provider label. Falls back to providerName then "其他". */
29
+ providerLabel?: string;
30
+ /**
31
+ * When true, the option is rendered with a "默认" badge. Purely decorative —
32
+ * auto-selection behaviour is the caller's job (via modelValue seeding).
33
+ */
34
+ isDefault?: boolean;
35
+ }
36
+
37
+ interface Props {
38
+ modelValue?: null | string;
39
+ options: GroupedModelSelectOption[];
40
+ /** Placeholder text when nothing is selected. */
41
+ placeholder?: string;
42
+ /** Fired into the search box's placeholder attribute. */
43
+ searchPlaceholder?: string;
44
+ /** Copy for the empty state when there are zero options. */
45
+ emptyText?: string;
46
+ /** Sub-hint under the empty-state icon. */
47
+ emptyHint?: string;
48
+ /** Disables the trigger. */
49
+ disabled?: boolean;
50
+ /**
51
+ * Fallback icon (single char) rendered when the selected option has no
52
+ * provider — e.g. legacy datasets whose embedding rows don't carry provider
53
+ * metadata. Default: "⌬".
54
+ */
55
+ fallbackIcon?: string;
56
+ }
57
+
58
+ const props = withDefaults(defineProps<Props>(), {
59
+ modelValue: null,
60
+ placeholder: '请选择模型',
61
+ searchPlaceholder: '搜索模型 / 供应商',
62
+ emptyText: '暂无可用模型',
63
+ emptyHint: '',
64
+ disabled: false,
65
+ fallbackIcon: '⌬',
66
+ });
67
+
68
+ const emit = defineEmits<{
69
+ (e: 'change', v: null | string): void;
70
+ (e: 'update:modelValue', v: null | string): void;
71
+ }>();
72
+
73
+ const open = ref(false);
74
+ const search = ref('');
75
+ const collapsed = ref<Set<string>>(new Set());
76
+ const rootRef = ref<HTMLElement | null>(null);
77
+
78
+ interface Group {
79
+ providerName: string;
80
+ providerLabel: string;
81
+ models: GroupedModelSelectOption[];
82
+ }
83
+
84
+ const groups = computed<Group[]>(() => {
85
+ const map = new Map<string, Group>();
86
+ for (const m of props.options) {
87
+ const pn = (m.providerName ?? '').trim() || '__other';
88
+ const label = (m.providerLabel ?? m.providerName ?? '').trim() || '其他';
89
+ let group = map.get(pn);
90
+ if (!group) {
91
+ group = { providerName: pn, providerLabel: label, models: [] };
92
+ map.set(pn, group);
93
+ }
94
+ group.models.push(m);
95
+ }
96
+ return [...map.values()];
97
+ });
98
+
99
+ const filteredGroups = computed<Group[]>(() => {
100
+ const q = search.value.trim().toLowerCase();
101
+ if (!q) return groups.value;
102
+ return groups.value
103
+ .map((g) => ({
104
+ ...g,
105
+ models: g.models.filter((m) => {
106
+ return (
107
+ m.label.toLowerCase().includes(q) ||
108
+ (m.providerLabel ?? m.providerName ?? '')
109
+ .toLowerCase()
110
+ .includes(q)
111
+ );
112
+ }),
113
+ }))
114
+ .filter((g) => g.models.length > 0);
115
+ });
116
+
117
+ const current = computed(() =>
118
+ props.options.find((m) => m.id === props.modelValue),
119
+ );
120
+
121
+ function toggleGroup(name: string) {
122
+ const next = new Set(collapsed.value);
123
+ if (next.has(name)) next.delete(name);
124
+ else next.add(name);
125
+ collapsed.value = next;
126
+ }
127
+
128
+ function pick(m: GroupedModelSelectOption) {
129
+ emit('update:modelValue', m.id);
130
+ emit('change', m.id);
131
+ open.value = false;
132
+ search.value = '';
133
+ }
134
+
135
+ function toggleOpen() {
136
+ if (props.disabled) return;
137
+ open.value = !open.value;
138
+ }
139
+
140
+ function onDocMousedown(e: MouseEvent) {
141
+ if (!open.value) return;
142
+ const el = rootRef.value;
143
+ if (el && !el.contains(e.target as Node)) open.value = false;
144
+ }
145
+
146
+ onMounted(() => window.addEventListener('mousedown', onDocMousedown));
147
+ onBeforeUnmount(() => window.removeEventListener('mousedown', onDocMousedown));
148
+ </script>
149
+
150
+ <template>
151
+ <div ref="rootRef" class="gms" :class="{ 'is-disabled': disabled }">
152
+ <button
153
+ type="button"
154
+ class="gms-trigger"
155
+ :class="{ 'is-active': open, 'has-value': !!current }"
156
+ :disabled="disabled"
157
+ @click="toggleOpen"
158
+ >
159
+ <span class="gms-trigger-icon">
160
+ <ProviderIcon
161
+ v-if="current?.providerName"
162
+ :name="current.providerName"
163
+ :size="20"
164
+ />
165
+ <span v-else class="gms-trigger-icon-fallback">{{ fallbackIcon }}</span>
166
+ </span>
167
+ <span v-if="current" class="gms-trigger-name" :title="current.label">
168
+ {{ current.label }}
169
+ </span>
170
+ <span v-else class="gms-trigger-placeholder">{{ placeholder }}</span>
171
+ <span class="gms-trigger-caret">▾</span>
172
+ </button>
173
+
174
+ <div v-if="open" class="gms-panel" @click.stop>
175
+ <div class="gms-search">
176
+ <span class="gms-search-icon">🔍</span>
177
+ <input
178
+ v-model="search"
179
+ class="gms-search-input"
180
+ :placeholder="searchPlaceholder"
181
+ @click.stop
182
+ />
183
+ </div>
184
+ <div class="gms-body">
185
+ <div v-if="filteredGroups.length === 0" class="gms-empty">
186
+ <div class="gms-empty-icon">{{ fallbackIcon }}</div>
187
+ <div>{{ emptyText }}</div>
188
+ <div v-if="emptyHint" class="gms-empty-hint">{{ emptyHint }}</div>
189
+ </div>
190
+ <div
191
+ v-for="g in filteredGroups"
192
+ :key="g.providerName"
193
+ class="gms-group"
194
+ >
195
+ <div
196
+ class="gms-group-head"
197
+ @click="toggleGroup(g.providerName)"
198
+ >
199
+ <span class="gms-fold">
200
+ {{ collapsed.has(g.providerName) ? '▸' : '▾' }}
201
+ </span>
202
+ <ProviderIcon
203
+ v-if="g.providerName !== '__other'"
204
+ :name="g.providerName"
205
+ :size="16"
206
+ />
207
+ <span v-else class="gms-group-icon">{{ fallbackIcon }}</span>
208
+ <span class="gms-group-name">{{ g.providerLabel }}</span>
209
+ <span class="gms-group-count">{{ g.models.length }}</span>
210
+ </div>
211
+ <div
212
+ v-if="!collapsed.has(g.providerName)"
213
+ class="gms-group-body"
214
+ >
215
+ <div
216
+ v-for="m in g.models"
217
+ :key="m.id"
218
+ class="gms-item"
219
+ :class="{ 'is-active': modelValue === m.id }"
220
+ @click="pick(m)"
221
+ >
222
+ <ProviderIcon
223
+ v-if="m.providerName"
224
+ :name="m.providerName"
225
+ :size="14"
226
+ />
227
+ <span class="gms-item-name" :title="m.label">
228
+ {{ m.label }}
229
+ </span>
230
+ <span v-if="m.isDefault" class="gms-item-default">默认</span>
231
+ <span v-if="modelValue === m.id" class="gms-item-check">✓</span>
232
+ </div>
233
+ </div>
234
+ </div>
235
+ </div>
236
+ </div>
237
+ </div>
238
+ </template>
239
+
240
+ <style scoped>
241
+ .gms {
242
+ position: relative;
243
+ width: 100%;
244
+ }
245
+ .gms.is-disabled {
246
+ opacity: 0.6;
247
+ pointer-events: none;
248
+ }
249
+ .gms-trigger {
250
+ width: 100%;
251
+ padding: 8px 10px;
252
+ display: flex;
253
+ align-items: center;
254
+ gap: 10px;
255
+ border: 1px solid #d1d5db;
256
+ border-radius: 8px;
257
+ background: #fff;
258
+ cursor: pointer;
259
+ transition:
260
+ border-color 0.15s,
261
+ box-shadow 0.15s;
262
+ }
263
+ .gms-trigger:hover:not(:disabled) {
264
+ border-color: #a5b4fc;
265
+ }
266
+ .gms-trigger.is-active {
267
+ border-color: #6366f1;
268
+ box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.15);
269
+ }
270
+ .gms-trigger.has-value {
271
+ background: #fafbff;
272
+ }
273
+ .gms-trigger-icon {
274
+ width: 22px;
275
+ height: 22px;
276
+ display: flex;
277
+ align-items: center;
278
+ justify-content: center;
279
+ color: #6366f1;
280
+ flex-shrink: 0;
281
+ }
282
+ .gms-trigger-icon-fallback {
283
+ font-size: 16px;
284
+ color: #94a3b8;
285
+ }
286
+ .gms-trigger-name {
287
+ flex: 1;
288
+ min-width: 0;
289
+ font-size: 13px;
290
+ font-weight: 500;
291
+ color: #0f172a;
292
+ overflow: hidden;
293
+ text-overflow: ellipsis;
294
+ white-space: nowrap;
295
+ text-align: left;
296
+ }
297
+ .gms-trigger-placeholder {
298
+ flex: 1;
299
+ font-size: 13px;
300
+ color: #94a3b8;
301
+ text-align: left;
302
+ }
303
+ .gms-trigger-caret {
304
+ font-size: 10px;
305
+ color: #94a3b8;
306
+ }
307
+ .gms-panel {
308
+ position: absolute;
309
+ top: calc(100% + 6px);
310
+ left: 0;
311
+ right: 0;
312
+ z-index: 40;
313
+ padding: 6px;
314
+ background: #fff;
315
+ border: 1px solid #e5e7eb;
316
+ border-radius: 10px;
317
+ box-shadow: 0 12px 32px rgba(15, 23, 42, 0.12);
318
+ max-height: 360px;
319
+ display: flex;
320
+ flex-direction: column;
321
+ }
322
+ .gms-search {
323
+ display: flex;
324
+ align-items: center;
325
+ gap: 6px;
326
+ padding: 6px 8px;
327
+ border-bottom: 1px solid #f1f5f9;
328
+ background: #f9fafb;
329
+ border-radius: 6px 6px 0 0;
330
+ }
331
+ .gms-search-icon {
332
+ font-size: 12px;
333
+ color: #94a3b8;
334
+ }
335
+ .gms-search-input {
336
+ flex: 1;
337
+ border: 0;
338
+ outline: 0;
339
+ background: transparent;
340
+ font-size: 12px;
341
+ color: #0f172a;
342
+ }
343
+ .gms-body {
344
+ overflow-y: auto;
345
+ padding: 4px 0;
346
+ min-height: 60px;
347
+ }
348
+ .gms-empty {
349
+ padding: 24px 12px;
350
+ text-align: center;
351
+ color: #94a3b8;
352
+ font-size: 12px;
353
+ }
354
+ .gms-empty-icon {
355
+ font-size: 26px;
356
+ opacity: 0.4;
357
+ }
358
+ .gms-empty-hint {
359
+ margin-top: 4px;
360
+ font-size: 11px;
361
+ color: #cbd5e1;
362
+ }
363
+ .gms-group + .gms-group {
364
+ margin-top: 2px;
365
+ padding-top: 2px;
366
+ border-top: 1px solid #f3f4f6;
367
+ }
368
+ .gms-group-head {
369
+ display: flex;
370
+ align-items: center;
371
+ gap: 8px;
372
+ padding: 6px 10px;
373
+ border-radius: 6px;
374
+ cursor: pointer;
375
+ user-select: none;
376
+ }
377
+ .gms-group-head:hover {
378
+ background: #f9fafb;
379
+ }
380
+ .gms-fold {
381
+ font-size: 10px;
382
+ color: #94a3b8;
383
+ width: 12px;
384
+ text-align: center;
385
+ }
386
+ .gms-group-icon {
387
+ font-size: 14px;
388
+ color: #94a3b8;
389
+ }
390
+ .gms-group-name {
391
+ flex: 1;
392
+ font-size: 12px;
393
+ font-weight: 600;
394
+ color: #1f2937;
395
+ }
396
+ .gms-group-count {
397
+ padding: 1px 6px;
398
+ border-radius: 4px;
399
+ background: #f1f5f9;
400
+ color: #64748b;
401
+ font-size: 10px;
402
+ }
403
+ .gms-group-body {
404
+ padding: 2px 0 4px 24px;
405
+ }
406
+ .gms-item {
407
+ display: flex;
408
+ align-items: center;
409
+ gap: 8px;
410
+ padding: 6px 10px;
411
+ border-radius: 6px;
412
+ cursor: pointer;
413
+ transition: background 0.12s;
414
+ }
415
+ .gms-item:hover {
416
+ background: #f3f4f6;
417
+ }
418
+ .gms-item.is-active {
419
+ background: #eef2ff;
420
+ }
421
+ .gms-item-name {
422
+ flex: 1;
423
+ font-size: 12px;
424
+ color: #1f2937;
425
+ overflow: hidden;
426
+ text-overflow: ellipsis;
427
+ white-space: nowrap;
428
+ }
429
+ .gms-item.is-active .gms-item-name {
430
+ color: #4338ca;
431
+ font-weight: 500;
432
+ }
433
+ .gms-item-default {
434
+ padding: 1px 6px;
435
+ border-radius: 4px;
436
+ background: #ecfdf5;
437
+ color: #059669;
438
+ font-size: 10px;
439
+ font-weight: 500;
440
+ }
441
+ .gms-item-check {
442
+ color: #4338ca;
443
+ font-size: 12px;
444
+ }
445
+ </style>