134 lines
3.1 KiB
Vue
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>
|