3 changed files with 265 additions and 120 deletions
@ -0,0 +1,226 @@ |
|||
<template> |
|||
<el-autocomplete |
|||
class="school-auto-complete" |
|||
:value="value" |
|||
:fetch-suggestions="querySearchAsync" |
|||
:placeholder="placeholder" |
|||
:debounce="debounce" |
|||
:loading="loading" |
|||
@select="handleSelect" |
|||
@input="handleInput" |
|||
:clearable="clearable" |
|||
:size="size" |
|||
:disabled="disabled" |
|||
> |
|||
<!-- 自定义下拉选项 --> |
|||
<template #default="{ item }"> |
|||
<div class="flex-between school-option"> |
|||
<span>{{ item.name }}</span> |
|||
<img |
|||
v-if="showSelectedIcon && item.id === selectedSchoolId" |
|||
src="@/assets/site/dropdown_chose_ic.svg" |
|||
alt="selected" |
|||
/> |
|||
</div> |
|||
</template> |
|||
</el-autocomplete> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: 'SchoolAutoComplete', |
|||
|
|||
props: { |
|||
// 双向绑定的值(学校名称) |
|||
value: { |
|||
type: String, |
|||
default: '' |
|||
}, |
|||
// 选中的学校ID |
|||
selectedSchoolId: { |
|||
type: [String, Number], |
|||
default: null |
|||
}, |
|||
// 占位符 |
|||
placeholder: { |
|||
type: String, |
|||
default: '请输入学校名称' |
|||
}, |
|||
// 防抖延迟时间 |
|||
debounce: { |
|||
type: Number, |
|||
default: 300 |
|||
}, |
|||
// 是否显示清空按钮 |
|||
clearable: { |
|||
type: Boolean, |
|||
default: true |
|||
}, |
|||
// 输入框尺寸 |
|||
size: { |
|||
type: String, |
|||
default: 'medium' |
|||
}, |
|||
// 是否禁用 |
|||
disabled: { |
|||
type: Boolean, |
|||
default: false |
|||
}, |
|||
// 是否显示选中图标 |
|||
showSelectedIcon: { |
|||
type: Boolean, |
|||
default: true |
|||
} |
|||
}, |
|||
|
|||
data() { |
|||
return { |
|||
loading: false, |
|||
timeout: null, |
|||
lastSearchKeyword: '', |
|||
schoolList: [] |
|||
} |
|||
}, |
|||
|
|||
beforeDestroy() { |
|||
clearTimeout(this.timeout) |
|||
}, |
|||
|
|||
methods: { |
|||
/** |
|||
* 异步搜索学校 |
|||
* @param {string} queryString 搜索关键字 |
|||
* @param {Function} callback 回调函数 |
|||
*/ |
|||
async querySearchAsync(queryString, callback) { |
|||
const keyword = queryString.trim() |
|||
|
|||
// 如果搜索内容为空或与上次相同,直接返回 |
|||
if (!keyword || keyword === this.lastSearchKeyword) { |
|||
callback([]) |
|||
return |
|||
} |
|||
|
|||
this.lastSearchKeyword = keyword |
|||
this.loading = true |
|||
|
|||
// 使用防抖 |
|||
clearTimeout(this.timeout) |
|||
this.timeout = setTimeout(async () => { |
|||
try { |
|||
const schools = await this.searchSchools(keyword) |
|||
this.schoolList = schools |
|||
callback(schools) |
|||
} catch (error) { |
|||
console.error('搜索学校失败:', error) |
|||
callback([]) |
|||
} finally { |
|||
this.loading = false |
|||
} |
|||
}, this.debounce) |
|||
}, |
|||
|
|||
/** |
|||
* 搜索学校API调用 |
|||
* @param {string} keyword 搜索关键字 |
|||
* @returns {Promise<Array>} 学校列表 |
|||
*/ |
|||
async searchSchools(keyword) { |
|||
try { |
|||
const response = await this.$http('POST', '/supernew/ajax_get_paiban_schools', { |
|||
keyword |
|||
}) |
|||
|
|||
if (response.status && response.data) { |
|||
return response.data |
|||
} |
|||
return [] |
|||
} catch (error) { |
|||
this.$message.error('搜索学校列表失败') |
|||
throw error |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 处理选择事件 |
|||
* @param {Object} item 选中的学校对象 |
|||
*/ |
|||
handleSelect(item) { |
|||
// 派发选中事件 |
|||
this.$emit('select', item) |
|||
// 更新选中的学校ID |
|||
this.$emit('update:selectedSchoolId', item.id) |
|||
// 更新输入框显示的值 |
|||
this.$emit('input', item.name) |
|||
this.$emit('change', item) |
|||
}, |
|||
|
|||
/** |
|||
* 处理输入事件 |
|||
* @param {string} value 输入的值 |
|||
*/ |
|||
handleInput(value) { |
|||
this.$emit('input', value) |
|||
// 如果输入框被清空,触发清空事件 |
|||
if (!value) { |
|||
this.$emit('clear') |
|||
this.$emit('update:selectedSchoolId', null) |
|||
this.lastSearchKeyword = '' |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 手动设置选中的学校 |
|||
* @param {Object} school 学校对象 |
|||
*/ |
|||
setSelectedSchool(school) { |
|||
if (school && school.id && school.name) { |
|||
this.$emit('input', school.name) |
|||
this.$emit('update:selectedSchoolId', school.id) |
|||
this.$emit('select', school) |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 清空选择 |
|||
*/ |
|||
clear() { |
|||
this.$emit('input', '') |
|||
this.$emit('update:selectedSchoolId', null) |
|||
this.$emit('clear') |
|||
this.lastSearchKeyword = '' |
|||
}, |
|||
|
|||
/** |
|||
* 手动触发搜索 |
|||
* @param {string} keyword 搜索关键字 |
|||
* @returns {Promise<Array>} 学校列表 |
|||
*/ |
|||
async triggerSearch(keyword) { |
|||
return await this.searchSchools(keyword || this.value) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.school-auto-complete { |
|||
width: 100%; |
|||
} |
|||
|
|||
.school-option { |
|||
width: 100%; |
|||
span { |
|||
flex: 1; |
|||
overflow: hidden; |
|||
text-overflow: ellipsis; |
|||
white-space: nowrap; |
|||
} |
|||
|
|||
img { |
|||
width: 16px; |
|||
height: 16px; |
|||
margin-left: 8px; |
|||
} |
|||
} |
|||
</style> |
|||
Loading…
Reference in new issue