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