Files
estate/src/components/Holder/index.vue
2026-06-22 08:14:35 +08:00

342 lines
11 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<slot v-if="$slots.default" />
<div v-else class="residentBox" @click="choiceResidentFun">
<div class="defaultbox" v-if="multipleSelection.length === 0">
<span>请选择</span>
<el-icon><Search /></el-icon>
</div>
<div v-else class="overflow-auto overflow-hidden w-full text-ellipsis text-nowrap">
<span>姓名{{ multipleSelection[0]?.name }}</span>
</div>
</div>
<el-dialog append-to-body v-model="dialog.dialogVisible" :title="dialog.dialogTitle" width="1050">
<nav class="flex flex-items-center mb-8">
<div class="flex flex-items-center mr-5 flex-1">
<div style="width: 120px">住户类型</div>
<el-select v-model="queryParams.ownerRelationship" placeholder="请选择" clearable>
<el-option v-for="dict in com_resident_relationship" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</div>
<div class="mr-5 flex-1">
<el-input clearable v-model="queryParams.name" placeholder="请输入住户姓名" />
</div>
<div>
<el-button type="primary" @click="getlist">查询</el-button>
<el-button @click="resetQuery">重置</el-button>
</div>
</nav>
<el-table ref="multipleTableRef" row-key="id" :data="tableData" border @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="序号" align="center" width="55" type="index" />
<el-table-column label="姓名" align="center" prop="name" />
<el-table-column label="类型" align="center" width="85" prop="type">
<template #default="{ row }">
<dict-tag :options="com_resident_type" :value="row.type" />
</template>
</el-table-column>
<el-table-column label="与业主关系" align="center" width="95" prop="ownerRelationship">
<template #default="{ row }">
<dict-tag :options="com_resident_relationship" :value="row.ownerRelationship" />
</template>
</el-table-column>
<el-table-column label="状态" align="center" width="85" prop="status">
<template #default="{ row }">
<dict-tag :options="com_certification_status" :value="row.status" />
</template>
</el-table-column>
<el-table-column label="证件号码" align="center" prop="idCard" />
<el-table-column label="手机号码" align="center" prop="phone" />
<el-table-column label="房间" show-overflow-tooltip align="center">
<template #default="{ row }">
{{ row.housePath }}
</template>
</el-table-column>
</el-table>
<template #footer>
<div class="dialog-footer flex flex-items-center flex-justify-between">
<pagination
style="margin-top: 0"
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getlist"
/>
<div>
<el-button @click="conback">退出</el-button>
<el-button type="primary" @click="confirm">确定</el-button>
</div>
</div>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { listResident } from '@/api/system/resident';
import { ResidentVO } from '@/api/system/resident/type';
import { getHousePathById } from '@/utils/house';
import { ref, nextTick, getCurrentInstance, ComponentInternalInstance, toRefs } from 'vue';
import { useHouseStore } from '@/store/modules/house';
const houseStore = useHouseStore();
const treedata = ref([]);
function init() {
houseStore.getCurrentVilageTreeHouse().then((res) => {
treedata.value = res;
});
}
init();
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { com_resident_type } = toRefs<any>(proxy?.useDict('com_resident_type'));
const { com_certification_status } = toRefs<any>(proxy?.useDict('com_certification_status'));
const { com_resident_relationship } = toRefs<any>(proxy?.useDict('com_resident_relationship'));
interface tableType extends ResidentVO {
housePath?: string;
}
// 触发方法
const emit = defineEmits<{
change: [value: string | number | (string | number)[]]; // 支持返回数组
}>();
// ✅ 正确写法:分开定义,避免类型问题
const props = defineProps<{
userid: string | number | string[] | number[];
isMultiple?: boolean;
returnvalue?: keyof tableType | '*';
}>();
// ✅ 手动设置默认值(替代 withDefaults
const isMultiple = computed(() => props.isMultiple ?? false);
const returnvalue = computed(() => props.returnvalue ?? '*'); // 👈 默认 userId
const { userid } = toRefs(props);
const dialog = ref({
dialogVisible: false,
dialogTitle: '选择住户'
});
const queryParams = ref({
pageNum: 1,
pageSize: 10,
ownerRelationship: '', // 👈 原来 null → 改成 ''
name: '',
status: '', // 👈 原来 null → 改成 ''
type: '', // 👈 原来 null → 改成 ''
houseId: null,
buildingId: null,
unitNo: null
});
const multipleTableRef = ref();
const tableData = ref<tableType[]>([]);
const multipleSelection = ref([]);
const total = ref(0);
const loading = ref(false);
// ==============================================
// ✅ 优化:处理 selection-change
// ==============================================
function handleSelectionChange(selection: tableType[]) {
if (isMultiple.value) {
// 多选逻辑:合并当前页选中项和之前页选中项
const currentSelectedIds = new Set(selection.map((item) => item.id));
// 过滤掉当前页未选中的旧数据
const otherPageSelections = multipleSelection.value.filter((item) => {
const isCurrentPageItem = tableData.value.some((row) => row.id === item.id);
if (isCurrentPageItem) {
return currentSelectedIds.has(item.id);
}
return true; // 保留其他页的数据
});
// 合并当前页新选中的数据
const finalSelection = [...otherPageSelections, ...selection];
// 去重
const uniqueMap = new Map();
finalSelection.forEach((item) => uniqueMap.set(item.id, item));
multipleSelection.value = Array.from(uniqueMap.values());
} else {
// 单选逻辑:始终只保留最后一个选中的项
if (selection.length > 0) {
// 获取最后选中的那一项
const lastSelected = selection[selection.length - 1];
multipleSelection.value = [lastSelected];
// 关键:如果 selection 长度大于1比如之前选了一个现在又选一个el-table可能暂时上报两个
// 我们需要手动清除表格中其他的勾选状态,只保留最后一个
nextTick(() => {
if (selection.length > 1) {
multipleTableRef.value?.clearSelection();
multipleTableRef.value?.toggleRowSelection(lastSelected, true);
}
});
} else {
multipleSelection.value = [];
}
}
}
// ✅ 优化:回显逻辑
const handleUserSelection = () => {
if (!multipleTableRef.value) return;
// 先清空所有选择
multipleTableRef.value.clearSelection();
multipleSelection.value = [];
if (!props.userid && props.userid !== 0) return;
nextTick(() => {
if (isMultiple.value && Array.isArray(props.userid)) {
// 多选回显
const selectedItems: tableType[] = [];
props.userid.forEach((id) => {
const findItem = tableData.value.find((item) => item.id == id || item.userId == id);
if (findItem) {
selectedItems.push(findItem);
multipleTableRef.value?.toggleRowSelection(findItem, true);
}
});
multipleSelection.value = selectedItems;
} else {
// 单选回显
// 注意props.userid 可能是单个 ID
const targetId = Array.isArray(props.userid) ? props.userid[0] : props.userid;
const findItem = tableData.value.find((item) => item.id == targetId || item.userId == targetId);
if (findItem) {
multipleTableRef.value?.toggleRowSelection(findItem, true);
multipleSelection.value = [findItem];
}
}
});
};
// 打开选择框
function choiceResidentFun() {
// 初始化
getlist();
dialog.value.dialogVisible = true;
}
// 获取列表
function getlist() {
loading.value = true;
listResident(queryParams.value)
.then((res) => {
tableData.value = res.rows;
tableData.value.forEach((item) => {
if (item.houseId !== null) {
const houselist = getHousePathById(treedata.value, item.houseId, 'label');
item.housePath = houselist?.join('-') || '';
}
});
handleUserSelection();
total.value = res.total;
})
.finally(() => {
loading.value = false;
});
}
// 重置查询
function resetQuery() {
queryParams.value = {
pageNum: 1,
pageSize: 10,
ownerRelationship: '', // 👈 这里也改
name: '',
type: '', // 👈 这里也改
status: '', // 👈 这里也改
houseId: null,
buildingId: null,
unitNo: null
};
getlist();
}
// 退出
function conback() {
dialog.value.dialogVisible = false;
resetQuery();
}
// ==============================================
// ✅ 核心修改:根据 returnvalue 返回对应的值
// ==============================================
function confirm() {
dialog.value.dialogVisible = false;
if (multipleSelection.value.length > 0) {
if (isMultiple.value) {
// 多选
if (returnvalue.value === '*') {
// ✅ 返回整个对象数组
emit('change', multipleSelection.value);
} else {
// 返回指定字段数组
emit(
'change',
multipleSelection.value.map((item) => item[returnvalue.value as keyof tableType])
);
}
} else {
// 单选
console.log(multipleSelection.value[0], multipleSelection.value);
if (returnvalue.value === '*') {
// ✅ 返回整个对象
emit('change', multipleSelection.value[0]);
} else {
// 返回指定字段
emit('change', multipleSelection.value[0][returnvalue.value as keyof tableType]);
}
}
} else {
emit('change', null);
}
}
defineExpose({
open: (arr) => {
if (arr && arr.length > 0) {
multipleSelection.value = arr.map((id) => ({
id: id
}));
} else {
multipleSelection.value = [];
}
getlist();
dialog.value.dialogVisible = true;
}
});
</script>
<style scoped lang="scss">
.residentBox {
width: 385px;
height: 35px;
line-height: 35px;
border: 1px solid #ccc;
border-radius: 5px;
padding: 0 10px;
.defaultbox {
display: flex;
align-items: center;
justify-content: space-between;
}
cursor: pointer;
&:hover {
background-color: #f4f8ff;
}
}
</style>