Files
shanxia2.0/web-admin/src/components/business/db/DbCrmCustomerSelect.vue
T
2026-08-04 14:02:01 +08:00

134 lines
3.1 KiB
Vue

<template>
<el-select
v-model="model"
:placeholder="placeholder"
filterable
remote
:remote-method="searchRemote"
:loading="loading"
:allow-create="allowCreate"
:default-first-option="allowCreate"
clearable
style="width: 100%"
@focus="handleFocus"
>
<el-option
v-for="item in displayOptions"
:key="item.id"
:label="item.customerName"
:value="item.customerName"
>
<div class="db-crm-option">
<span>{{ item.customerName }}</span>
<span v-if="item.customerNo" class="db-crm-option__meta">{{ item.customerNo }}</span>
</div>
</el-option>
</el-select>
</template>
<script setup lang="ts">
import { fetchCustomerOptions } from '@/api/crm/customer'
defineOptions({ name: 'DbCrmCustomerSelect' })
const model = defineModel<string>({ default: '' })
withDefaults(
defineProps<{
placeholder?: string
allowCreate?: boolean
}>(),
{
placeholder: '请输入客户名称搜索',
allowCreate: true
}
)
interface CustomerOption {
id: string
customerName: string
customerNo?: string
}
const loading = ref(false)
const options = ref<CustomerOption[]>([])
const extractOptions = (res: unknown): CustomerOption[] => {
const unwrapped = (res as { data?: unknown })?.data ?? res
if (Array.isArray(unwrapped)) return unwrapped as CustomerOption[]
const payload = (unwrapped as { list?: CustomerOption[]; rows?: CustomerOption[] }) || {}
return payload.list || payload.rows || []
}
const loadDefault = async () => {
loading.value = true
try {
const res = await fetchCustomerOptions({ limit: 20 })
options.value = extractOptions(res)
} catch (error) {
console.error('加载 CRM 客户列表失败', error)
options.value = []
} finally {
loading.value = false
}
}
const searchRemote = async (query: string) => {
if (!query.trim()) {
await loadDefault()
return
}
loading.value = true
try {
const res = await fetchCustomerOptions({
keyword: query.trim(),
limit: 50
})
options.value = extractOptions(res)
} catch (error) {
console.error('搜索 CRM 客户失败', error)
options.value = []
} finally {
loading.value = false
}
}
const handleFocus = () => {
if (options.value.length === 0) {
loadDefault()
}
}
/** 编辑回显:历史往来单位若不在客户库,仍展示只读选项(禁止 allow-create 时) */
const displayOptions = computed(() => {
const current = model.value?.trim()
if (!current) return options.value
if (options.value.some((item) => item.customerName === current)) {
return options.value
}
return [
{
id: `legacy-${current}`,
customerName: current
},
...options.value
]
})
</script>
<style scoped lang="scss">
.db-crm-option {
display: flex;
justify-content: space-between;
align-items: center;
gap: 12px;
min-width: 0;
}
.db-crm-option__meta {
flex-shrink: 0;
font-size: 12px;
color: var(--text-muted);
}
</style>