diff --git a/src/components/assistant/AssistantResponseCard.vue b/src/components/assistant/AssistantResponseCard.vue index fc4b033..401f1ad 100644 --- a/src/components/assistant/AssistantResponseCard.vue +++ b/src/components/assistant/AssistantResponseCard.vue @@ -403,14 +403,6 @@ function generateReport() { > 查看标准详情 - - 📌 收藏方案 - -import { computed, onMounted, ref, watch } from "vue"; +import { computed, onBeforeUnmount, onMounted, ref, watch } from "vue"; import { useRoute, useRouter } from "vue-router"; import { fetchSupplierOptions } from "@/api/suppliers"; @@ -10,6 +10,11 @@ const router = useRouter(); const route = useRoute(); const supplierNames = ref([]); const selected = ref(""); +const supplierQuery = ref(""); +const supplierResults = ref([]); +const supplierDropdownOpen = ref(false); +const supplierSearching = ref(false); +let supplierSearchTimer: ReturnType | undefined; const profile = ref(null); const loading = ref(false); const error = ref(""); @@ -89,11 +94,64 @@ async function loadOptions() { typeof route.query.supplier === "string" ? route.query.supplier : (response.data.data?.defaultSupplier ?? supplierNames.value[0] ?? ""); + supplierQuery.value = selected.value; + supplierResults.value = supplierNames.value; if (selected.value) await loadProfile(); } catch { error.value = "供应商列表加载失败,请重试。"; } } + +function openSupplierDropdown() { + supplierDropdownOpen.value = true; + if (!supplierQuery.value || supplierQuery.value === selected.value) { + supplierResults.value = supplierNames.value; + } +} + +function searchSuppliers(value: string) { + if (supplierSearchTimer) clearTimeout(supplierSearchTimer); + const keyword = value.trim(); + if (!keyword) { + supplierResults.value = supplierNames.value; + supplierSearching.value = false; + return; + } + const local = supplierNames.value.filter((name) => name.includes(keyword)); + supplierResults.value = local; + supplierSearching.value = true; + supplierSearchTimer = setTimeout(async () => { + try { + const response = await fetchSupplierOptions(keyword); + supplierResults.value = + response.data.data?.items.map((item) => item.name) ?? []; + } catch { + supplierResults.value = local; + } finally { + supplierSearching.value = false; + } + }, 180); +} + +function onSupplierInput(event: Event) { + supplierQuery.value = (event.target as HTMLInputElement).value; + supplierDropdownOpen.value = true; + searchSuppliers(supplierQuery.value); +} + +function selectSupplier(name: string) { + selected.value = name; + supplierQuery.value = name; + supplierDropdownOpen.value = false; + chooseSupplier(); +} + +function closeSupplierDropdown() { + window.setTimeout(() => { + supplierDropdownOpen.value = false; + if (selected.value) supplierQuery.value = selected.value; + }, 120); +} async function loadProfile() { if (!selected.value) return; loading.value = true; @@ -116,11 +174,15 @@ function chooseSupplier() { void loadProfile(); } onMounted(() => void loadOptions()); +onBeforeUnmount(() => { + if (supplierSearchTimer) clearTimeout(supplierSearchTimer); +}); watch( () => route.query.supplier, (value) => { if (typeof value === "string" && value !== selected.value) { selected.value = value; + supplierQuery.value = value; void loadProfile(); } }, @@ -132,16 +194,46 @@ watch( 供应商深度画像 - - - {{ name }} - - + + + + + {{ name }} + + 搜索中… + 未找到匹配供应商 + + {{ tierLabel }} @@ -418,6 +510,8 @@ watch( font-weight: 650; } .supplier-select { + width: 180px; + min-height: 34px; padding: 7px 14px; border: 1px solid #e4e4e2; border-radius: 5px; @@ -428,6 +522,47 @@ watch( font-size: 13px; cursor: pointer; } +.supplier-combobox { + position: relative; + z-index: 5; +} +.supplier-combobox .supplier-select { + cursor: text; +} +.supplier-options { + position: absolute; + top: calc(100% + 4px); + right: 0; + left: 0; + max-height: 260px; + overflow-y: auto; + border: 1px solid var(--color-border-strong); + border-radius: 5px; + padding: 4px 0; + background: #fff; + box-shadow: var(--shadow-lg); +} +.supplier-option { + display: block; + width: 100%; + border: 0; + padding: 8px 12px; + background: #fff; + color: var(--color-text-secondary); + font-size: 12px; + text-align: left; +} +.supplier-option:hover, +.supplier-option.active { + background: var(--color-accent-subtle); + color: var(--color-accent); +} +.supplier-option-state { + display: block; + padding: 9px 12px; + color: var(--color-text-faint); + font-size: 11px; +} .version-note { color: #999; font-size: 11px; @@ -700,6 +835,13 @@ watch( order: 3; width: 100%; } + .supplier-combobox { + order: 3; + width: 100%; + } + .supplier-combobox .supplier-select { + width: 100%; + } .version-note { width: 100%; }