Compare commits
1 Commits
master
...
styleCommo
| Author | SHA1 | Date |
|---|---|---|
|
|
2285163265 | 2 weeks ago |
3 changed files with 667 additions and 353 deletions
@ -0,0 +1,247 @@ |
|||||
|
<template> |
||||
|
<el-autocomplete |
||||
|
class="school-auto-complete" |
||||
|
:value="value" |
||||
|
:fetch-suggestions="querySearchAsync" |
||||
|
:placeholder="placeholder" |
||||
|
:debounce="debounce" |
||||
|
:loading="loading" |
||||
|
@select="handleSelect" |
||||
|
@input="handleInput" |
||||
|
@clear="handleManualClear" |
||||
|
: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: { |
||||
|
url: { |
||||
|
type: String, |
||||
|
default: '' |
||||
|
}, |
||||
|
// 双向绑定的值(学校名称) |
||||
|
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: [], |
||||
|
// 新增:记录最后一次有效选择 |
||||
|
lastValidSelection: null |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
mounted() { |
||||
|
// 初始化时记录当前选择 |
||||
|
if (this.selectedSchoolId && this.value) { |
||||
|
this.lastValidSelection = { |
||||
|
id: this.selectedSchoolId, |
||||
|
name: this.value |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
beforeDestroy() { |
||||
|
clearTimeout(this.timeout) |
||||
|
}, |
||||
|
|
||||
|
methods: { |
||||
|
/** |
||||
|
* 异步搜索学校 |
||||
|
*/ |
||||
|
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调用 |
||||
|
*/ |
||||
|
async searchSchools(keyword) { |
||||
|
try { |
||||
|
const response = await this.$http('POST', this.url, { |
||||
|
keyword |
||||
|
}) |
||||
|
|
||||
|
if (response.status && response.data) { |
||||
|
return response.data |
||||
|
} |
||||
|
return [] |
||||
|
} catch (error) { |
||||
|
this.$message.error('搜索学校列表失败') |
||||
|
throw error |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 处理选择事件 |
||||
|
*/ |
||||
|
handleSelect(item) { |
||||
|
console.log('选中学校:', item) |
||||
|
|
||||
|
// 更新记录 |
||||
|
this.lastValidSelection = { |
||||
|
id: item.id, |
||||
|
name: item.name |
||||
|
} |
||||
|
|
||||
|
this.$emit('select', item) |
||||
|
this.$emit('update:selectedSchoolId', item.id) |
||||
|
this.$emit('input', item.name) |
||||
|
this.$emit('change', item) |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 处理输入事件 - 安全版本 |
||||
|
*/ |
||||
|
handleInput(value) { |
||||
|
console.log('输入变化:', value, '当前选中:', this.selectedSchoolId) |
||||
|
|
||||
|
// 只更新显示的值 |
||||
|
this.$emit('input', value) |
||||
|
|
||||
|
// 重要:这里不自动触发清空 |
||||
|
// 清空只会在 handleManualClear 中触发 |
||||
|
}, |
||||
|
handleManualClear() { |
||||
|
console.log('用户手动清空') |
||||
|
this.clearSelection() |
||||
|
}, |
||||
|
clearSelection() { |
||||
|
console.log('执行清空操作') |
||||
|
this.$emit('input', '') |
||||
|
this.$emit('update:selectedSchoolId', null) |
||||
|
this.$emit('clear') |
||||
|
this.lastSearchKeyword = '' |
||||
|
this.lastValidSelection = null |
||||
|
}, |
||||
|
setSelectedSchool(school) { |
||||
|
if (school && school.id && school.name) { |
||||
|
this.lastValidSelection = { |
||||
|
id: school.id, |
||||
|
name: school.name |
||||
|
} |
||||
|
this.$emit('input', school.name) |
||||
|
this.$emit('update:selectedSchoolId', school.id) |
||||
|
this.$emit('select', school) |
||||
|
} |
||||
|
}, |
||||
|
clear() { |
||||
|
this.clearSelection() |
||||
|
}, |
||||
|
|
||||
|
async triggerSearch(keyword) { |
||||
|
return await this.searchSchools(keyword || this.value) |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 恢复上一次的有效选择 |
||||
|
*/ |
||||
|
restoreLastSelection() { |
||||
|
if (this.lastValidSelection) { |
||||
|
this.setSelectedSchool(this.lastValidSelection) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</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> |
||||
File diff suppressed because it is too large
Loading…
Reference in new issue