将 StyleSelector 和 TextGeneratePopup 中的 Select 组件替换为 Combobox 组件,添加搜索过滤功能。 - StyleSelector.vue: 将 Select 组件替换为 Combobox,添加搜索关键词过滤和显示值处理 - TextGeneratePopup.vue: 将智能体选择器从 Select 升级为 Combobox,支持按名称搜索智能体 - 两个组件都添加了搜索输入框、过滤逻辑和空状态显示
This commit is contained in:
@@ -1,11 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<Select v-model="selectedId" @update:model-value="handleChange">
|
<Combobox v-model="selectedId" @update:model-value="handleChange">
|
||||||
<SelectTrigger class="w-full">
|
<ComboboxAnchor class="w-full">
|
||||||
<SelectValue :placeholder="placeholder" />
|
<ComboboxTrigger as-child>
|
||||||
</SelectTrigger>
|
<ComboboxInput
|
||||||
<SelectContent>
|
:placeholder="placeholder"
|
||||||
<SelectItem
|
v-model="searchKeyword"
|
||||||
v-for="item in allList"
|
:display-value="displayValue"
|
||||||
|
/>
|
||||||
|
</ComboboxTrigger>
|
||||||
|
</ComboboxAnchor>
|
||||||
|
<ComboboxList>
|
||||||
|
<ComboboxEmpty>未找到匹配项</ComboboxEmpty>
|
||||||
|
<ComboboxItem
|
||||||
|
v-for="item in filteredList"
|
||||||
:key="item.id"
|
:key="item.id"
|
||||||
:value="item.id"
|
:value="item.id"
|
||||||
>
|
>
|
||||||
@@ -14,14 +21,9 @@
|
|||||||
<span class="option-name">{{ item.name }}</span>
|
<span class="option-name">{{ item.name }}</span>
|
||||||
<span class="option-tag">{{ item.category || '其他' }}</span>
|
<span class="option-tag">{{ item.category || '其他' }}</span>
|
||||||
</div>
|
</div>
|
||||||
</SelectItem>
|
</ComboboxItem>
|
||||||
|
</ComboboxList>
|
||||||
<!-- 空状态 -->
|
</Combobox>
|
||||||
<div v-if="!loading && allList.length === 0" class="empty-text">
|
|
||||||
暂无可选项
|
|
||||||
</div>
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@@ -29,7 +31,15 @@ import { ref, computed, watch, onMounted } from 'vue'
|
|||||||
import { usePromptStore } from '@/stores/prompt'
|
import { usePromptStore } from '@/stores/prompt'
|
||||||
import { getJSON, setJSON } from '@/utils/storage'
|
import { getJSON, setJSON } from '@/utils/storage'
|
||||||
|
|
||||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
|
import {
|
||||||
|
Combobox,
|
||||||
|
ComboboxAnchor,
|
||||||
|
ComboboxEmpty,
|
||||||
|
ComboboxInput,
|
||||||
|
ComboboxItem,
|
||||||
|
ComboboxList,
|
||||||
|
ComboboxTrigger
|
||||||
|
} from '@/components/ui/combobox'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
modelValue: {
|
modelValue: {
|
||||||
@@ -52,10 +62,30 @@ const promptStore = usePromptStore()
|
|||||||
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const selectedId = ref(null)
|
const selectedId = ref(null)
|
||||||
|
const searchKeyword = ref('')
|
||||||
|
|
||||||
// 全部列表(来自 /ai/user-prompt/my-list)
|
// 全部列表(来自 /ai/user-prompt/my-list)
|
||||||
const allList = computed(() => promptStore.promptList || [])
|
const allList = computed(() => promptStore.promptList || [])
|
||||||
|
|
||||||
|
// 过滤后的列表
|
||||||
|
const filteredList = computed(() => {
|
||||||
|
if (!searchKeyword.value.trim()) {
|
||||||
|
return allList.value
|
||||||
|
}
|
||||||
|
const keyword = searchKeyword.value.toLowerCase()
|
||||||
|
return allList.value.filter(item =>
|
||||||
|
item.name?.toLowerCase().includes(keyword) ||
|
||||||
|
item.category?.toLowerCase().includes(keyword)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 显示选中项名称
|
||||||
|
const displayValue = (val) => {
|
||||||
|
if (!val) return ''
|
||||||
|
const item = allList.value.find(p => p.id === val)
|
||||||
|
return item?.name || ''
|
||||||
|
}
|
||||||
|
|
||||||
// 处理选择变化
|
// 处理选择变化
|
||||||
function handleChange(value) {
|
function handleChange(value) {
|
||||||
if (!value) {
|
if (!value) {
|
||||||
|
|||||||
@@ -25,13 +25,20 @@
|
|||||||
<!-- 智能体选择 -->
|
<!-- 智能体选择 -->
|
||||||
<div class="form-item">
|
<div class="form-item">
|
||||||
<label class="form-label">选择智能体</label>
|
<label class="form-label">选择智能体</label>
|
||||||
<Select v-model="selectedAgentId" :disabled="loadingAgents" class="agent-select">
|
<Combobox v-model="selectedAgentId" :disabled="loadingAgents">
|
||||||
<SelectTrigger class="agent-select-trigger">
|
<ComboboxAnchor class="agent-select-anchor">
|
||||||
<SelectValue :placeholder="loadingAgents ? '加载中...' : '请选择智能体'" />
|
<ComboboxTrigger as-child>
|
||||||
</SelectTrigger>
|
<ComboboxInput
|
||||||
<SelectContent>
|
:placeholder="loadingAgents ? '加载中...' : '搜索或选择智能体...'"
|
||||||
<SelectItem
|
v-model="searchKeyword"
|
||||||
v-for="agent in agentList"
|
:display-value="displayValue"
|
||||||
|
/>
|
||||||
|
</ComboboxTrigger>
|
||||||
|
</ComboboxAnchor>
|
||||||
|
<ComboboxList class="agent-combobox-list">
|
||||||
|
<ComboboxEmpty>未找到匹配的智能体</ComboboxEmpty>
|
||||||
|
<ComboboxItem
|
||||||
|
v-for="agent in filteredAgents"
|
||||||
:key="agent.id"
|
:key="agent.id"
|
||||||
:value="agent.id"
|
:value="agent.id"
|
||||||
>
|
>
|
||||||
@@ -39,9 +46,9 @@
|
|||||||
<img v-if="agent.icon" :src="agent.icon" class="agent-icon" />
|
<img v-if="agent.icon" :src="agent.icon" class="agent-icon" />
|
||||||
<span class="agent-name">{{ agent.agentName }}</span>
|
<span class="agent-name">{{ agent.agentName }}</span>
|
||||||
</div>
|
</div>
|
||||||
</SelectItem>
|
</ComboboxItem>
|
||||||
</SelectContent>
|
</ComboboxList>
|
||||||
</Select>
|
</Combobox>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 主题输入 -->
|
<!-- 主题输入 -->
|
||||||
@@ -89,12 +96,14 @@ import { ref, computed, watch, onUnmounted } from 'vue'
|
|||||||
import { Icon } from '@iconify/vue'
|
import { Icon } from '@iconify/vue'
|
||||||
import { toast } from 'vue-sonner'
|
import { toast } from 'vue-sonner'
|
||||||
import {
|
import {
|
||||||
Select,
|
Combobox,
|
||||||
SelectContent,
|
ComboboxAnchor,
|
||||||
SelectItem,
|
ComboboxEmpty,
|
||||||
SelectTrigger,
|
ComboboxInput,
|
||||||
SelectValue
|
ComboboxItem,
|
||||||
} from '@/components/ui/select'
|
ComboboxList,
|
||||||
|
ComboboxTrigger
|
||||||
|
} from '@/components/ui/combobox'
|
||||||
import { getAgentList, sendChatStream } from '@/api/agent'
|
import { getAgentList, sendChatStream } from '@/api/agent'
|
||||||
|
|
||||||
// Props
|
// Props
|
||||||
@@ -117,6 +126,7 @@ const selectedAgentId = ref<number | null>(null)
|
|||||||
const theme = ref('')
|
const theme = ref('')
|
||||||
const generatedText = ref('')
|
const generatedText = ref('')
|
||||||
const isGenerating = ref(false)
|
const isGenerating = ref(false)
|
||||||
|
const searchKeyword = ref('')
|
||||||
const abortController = ref<AbortController | null>(null)
|
const abortController = ref<AbortController | null>(null)
|
||||||
const popoverStyle = ref<Record<string, string>>({})
|
const popoverStyle = ref<Record<string, string>>({})
|
||||||
|
|
||||||
@@ -125,6 +135,24 @@ const canGenerate = computed(() => {
|
|||||||
return selectedAgentId.value && theme.value.trim().length > 0
|
return selectedAgentId.value && theme.value.trim().length > 0
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 过滤后的智能体列表
|
||||||
|
const filteredAgents = computed(() => {
|
||||||
|
if (!searchKeyword.value.trim()) {
|
||||||
|
return agentList.value
|
||||||
|
}
|
||||||
|
const keyword = searchKeyword.value.toLowerCase()
|
||||||
|
return agentList.value.filter(agent =>
|
||||||
|
agent.agentName?.toLowerCase().includes(keyword)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 显示选中智能体的名称
|
||||||
|
const displayValue = (val: number | null) => {
|
||||||
|
if (!val) return ''
|
||||||
|
const agent = agentList.value.find(a => a.id === val)
|
||||||
|
return agent?.agentName || ''
|
||||||
|
}
|
||||||
|
|
||||||
// 获取智能体列表
|
// 获取智能体列表
|
||||||
const fetchAgents = async () => {
|
const fetchAgents = async () => {
|
||||||
loadingAgents.value = true
|
loadingAgents.value = true
|
||||||
|
|||||||
Reference in New Issue
Block a user