2025-06-03 14:52:31 +08:00
|
|
|
|
<template>
|
|
|
|
|
<el-drawer
|
|
|
|
|
v-model="visible"
|
|
|
|
|
title="添加成员"
|
|
|
|
|
size="600px"
|
|
|
|
|
:destroy-on-close="true"
|
|
|
|
|
>
|
|
|
|
|
<div class="drawer-content">
|
2025-06-03 15:40:34 +08:00
|
|
|
|
<div class="search-box">
|
|
|
|
|
<el-input v-model="searchForm.name" placeholder="请输入姓名" clearable style="width: 180px; margin-right: 10px;" />
|
|
|
|
|
<el-input v-model="searchForm.mobile" placeholder="请输入手机号码" clearable style="width: 180px; margin-right: 10px;" />
|
|
|
|
|
</div>
|
2025-06-03 14:52:31 +08:00
|
|
|
|
<div class="drawer-header">
|
|
|
|
|
<span class="selected-count">已选择 {{ selectedMembers.length }}/5 人</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="table-container">
|
|
|
|
|
<el-table
|
2025-06-03 15:40:34 +08:00
|
|
|
|
:data="filteredMembers"
|
2025-06-03 14:52:31 +08:00
|
|
|
|
style="width: 100%"
|
|
|
|
|
@selection-change="handleSelectionChange"
|
|
|
|
|
>
|
|
|
|
|
<el-table-column type="selection" width="55" :selectable="isSelectable" />
|
|
|
|
|
<el-table-column label="姓名" prop="name" />
|
|
|
|
|
<el-table-column label="性别" prop="gender">
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
<el-tag :type="scope.row.gender === 'male' ? 'primary' : 'success'">
|
|
|
|
|
{{ scope.row.gender === 'male' ? '男' : '女' }}
|
|
|
|
|
</el-tag>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column label="年龄" prop="age" />
|
|
|
|
|
<el-table-column label="手机号码" prop="mobile" />
|
|
|
|
|
</el-table>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="drawer-footer">
|
|
|
|
|
<el-button @click="handleCancel">取 消</el-button>
|
|
|
|
|
<el-button type="primary" @click="handleConfirm" :disabled="selectedMembers.length === 0">
|
|
|
|
|
确 定
|
|
|
|
|
</el-button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</el-drawer>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script lang="ts" setup>
|
2025-06-03 15:40:34 +08:00
|
|
|
|
import { ref, computed } from 'vue'
|
2025-06-03 14:52:31 +08:00
|
|
|
|
|
|
|
|
|
interface FamilyMember {
|
|
|
|
|
id: number
|
|
|
|
|
name: string
|
|
|
|
|
mobile: string
|
|
|
|
|
age: number
|
|
|
|
|
gender: string
|
|
|
|
|
relation: string
|
|
|
|
|
address: string
|
|
|
|
|
createTime: string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const props = defineProps<{
|
|
|
|
|
modelValue: boolean
|
|
|
|
|
allMembers: FamilyMember[]
|
|
|
|
|
}>()
|
|
|
|
|
|
|
|
|
|
const emit = defineEmits<{
|
|
|
|
|
(e: 'update:modelValue', value: boolean): void
|
|
|
|
|
(e: 'confirm', members: FamilyMember[]): void
|
|
|
|
|
}>()
|
|
|
|
|
|
|
|
|
|
const visible = ref(props.modelValue)
|
|
|
|
|
const selectedMembers = ref<FamilyMember[]>([])
|
2025-06-03 15:40:34 +08:00
|
|
|
|
const searchForm = ref({
|
|
|
|
|
name: '',
|
|
|
|
|
mobile: ''
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// 过滤后的成员列表
|
|
|
|
|
const filteredMembers = computed(() => {
|
|
|
|
|
return props.allMembers.filter(member => {
|
|
|
|
|
const nameMatch = !searchForm.value.name || member.name.includes(searchForm.value.name)
|
|
|
|
|
const mobileMatch = !searchForm.value.mobile || member.mobile.includes(searchForm.value.mobile)
|
|
|
|
|
return nameMatch && mobileMatch
|
|
|
|
|
})
|
|
|
|
|
})
|
2025-06-03 14:52:31 +08:00
|
|
|
|
|
|
|
|
|
// 监听visible变化
|
|
|
|
|
watch(() => props.modelValue, (val) => {
|
|
|
|
|
visible.value = val
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// 监听visible变化并同步到父组件
|
|
|
|
|
watch(visible, (val) => {
|
|
|
|
|
emit('update:modelValue', val)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// 判断是否可选
|
|
|
|
|
const isSelectable = (row: FamilyMember) => {
|
|
|
|
|
return selectedMembers.value.length < 5 || selectedMembers.value.some(item => item.id === row.id)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 处理选择变化
|
|
|
|
|
const handleSelectionChange = (selection: FamilyMember[]) => {
|
|
|
|
|
if (selection.length > 5) {
|
|
|
|
|
// 如果超过5个,只保留前5个
|
|
|
|
|
selectedMembers.value = selection.slice(0, 5)
|
|
|
|
|
} else {
|
|
|
|
|
selectedMembers.value = selection
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 取消
|
|
|
|
|
const handleCancel = () => {
|
|
|
|
|
visible.value = false
|
|
|
|
|
selectedMembers.value = []
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 确认
|
|
|
|
|
const handleConfirm = () => {
|
|
|
|
|
emit('confirm', selectedMembers.value)
|
|
|
|
|
handleCancel()
|
|
|
|
|
}
|
2025-06-03 15:40:34 +08:00
|
|
|
|
|
|
|
|
|
// 搜索
|
|
|
|
|
const handleSearch = () => {
|
|
|
|
|
// 搜索逻辑已通过计算属性实现
|
|
|
|
|
}
|
2025-06-03 14:52:31 +08:00
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
2025-06-03 15:40:34 +08:00
|
|
|
|
.drawer-content {
|
|
|
|
|
height: 89%;
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.search-box {
|
|
|
|
|
padding: 16px;
|
|
|
|
|
border-bottom: 1px solid #e4e7ed;
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-03 14:52:31 +08:00
|
|
|
|
.drawer-header {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: flex-end;
|
2025-06-03 15:40:34 +08:00
|
|
|
|
padding: 10px 16px;
|
2025-06-03 14:52:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.selected-count {
|
|
|
|
|
color: #409EFF;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.table-container {
|
|
|
|
|
flex: 1;
|
|
|
|
|
overflow: auto;
|
2025-06-03 15:40:34 +08:00
|
|
|
|
height: calc(100vh - 250px);
|
|
|
|
|
margin: 0 16px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.el-table) {
|
|
|
|
|
height: 100%;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.el-table__header-wrapper) {
|
|
|
|
|
position: sticky;
|
|
|
|
|
top: 0;
|
|
|
|
|
z-index: 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.el-table__body-wrapper) {
|
|
|
|
|
overflow-y: auto;
|
2025-06-03 14:52:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.drawer-footer {
|
2025-06-03 15:40:34 +08:00
|
|
|
|
padding: 16px;
|
2025-06-03 14:52:31 +08:00
|
|
|
|
text-align: right;
|
|
|
|
|
border-top: 1px solid #e4e7ed;
|
|
|
|
|
}
|
|
|
|
|
</style>
|