Files
xk-doctor-wx/subPackages/sub_salesperson/components/PromoterPicker.vue
2026-06-18 13:49:43 +08:00

148 lines
4.9 KiB
Vue

<template>
<view class="picker-wrap">
<view class="promoter-picker" @click="onOpen">
<view v-if="selected" class="promoter-selected">
<image v-if="selected.avatar" :src="selected.avatar" class="avatar" mode="aspectFill" />
<view v-else class="avatar placeholder">{{ (selected.nick_name || '?').charAt(0) }}</view>
<view class="meta">
<text class="name">{{ selected.nick_name || '-' }}</text>
<text class="sub">{{ selectedSubText }}</text>
</view>
</view>
<text v-else class="placeholder-text">{{ placeholder }}</text>
<u-icon v-if="!disabled" name="arrow-right" color="#c0c4cc" size="28"></u-icon>
</view>
<drawer-page-container v-model="showPopup" title="选择业务员">
<view class="search-wrap">
<u-input
v-model="searchKeyword"
placeholder="搜索姓名、业务码、手机号"
:clearable="true"
border="surround"
/>
</view>
<scroll-view scroll-y class="sheet-scroll">
<view v-if="loading" class="empty">加载中...</view>
<view v-else-if="!filteredOptions.length" class="empty">无匹配业务员</view>
<view
v-for="item in filteredOptions"
:key="item.id"
class="option-item"
@click="onPick(item)"
>
<image v-if="item.avatar" :src="item.avatar" class="avatar" mode="aspectFill" />
<view v-else class="avatar placeholder">{{ (item.nick_name || '?').charAt(0) }}</view>
<view class="meta">
<text class="name">{{ item.nick_name || '-' }}</text>
<text class="sub">{{ item.code }} · {{ item.role_name || '业务员' }}</text>
<text v-if="item.phone" class="phone">{{ item.phone }}</text>
</view>
<u-icon v-if="value === item.code" name="checkmark" color="#6acdbb" size="32"></u-icon>
</view>
</scroll-view>
</drawer-page-container>
</view>
</template>
<script>
import DrawerPageContainer from '@/subPackages/sub_salesperson/components/DrawerPageContainer.vue'
function filterPromoterOptions(keyword, list) {
const q = String(keyword || '').trim().toLowerCase()
if (!q) return list
return list.filter((item) => {
const name = (item.nick_name || '').toLowerCase()
const code = (item.code || '').toLowerCase()
const phone = (item.phone || '').toLowerCase()
const role = (item.role_name || '').toLowerCase()
return name.includes(q) || code.includes(q) || phone.includes(q) || role.includes(q)
})
}
export default {
name: 'PromoterPicker',
components: { DrawerPageContainer },
props: {
value: { type: String, default: '' },
disabled: { type: Boolean, default: false },
placeholder: { type: String, default: '请选择业务员' },
options: { type: Array, default: () => [] },
loading: { type: Boolean, default: false },
},
data() {
return {
showPopup: false,
searchKeyword: '',
}
},
computed: {
selected() {
return this.options.find((o) => o.code === this.value) || null
},
filteredOptions() {
return filterPromoterOptions(this.searchKeyword, this.options)
},
selectedSubText() {
if (!this.selected) return ''
const parts = []
if (this.selected.code) parts.push(this.selected.code)
if (this.selected.phone) parts.push(this.selected.phone)
else if (this.selected.role_name) parts.push(this.selected.role_name)
return parts.join(' · ')
},
},
methods: {
onOpen() {
if (this.disabled) return
this.searchKeyword = ''
this.showPopup = true
},
onPick(item) {
this.$emit('input', item.code)
this.$emit('change', item)
this.showPopup = false
},
},
}
</script>
<style scoped>
.picker-wrap { width: 100%; }
.promoter-picker {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
min-height: 88rpx;
padding: 8rpx 0;
box-sizing: border-box;
}
.promoter-selected { display: flex; align-items: center; gap: 16rpx; flex: 1; min-width: 0; }
.avatar { width: 72rpx; height: 72rpx; border-radius: 50%; flex-shrink: 0; }
.avatar.placeholder {
background: #e8f7f4;
color: #6acdbb;
display: flex;
align-items: center;
justify-content: center;
font-size: 30rpx;
font-weight: 600;
}
.meta { flex: 1; min-width: 0; }
.name { display: block; font-size: 28rpx; color: #1d2129; }
.sub { display: block; font-size: 24rpx; color: #86909c; margin-top: 6rpx; }
.phone { display: block; font-size: 22rpx; color: #86909c; margin-top: 4rpx; }
.placeholder-text { font-size: 28rpx; color: #c0c4cc; flex: 1; }
.search-wrap { padding: 0 32rpx 16rpx; }
.sheet-scroll { max-height: 55vh; padding-bottom: 24rpx; }
.option-item {
display: flex;
align-items: center;
gap: 16rpx;
padding: 24rpx 32rpx;
border-bottom: 1rpx solid #f5f5f5;
}
.empty { text-align: center; color: #86909c; padding: 80rpx 0; font-size: 28rpx; }
</style>