11<script lang="ts" setup>
2- import type { GroupNodeWithApis , HttpMethod } from ' @/types/api'
2+ import type { HttpMethod } from ' @/types/api'
33import type { ConflictStrategy , ImportPreview } from ' @/types/import'
44import { AlertTriangle , ChevronDown , ChevronRight , FileText , FolderOpen } from ' lucide-vue-next'
5+ import { storeToRefs } from ' pinia'
56import { computed , ref } from ' vue'
67import { Badge } from ' @/components/ui/badge'
78import { Button } from ' @/components/ui/button'
@@ -13,7 +14,6 @@ import {
1314} from ' @/components/ui/collapsible'
1415import { Label } from ' @/components/ui/label'
1516import { RadioGroup , RadioGroupItem } from ' @/components/ui/radio-group'
16- import { ScrollArea } from ' @/components/ui/scroll-area'
1717import {
1818 Select ,
1919 SelectContent ,
@@ -40,30 +40,19 @@ const emits = defineEmits<{
4040}>()
4141
4242const apiTreeStore = useApiTreeStore ()
43+ const { flatGroups } = storeToRefs (apiTreeStore )
44+
45+ /** 按 tags 自动创建分组(Reka-ui 不支持清空选项,,,) */
46+ const AUTO_GROUP_VALUE = ' __auto__'
4347
4448// 配置选项
4549const conflictStrategy = ref <ConflictStrategy >(' skip' )
46- const targetGroupId = ref <string >(' ' )
50+ const targetGroupId = ref <string >(AUTO_GROUP_VALUE )
4751const createMissingGroups = ref (true )
4852
4953// 分组展开状态
5054const expandedGroups = ref <Set <string >>(new Set ())
5155
52- // 扁平化分组列表
53- const flatGroups = computed (() => {
54- const result: { id: string , name: string , level: number }[] = []
55-
56- function traverse(nodes : GroupNodeWithApis [], level : number ) {
57- for (const node of nodes ) {
58- result .push ({ id: node .id , name: node .name , level })
59- traverse (node .children , level + 1 )
60- }
61- }
62-
63- traverse (apiTreeStore .tree , 0 )
64- return result
65- })
66-
6756// 按分组组织 API
6857const apisGroupedByGroup = computed (() => {
6958 const groups = new Map <string , typeof props .preview .apis >()
@@ -87,7 +76,7 @@ function toggleGroup(groupName: string) {
8776function handleSubmit() {
8877 emits (' submit' , {
8978 conflictStrategy: conflictStrategy .value ,
90- targetGroupId: targetGroupId .value || undefined ,
79+ targetGroupId: targetGroupId .value === AUTO_GROUP_VALUE ? undefined : targetGroupId . value ,
9180 createMissingGroups: createMissingGroups .value ,
9281 })
9382}
@@ -194,11 +183,14 @@ function getMethodClass(method: HttpMethod) {
194183 <!-- 目标分组 -->
195184 <div class =" space-y-2" >
196185 <Label for="target-group">目标分组(可选)</Label >
197- <Select v-model =" targetGroupId " : disabled = " ! flatGroups . length " >
186+ <Select v-model =" targetGroupId " >
198187 <SelectTrigger id="target-group">
199- <SelectValue : placeholder =" ` ${ flatGroups . length > 0 ? ' ' : ' 无可选分组, ' } 按 tags 自动创建分组` " />
188+ <SelectValue placeholder="按 tags 自动创建分组" />
200189 </SelectTrigger >
201190 <SelectContent >
191+ <SelectItem :value =" AUTO_GROUP_VALUE " >
192+ <span class =" text-muted-foreground" >按 tags 自动创建分组</span >
193+ </SelectItem >
202194 <SelectItem
203195 v-for =" group in flatGroups "
204196 :key =" group .id "
@@ -218,7 +210,7 @@ function getMethodClass(method: HttpMethod) {
218210 <Checkbox
219211 id="create-groups"
220212 :checked =" createMissingGroups "
221- :disabled =" !! targetGroupId "
213+ :disabled =" targetGroupId !== AUTO_GROUP_VALUE "
222214 @update :checked =" createMissingGroups = $event as boolean "
223215 />
224216 < Label for = " create-groups" class="font-normal cursor-pointer">
@@ -232,54 +224,52 @@ function getMethodClass(method: HttpMethod) {
232224 <!-- API 预览列表 -->
233225 <div class =" space-y-2" >
234226 <Label >接口预览</Label >
235- <ScrollArea class="h-[200px] rounded-md border">
236- <div class =" p-2 space-y-1" >
237- <Collapsible
238- v-for =" [groupName , apis ] in apisGroupedByGroup "
239- :key =" groupName "
240- :open =" expandedGroups .has (groupName )"
241- @update :open =" toggleGroup (groupName )"
242- >
243- <CollapsibleTrigger class="flex items-center gap-2 w-full p-2 hover:bg-muted rounded-md text-left">
244- <component
245- :is =" expandedGroups.has(groupName) ? ChevronDown : ChevronRight"
246- class =" h-4 w-4 text-muted-foreground shrink-0"
247- />
248- <FolderOpen class="h-4 w-4 text-muted-foreground shrink-0" />
249- <span class =" text-sm font-medium flex-1 truncate" >{{ groupName }}</span >
250- <Badge variant="secondary" class="ml-auto">
251- {{ apis.length }}
252- </Badge >
253- </CollapsibleTrigger >
254- <CollapsibleContent >
255- <div class =" ml-6 pl-4 border-l space-y-1" >
256- <div
257- v-for =" api in apis"
258- :key =" `${api.method}-${api.path}`"
259- class =" flex items-center gap-2 p-2 text-sm rounded-md"
260- :class =" api.hasConflict ? 'bg-amber-50 dark:bg-amber-950/20' : 'hover:bg-muted'"
227+ <div class =" p-2 space-y-1" >
228+ <Collapsible
229+ v-for =" [groupName , apis ] in apisGroupedByGroup "
230+ :key =" groupName "
231+ :open =" expandedGroups .has (groupName )"
232+ @update :open =" toggleGroup (groupName )"
233+ >
234+ <CollapsibleTrigger class="flex items-center gap-2 w-full p-2 hover:bg-muted rounded-md text-left">
235+ <component
236+ :is =" expandedGroups.has(groupName) ? ChevronDown : ChevronRight"
237+ class =" h-4 w-4 text-muted-foreground shrink-0"
238+ />
239+ <FolderOpen class="h-4 w-4 text-muted-foreground shrink-0" />
240+ <span class =" text-sm font-medium flex-1 truncate" >{{ groupName }}</span >
241+ <Badge variant="secondary" class="ml-auto">
242+ {{ apis.length }}
243+ </Badge >
244+ </CollapsibleTrigger >
245+ <CollapsibleContent >
246+ <div class =" ml-6 pl-4 border-l space-y-1" >
247+ <div
248+ v-for =" api in apis"
249+ :key =" `${api.method}-${api.path}`"
250+ class =" flex items-center gap-2 p-2 text-sm rounded-md"
251+ :class =" api.hasConflict ? 'bg-amber-50 dark:bg-amber-950/20' : 'hover:bg-muted'"
252+ >
253+ <span
254+ class =" font-mono text-xs font-bold w-16 shrink-0"
255+ :class =" getMethodClass(api.method)"
261256 >
262- <span
263- class =" font-mono text-xs font-bold w-16 shrink-0"
264- :class =" getMethodClass(api.method)"
265- >
266- {{ api.method }}
267- </span >
268- <span class =" font-mono text-xs text-muted-foreground truncate flex-1" >
269- {{ api.path }}
270- </span >
271- <span class =" text-xs truncate max-w-[120px]" >
272- {{ api.name }}
273- </span >
274- <Badge v-if =" api .hasConflict " variant="outline" class="text-amber-600 border-amber-300 shrink-0">
275- 冲突
276- </Badge >
277- </div >
257+ {{ api.method }}
258+ </span >
259+ <span class =" font-mono text-xs text-muted-foreground truncate flex-1" >
260+ {{ api.path }}
261+ </span >
262+ <span class =" text-xs truncate max-w-[120px]" >
263+ {{ api.name }}
264+ </span >
265+ <Badge v-if =" api .hasConflict " variant="outline" class="text-amber-600 border-amber-300 shrink-0">
266+ 冲突
267+ </Badge >
278268 </div >
279- </CollapsibleContent >
280- </Collapsible >
281- </div >
282- </ScrollArea >
269+ </div >
270+ </CollapsibleContent >
271+ </Collapsible >
272+ </div >
283273 </div >
284274
285275 <!-- 操作按钮 -->
0 commit comments