99 lines
4.4 KiB
Vue
99 lines
4.4 KiB
Vue
<template>
|
||
<div class="h5-user-select">
|
||
<van-field v-bind="$attrs" :value="displayName" readonly clickable is-link @click="open"></van-field>
|
||
<van-popup v-model="visible" position="bottom" round get-container="body" class="h5-user-select-popup">
|
||
<div class="h5-user-select-popup__header">
|
||
<van-button native-type="button" type="default" size="small" @click="visible = false">取消</van-button>
|
||
<strong>选择慰问对象</strong>
|
||
<van-button native-type="button" type="info" size="small" :disabled="!pendingUser" @click="confirm">确认</van-button>
|
||
</div>
|
||
<van-search v-model="keyword" placeholder="请输入姓名或工号查询" @input="scheduleSearch" @search="search" @clear="search"></van-search>
|
||
<div class="h5-user-select-popup__list">
|
||
<div v-if="loading" class="h5-user-select-popup__status"><van-loading size="24px">加载中</van-loading></div>
|
||
<div v-else-if="error" class="h5-user-select-popup__status"><span class="h5-user-select-popup__error">{{ error }}</span><van-button native-type="button" size="small" @click="search">重新加载</van-button></div>
|
||
<van-empty v-else-if="!options.length" description="未找到本工会人员"></van-empty>
|
||
<template v-else>
|
||
<van-cell v-for="person in options" :key="person.id" clickable
|
||
:class="{ 'h5-user-select-popup__selected': pendingUser && pendingUser.id === person.id }"
|
||
:title="person.userName + (person.loginName ? '(' + person.loginName + ')' : '')"
|
||
:label="[person.unitName, person.personType].filter(Boolean).join(' · ')"
|
||
@click="pendingUser = person">
|
||
<van-icon v-if="pendingUser && pendingUser.id === person.id" name="success" color="#1989fa"></van-icon>
|
||
</van-cell>
|
||
</template>
|
||
</div>
|
||
</van-popup>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
module.exports = {
|
||
inheritAttrs: false,
|
||
model: { prop: 'value', event: 'change' },
|
||
props: {
|
||
value: { type: String, default: '' },
|
||
displayName: { type: String, default: '' },
|
||
api: { type: String, required: true }
|
||
},
|
||
data() {
|
||
return { visible: false, keyword: '', options: [], pendingUser: null, loading: false, error: '', searchTimer: null, requestId: 0 }
|
||
},
|
||
beforeDestroy() {
|
||
clearTimeout(this.searchTimer)
|
||
this.requestId++
|
||
},
|
||
methods: {
|
||
open() {
|
||
this.keyword = ''
|
||
this.pendingUser = null
|
||
this.visible = true
|
||
this.search()
|
||
},
|
||
scheduleSearch() {
|
||
clearTimeout(this.searchTimer)
|
||
this.requestId++
|
||
this.pendingUser = null
|
||
this.loading = true
|
||
this.searchTimer = setTimeout(() => this.search(), 250)
|
||
},
|
||
async search() {
|
||
clearTimeout(this.searchTimer)
|
||
const requestId = ++this.requestId
|
||
this.loading = true
|
||
this.error = ''
|
||
this.pendingUser = null
|
||
try {
|
||
const result = await this.$axios.post(this.api, { keyword: this.keyword })
|
||
if (requestId !== this.requestId) return
|
||
if (result.code !== 0) throw new Error(result.msg || '人员加载失败')
|
||
this.options = result.data || []
|
||
} catch (error) {
|
||
if (requestId !== this.requestId) return
|
||
this.options = []
|
||
this.error = error.message || '人员加载失败'
|
||
} finally {
|
||
if (requestId === this.requestId) this.loading = false
|
||
}
|
||
},
|
||
confirm() {
|
||
if (!this.pendingUser) return
|
||
const person = this.pendingUser
|
||
this.$emit('change', person.id)
|
||
this.$emit('selected', person, person.id)
|
||
this.visible = false
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style>
|
||
.h5-user-select-popup { display: flex; flex-direction: column; height: 72vh; max-height: 640px; padding-bottom: env(safe-area-inset-bottom); box-sizing: border-box; }
|
||
.h5-user-select-popup__header { display: flex; align-items: center; justify-content: space-between; flex-shrink: 0; padding: 14px 16px; border-bottom: 1px solid #ebedf0; }
|
||
.h5-user-select-popup__header strong { font-size: 16px; color: #323233; }
|
||
.h5-user-select-popup__header .van-button { min-width: 56px; }
|
||
.h5-user-select-popup__list { flex: 1; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch; }
|
||
.h5-user-select-popup__selected { background: #edf6ff; }
|
||
.h5-user-select-popup__status { display: flex; align-items: center; justify-content: center; flex-direction: column; gap: 12px; padding: 40px 16px; }
|
||
.h5-user-select-popup__error { color: #ee0a24; }
|
||
</style>
|