200 lines
4.9 KiB
Vue
200 lines
4.9 KiB
Vue
<template>
|
|
<u-popup v-model="visible" mode="bottom" :safe-area-inset-bottom="true" border-radius="16">
|
|
<view class="search-select" :style="{ maxHeight: panelMaxHeight + 'px' }">
|
|
<view class="search-select__bar">
|
|
<text class="search-select__title">{{ title }}</text>
|
|
<text class="search-select__cancel" @click="visible = false">取消</text>
|
|
</view>
|
|
<view class="search-select__search">
|
|
<u-search v-model="keyword" :placeholder="placeholder" :show-action="false" />
|
|
</view>
|
|
<scroll-view
|
|
scroll-y
|
|
class="search-select__list"
|
|
:style="{ height: listHeight + 'px' }"
|
|
:enable-back-to-top="false"
|
|
>
|
|
<view v-if="!filteredList.length" class="search-select__empty">暂无匹配数据</view>
|
|
<view
|
|
v-for="item in filteredList"
|
|
:key="String(item.value)"
|
|
class="search-select__item"
|
|
:class="{ 'is-selected': multiple && isPicked(item) }"
|
|
@click="onItemClick(item)"
|
|
>
|
|
<text class="search-select__item-label">{{ item.label }}</text>
|
|
<text v-if="multiple && isPicked(item)" class="search-select__check">已选</text>
|
|
</view>
|
|
</scroll-view>
|
|
<view v-if="multiple" class="search-select__footer">
|
|
<view class="search-select__ok" @click="confirmMultiple">确定</view>
|
|
</view>
|
|
</view>
|
|
</u-popup>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
props: {
|
|
show: { type: Boolean, default: false },
|
|
title: { type: String, default: '请选择' },
|
|
placeholder: { type: String, default: '请输入名称搜索' },
|
|
list: { type: Array, default: () => [] },
|
|
multiple: { type: Boolean, default: false },
|
|
selected: { type: Array, default: () => [] },
|
|
},
|
|
data() {
|
|
return {
|
|
keyword: '',
|
|
panelMaxHeight: 520,
|
|
listHeight: 360,
|
|
picked: [],
|
|
};
|
|
},
|
|
computed: {
|
|
visible: {
|
|
get() { return this.show; },
|
|
set(val) { this.$emit('update:show', val); },
|
|
},
|
|
filteredList() {
|
|
const keyword = (this.keyword || '').trim().toLowerCase();
|
|
if (!keyword) return this.list;
|
|
return this.list.filter((item) => String(item.label || '').toLowerCase().includes(keyword));
|
|
},
|
|
},
|
|
watch: {
|
|
show(val) {
|
|
if (val) {
|
|
this.keyword = '';
|
|
this.picked = (this.selected || []).map((item) => String(item));
|
|
this.calcHeight();
|
|
}
|
|
},
|
|
},
|
|
mounted() {
|
|
this.calcHeight();
|
|
},
|
|
methods: {
|
|
calcHeight() {
|
|
try {
|
|
const sys = uni.getSystemInfoSync();
|
|
const winH = sys.windowHeight || 600;
|
|
// 弹层约占屏高 65%,列表为弹层去掉标题+搜索后的剩余高度
|
|
this.panelMaxHeight = Math.floor(winH * 0.65);
|
|
const chrome = this.multiple ? 230 : 140;
|
|
this.listHeight = Math.max(220, this.panelMaxHeight - chrome);
|
|
} catch (e) {
|
|
this.panelMaxHeight = 520;
|
|
this.listHeight = this.multiple ? 280 : 360;
|
|
}
|
|
},
|
|
isPicked(item) {
|
|
return this.picked.includes(String(item.value));
|
|
},
|
|
onItemClick(item) {
|
|
if (!this.multiple) {
|
|
this.confirm(item);
|
|
return;
|
|
}
|
|
const key = String(item.value);
|
|
if (this.picked.includes(key)) {
|
|
this.picked = this.picked.filter((value) => value !== key);
|
|
return;
|
|
}
|
|
this.picked = this.picked.concat(key);
|
|
},
|
|
confirm(item) {
|
|
this.visible = false;
|
|
this.$emit('confirm', item);
|
|
},
|
|
confirmMultiple() {
|
|
const selected = (this.list || []).filter((item) => this.isPicked(item));
|
|
this.visible = false;
|
|
this.$emit('confirm', selected);
|
|
},
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
@import '@/common/pda-typography.scss';
|
|
|
|
.search-select {
|
|
background: #fff;
|
|
padding-bottom: 20rpx;
|
|
box-sizing: border-box;
|
|
display: flex;
|
|
flex-direction: column;
|
|
overflow: hidden;
|
|
}
|
|
.search-select__bar {
|
|
flex-shrink: 0;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 24rpx 30rpx 12rpx;
|
|
}
|
|
.search-select__title {
|
|
font-size: $pda-font-popup-title;
|
|
font-weight: bold;
|
|
color: #202328;
|
|
}
|
|
.search-select__cancel {
|
|
font-size: $pda-font-popup-sub;
|
|
color: #888;
|
|
}
|
|
.search-select__search {
|
|
flex-shrink: 0;
|
|
padding: 0 24rpx 12rpx;
|
|
}
|
|
.search-select__list {
|
|
width: 100%;
|
|
box-sizing: border-box;
|
|
}
|
|
.search-select__empty {
|
|
padding: 80rpx 0;
|
|
text-align: center;
|
|
color: #999;
|
|
font-size: $pda-font-popup-sub;
|
|
}
|
|
.search-select__item {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
min-height: $pda-row-min-height;
|
|
padding: 20rpx 30rpx;
|
|
box-sizing: border-box;
|
|
font-size: $pda-font-popup-item;
|
|
color: #202328;
|
|
border-bottom: 1px solid #f2f2f2;
|
|
}
|
|
.search-select__item-label {
|
|
flex: 1;
|
|
min-width: 0;
|
|
font-size: $pda-font-popup-item;
|
|
color: #202328;
|
|
}
|
|
.search-select__item.is-selected .search-select__item-label {
|
|
color: #2f78e6;
|
|
}
|
|
.search-select__check {
|
|
flex-shrink: 0;
|
|
margin-left: 16rpx;
|
|
font-size: $pda-font-action;
|
|
color: #2f78e6;
|
|
}
|
|
.search-select__footer {
|
|
flex-shrink: 0;
|
|
padding: 16rpx 30rpx 8rpx;
|
|
}
|
|
.search-select__ok {
|
|
height: $pda-button-height;
|
|
line-height: $pda-button-height;
|
|
text-align: center;
|
|
font-size: $pda-font-button;
|
|
color: #fff;
|
|
background: #2979ff;
|
|
border-radius: 46rpx;
|
|
}
|
|
</style>
|