2026-02-14 20:06:38 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<div class="px-4 sm:px-6 py-3 sm:py-3.5 border-b border-border/50">
|
|
|
|
|
|
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 sm:gap-4">
|
|
|
|
|
|
<!-- 左侧:标题 -->
|
|
|
|
|
|
<h3 class="text-sm sm:text-base font-semibold text-foreground shrink-0">
|
2026-06-30 14:14:12 +08:00
|
|
|
|
{{ legacyT('提供商管理') }}
|
2026-02-14 20:06:38 +08:00
|
|
|
|
</h3>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 右侧:操作区 -->
|
|
|
|
|
|
<div class="flex flex-wrap items-center gap-2">
|
|
|
|
|
|
<!-- 搜索框 -->
|
|
|
|
|
|
<div class="relative">
|
|
|
|
|
|
<Search class="absolute left-2.5 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-muted-foreground/70 z-10 pointer-events-none" />
|
|
|
|
|
|
<Input
|
|
|
|
|
|
id="provider-search"
|
|
|
|
|
|
:model-value="searchQuery"
|
|
|
|
|
|
type="text"
|
2026-06-30 14:14:12 +08:00
|
|
|
|
:placeholder="legacyT('搜索提供商...')"
|
2026-02-14 20:06:38 +08:00
|
|
|
|
class="w-32 sm:w-44 pl-8 pr-3 h-8 text-sm bg-muted/30 border-border/50 focus:border-primary/50 transition-colors"
|
|
|
|
|
|
@update:model-value="$emit('update:searchQuery', $event)"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 状态筛选 -->
|
2026-09-07 14:13:59 +08:00
|
|
|
|
<div :class="{ 'xl:hidden': !cardView }">
|
2026-05-01 02:14:49 +08:00
|
|
|
|
<Select
|
|
|
|
|
|
:model-value="filterStatus"
|
|
|
|
|
|
@update:model-value="$emit('update:filterStatus', $event)"
|
|
|
|
|
|
>
|
|
|
|
|
|
<SelectTrigger class="w-20 sm:w-28 h-8 text-xs border-border/60">
|
2026-06-30 14:14:12 +08:00
|
|
|
|
<SelectValue :placeholder="legacyT('全部状态')" />
|
2026-05-01 02:14:49 +08:00
|
|
|
|
</SelectTrigger>
|
|
|
|
|
|
<SelectContent>
|
|
|
|
|
|
<SelectItem
|
|
|
|
|
|
v-for="status in statusFilters"
|
|
|
|
|
|
:key="status.value"
|
|
|
|
|
|
:value="status.value"
|
|
|
|
|
|
>
|
2026-06-30 14:14:12 +08:00
|
|
|
|
{{ legacyT(status.label) }}
|
2026-05-01 02:14:49 +08:00
|
|
|
|
</SelectItem>
|
|
|
|
|
|
</SelectContent>
|
|
|
|
|
|
</Select>
|
|
|
|
|
|
</div>
|
2026-02-14 20:06:38 +08:00
|
|
|
|
|
|
|
|
|
|
<!-- API 格式筛选 -->
|
2026-09-07 14:13:59 +08:00
|
|
|
|
<div :class="{ 'xl:hidden': !cardView }">
|
2026-05-01 02:14:49 +08:00
|
|
|
|
<Select
|
|
|
|
|
|
:model-value="filterApiFormat"
|
|
|
|
|
|
@update:model-value="$emit('update:filterApiFormat', $event)"
|
|
|
|
|
|
>
|
|
|
|
|
|
<SelectTrigger class="w-20 sm:w-28 h-8 text-xs border-border/60">
|
2026-06-30 14:14:12 +08:00
|
|
|
|
<SelectValue :placeholder="legacyT('全部格式')" />
|
2026-05-01 02:14:49 +08:00
|
|
|
|
</SelectTrigger>
|
|
|
|
|
|
<SelectContent>
|
|
|
|
|
|
<SelectItem
|
|
|
|
|
|
v-for="fmt in apiFormatFilters"
|
|
|
|
|
|
:key="fmt.value"
|
|
|
|
|
|
:value="fmt.value"
|
|
|
|
|
|
>
|
2026-06-30 14:14:12 +08:00
|
|
|
|
{{ legacyT(fmt.label) }}
|
2026-05-01 02:14:49 +08:00
|
|
|
|
</SelectItem>
|
|
|
|
|
|
</SelectContent>
|
|
|
|
|
|
</Select>
|
|
|
|
|
|
</div>
|
2026-02-14 20:06:38 +08:00
|
|
|
|
|
|
|
|
|
|
<!-- 模型筛选 -->
|
2026-09-07 14:13:59 +08:00
|
|
|
|
<div :class="{ 'xl:hidden': !cardView }">
|
2026-05-01 02:14:49 +08:00
|
|
|
|
<Select
|
|
|
|
|
|
:model-value="filterModel"
|
|
|
|
|
|
@update:model-value="$emit('update:filterModel', $event)"
|
|
|
|
|
|
>
|
|
|
|
|
|
<SelectTrigger class="w-20 sm:w-36 h-8 text-xs border-border/60">
|
2026-06-30 14:14:12 +08:00
|
|
|
|
<SelectValue :placeholder="legacyT('全部模型')" />
|
2026-05-01 02:14:49 +08:00
|
|
|
|
</SelectTrigger>
|
|
|
|
|
|
<SelectContent>
|
|
|
|
|
|
<SelectItem
|
|
|
|
|
|
v-for="model in modelFilters"
|
|
|
|
|
|
:key="model.value"
|
|
|
|
|
|
:value="model.value"
|
|
|
|
|
|
>
|
2026-06-30 14:14:12 +08:00
|
|
|
|
{{ legacyT(model.label) }}
|
2026-05-01 02:14:49 +08:00
|
|
|
|
</SelectItem>
|
|
|
|
|
|
</SelectContent>
|
|
|
|
|
|
</Select>
|
|
|
|
|
|
</div>
|
2026-02-14 20:06:38 +08:00
|
|
|
|
|
|
|
|
|
|
<!-- 重置筛选 -->
|
|
|
|
|
|
<Button
|
|
|
|
|
|
v-if="hasActiveFilters"
|
|
|
|
|
|
variant="ghost"
|
|
|
|
|
|
size="icon"
|
|
|
|
|
|
class="h-8 w-8"
|
2026-06-30 14:14:12 +08:00
|
|
|
|
:title="legacyT('重置筛选')"
|
2026-02-14 20:06:38 +08:00
|
|
|
|
@click="$emit('resetFilters')"
|
|
|
|
|
|
>
|
|
|
|
|
|
<FilterX class="w-3.5 h-3.5" />
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="hidden sm:block h-4 w-px bg-border" />
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 操作按钮 -->
|
2026-06-07 22:57:02 +08:00
|
|
|
|
<Button
|
|
|
|
|
|
variant="ghost"
|
|
|
|
|
|
size="icon"
|
|
|
|
|
|
class="h-8 w-8"
|
2026-06-30 14:14:12 +08:00
|
|
|
|
:title="legacyT('批量处理提供商')"
|
2026-06-07 22:57:02 +08:00
|
|
|
|
:disabled="loading"
|
|
|
|
|
|
@click="$emit('batchProcess')"
|
|
|
|
|
|
>
|
|
|
|
|
|
<Users class="w-3.5 h-3.5" />
|
|
|
|
|
|
</Button>
|
2026-02-14 20:06:38 +08:00
|
|
|
|
<Button
|
|
|
|
|
|
variant="ghost"
|
|
|
|
|
|
size="icon"
|
|
|
|
|
|
class="h-8 w-8"
|
2026-06-30 14:14:12 +08:00
|
|
|
|
:title="legacyT('新增提供商')"
|
2026-02-14 20:06:38 +08:00
|
|
|
|
@click="$emit('addProvider')"
|
|
|
|
|
|
>
|
|
|
|
|
|
<Plus class="w-3.5 h-3.5" />
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
<RefreshButton
|
|
|
|
|
|
:loading="loading"
|
|
|
|
|
|
@click="$emit('refresh')"
|
|
|
|
|
|
/>
|
2026-09-07 14:13:59 +08:00
|
|
|
|
<Button
|
|
|
|
|
|
variant="ghost"
|
|
|
|
|
|
size="icon"
|
|
|
|
|
|
class="h-8 w-8"
|
|
|
|
|
|
:class="{ 'bg-primary/10 text-primary hover:bg-primary/15 hover:text-primary': cardView }"
|
|
|
|
|
|
:title="legacyT(cardView ? '切换到列表视图' : '切换到卡片视图')"
|
|
|
|
|
|
:aria-label="legacyT('卡片视图')"
|
|
|
|
|
|
:aria-pressed="cardView"
|
|
|
|
|
|
@click="$emit('toggleView')"
|
|
|
|
|
|
>
|
|
|
|
|
|
<List
|
|
|
|
|
|
v-if="cardView"
|
|
|
|
|
|
class="w-3.5 h-3.5"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<LayoutGrid
|
|
|
|
|
|
v-else
|
|
|
|
|
|
class="w-3.5 h-3.5"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Button>
|
2026-02-14 20:06:38 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
2026-09-07 14:13:59 +08:00
|
|
|
|
import { Search, Plus, FilterX, Users, LayoutGrid, List } from 'lucide-vue-next'
|
2026-02-14 20:06:38 +08:00
|
|
|
|
import Button from '@/components/ui/button.vue'
|
|
|
|
|
|
import Input from '@/components/ui/input.vue'
|
|
|
|
|
|
import Select from '@/components/ui/select.vue'
|
|
|
|
|
|
import SelectTrigger from '@/components/ui/select-trigger.vue'
|
|
|
|
|
|
import SelectValue from '@/components/ui/select-value.vue'
|
|
|
|
|
|
import SelectContent from '@/components/ui/select-content.vue'
|
|
|
|
|
|
import SelectItem from '@/components/ui/select-item.vue'
|
|
|
|
|
|
import RefreshButton from '@/components/ui/refresh-button.vue'
|
|
|
|
|
|
import type { FilterOption } from '@/features/providers/composables/useProviderFilters'
|
2026-06-30 14:14:12 +08:00
|
|
|
|
import { useI18n } from '@/i18n'
|
2026-02-14 20:06:38 +08:00
|
|
|
|
|
|
|
|
|
|
defineProps<{
|
|
|
|
|
|
searchQuery: string
|
|
|
|
|
|
filterStatus: string
|
|
|
|
|
|
filterApiFormat: string
|
|
|
|
|
|
filterModel: string
|
|
|
|
|
|
statusFilters: FilterOption[]
|
|
|
|
|
|
apiFormatFilters: FilterOption[]
|
|
|
|
|
|
modelFilters: FilterOption[]
|
|
|
|
|
|
hasActiveFilters: boolean
|
|
|
|
|
|
loading: boolean
|
2026-09-07 14:13:59 +08:00
|
|
|
|
cardView: boolean
|
2026-02-14 20:06:38 +08:00
|
|
|
|
}>()
|
|
|
|
|
|
|
|
|
|
|
|
defineEmits<{
|
|
|
|
|
|
'update:searchQuery': [value: string]
|
|
|
|
|
|
'update:filterStatus': [value: string]
|
|
|
|
|
|
'update:filterApiFormat': [value: string]
|
|
|
|
|
|
'update:filterModel': [value: string]
|
|
|
|
|
|
'resetFilters': []
|
2026-06-07 22:57:02 +08:00
|
|
|
|
'batchProcess': []
|
2026-02-14 20:06:38 +08:00
|
|
|
|
'addProvider': []
|
|
|
|
|
|
'refresh': []
|
2026-09-07 14:13:59 +08:00
|
|
|
|
'toggleView': []
|
2026-02-14 20:06:38 +08:00
|
|
|
|
}>()
|
2026-06-30 14:14:12 +08:00
|
|
|
|
|
|
|
|
|
|
const { legacyT } = useI18n()
|
2026-02-14 20:06:38 +08:00
|
|
|
|
</script>
|