Files
im-uniapp/components/hrm/EmployeePicker.vue
2026-04-17 12:09:43 +08:00

72 lines
3.6 KiB
Vue

<template>
<view v-if="visible" class="mask" @tap="close">
<view class="sheet" @tap.stop>
<view class="sheet-header">
<text class="sheet-title">{{ title }}</text>
<text class="sheet-close" @tap="close">关闭</text>
</view>
<input class="search" v-model="keyword" placeholder="搜索姓名/部门" />
<scroll-view class="list" scroll-y>
<view v-for="item in filteredList" :key="item.userId || item.id" class="list-item" @tap="select(item)">
<view class="list-main">
<view class="list-name">{{ getName(item) }}</view>
<view class="list-sub">{{ getDept(item) }}</view>
</view>
<view class="check" :class="isSelected(item) ? 'selected' : ''"></view>
</view>
</scroll-view>
<view class="footer">
<button class="btn ghost" @tap="close">取消</button>
<button v-if="multiple" class="btn primary" @tap="confirm">确定</button>
</view>
</view>
</view>
</template>
<script>
export default {
props: {
visible: Boolean,
title: { type: String, default: '选择人员' },
list: { type: Array, default: () => [] },
multiple: { type: Boolean, default: false },
value: { type: [Object, Array, null], default: null }
},
emits: ['update:visible', 'change', 'confirm'],
data() { return { keyword: '' } },
computed: {
filteredList() {
const kw = this.keyword.trim().toLowerCase()
if (!kw) return this.list
return this.list.filter(item => `${this.getName(item)} ${this.getDept(item)}`.toLowerCase().includes(kw))
}
},
methods: {
getName(item) { return item?.empName || item?.nickName || item?.userName || item?.realName || `员工${item?.userId || item?.id || ''}` },
getDept(item) { return item?.dept?.deptName || item?.deptName || '未分配部门' },
isSelected(item) {
if (!this.multiple) return this.value && String((this.value.userId || this.value.id)) === String(item.userId || item.id)
return Array.isArray(this.value) && this.value.some(v => String((v.userId || v.id)) === String(item.userId || item.id))
},
select(item) {
if (this.multiple) {
const arr = Array.isArray(this.value) ? [...this.value] : []
const id = String(item.userId || item.id)
const idx = arr.findIndex(v => String(v.userId || v.id) === id)
if (idx >= 0) arr.splice(idx, 1)
else arr.push(item)
this.$emit('change', arr)
return
}
this.$emit('change', item)
this.close()
},
confirm() { this.$emit('confirm'); this.close() },
close() { this.$emit('update:visible', false) }
}
}
</script>
<style scoped>
.mask{position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:1000;display:flex;align-items:flex-end}.sheet{width:100%;background:#fff;border-radius:24rpx 24rpx 0 0;padding:20rpx;box-sizing:border-box}.sheet-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16rpx}.sheet-title{font-size:30rpx;font-weight:800}.sheet-close{font-size:26rpx;color:#1677ff}.search{width:100%;box-sizing:border-box;padding:18rpx 20rpx;border:1rpx solid #e5e7eb;border-radius:16rpx;background:#f9fafb;font-size:26rpx;margin-bottom:16rpx}.list{max-height:60vh}.list-item{display:flex;justify-content:space-between;align-items:center;padding:18rpx 4rpx;border-bottom:1rpx solid #f3f4f6}.list-name{font-size:28rpx;font-weight:700}.list-sub{font-size:22rpx;color:#94a3b8;margin-top:4rpx}.check{width:28rpx;height:28rpx;border-radius:50%;border:2rpx solid #cbd5e1}.check.selected{background:#1677ff;border-color:#1677ff}.footer{display:flex;gap:12rpx;margin-top:16rpx}.btn{flex:1;border-radius:16rpx}.btn.ghost{background:#f3f4f6;color:#334155}.btn.primary{background:#1677ff;color:#fff}
</style>