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

370 lines
12 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 name="default" />
<el-dialog append-to-body v-model="dialog.dialogVisible" :title="dialog.dialogTitle" width="1400">
<nav class="flex flex-items-center mb-8 justify-between">
<!-- <div class="flex flex-items-center">
<div style="width: 70px; text-align: right; padding-right: 10px">房屋类型</div>
<div class="flex-1">
<el-select @change="handleChangeHouse" style="width: 140px" v-model="queryParams.houseUseTypeId">
<el-option v-for="(item, index) in houseUseTypeList" :key="index" :label="item.name" :value="item.id"></el-option>
</el-select>
</div>
</div> -->
<div class="flex flex-items-center">
<div class="flex flex-items-center">
<div style="width: 50px; text-align: right; padding-right: 10px">楼栋</div>
<div class="flex-1"></div>
<el-select @change="handleChangebuilding" clearable style="width: 120px" v-model="queryParams.buildingId">
<el-option v-for="(item, index) in buildinglist" :key="index" :label="item.buildingName" :value="item.id"></el-option>
</el-select>
</div>
<div class="flex flex-items-center mr-20px">
<div style="width: 50px; text-align: right; padding-right: 10px">单元</div>
<div class="flex-1">
<el-select @change="handleChangeUnit" clearable style="width: 120px" v-model="queryParams.unitNoId">
<el-option v-for="(item, index) in unitlist" :key="index" :label="item.unitNoName" :value="item.unitNoId"></el-option>
</el-select>
</div>
</div>
<div class="flex flex-items-center mr-20px">
<div style="width: 80px; text-align: right; padding-right: 10px">房屋类型</div>
<div class="flex-1">
<el-select clearable @change="handleHouseUseChange" style="width: 120px" v-model="queryParams.houseUseTypeId">
<el-option v-for="(item, index) in houseUseTypeList" :key="index" :label="item.name" :value="item.id"></el-option>
</el-select>
</div>
</div>
<div class="flex flex-items-center mr-20px">
<div style="width: 60px; text-align: right; padding-right: 10px">房屋号</div>
<div class="flex-1">
<el-input clearable @clear="handleClear" style="width: 120px" v-model="queryParams.houseNo" placeholder="请输入房屋号"></el-input>
</div>
</div>
<div class="flex flex-items-center mr-20px">
<div style="width: 80px; text-align: right; padding-right: 10px">业主名称</div>
<div class="flex-1">
<el-input clearable @clear="handleClear" style="width: 120px" v-model="queryParams.residentName" placeholder="请输入业主名称"></el-input>
</div>
</div>
</div>
<div>
<el-button type="primary" @click="getlist">查询</el-button>
<el-button @click="resetQuery">重置</el-button>
</div>
</nav>
<el-table row-key="houseId" v-loading="loading" ref="multipleTableRef" :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="villageName" />
<el-table-column label="楼栋" align="center" prop="buildingName" />
<el-table-column label="单元" align="center" prop="unitNoName" />
<el-table-column label="房间" align="center" prop="houseNo" />
<el-table-column label="业主" align="center">
<template #default="scope">
<span>{{ scope.row.residentName ? scope.row.residentName : '---' }}</span>
</template>
</el-table-column>
</el-table>
<template #footer>
<div class="dialog-footer flex flex-items-center flex-justify-between">
<pagination
style="margin-top: 0"
layout="total, prev, pager, next, jumper"
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 { getBuildinglistAPI, getHouselistAPI } from '@/api/system/house';
import { listHouseUseType_add_house } from '@/api/system/houseUse';
import { BillHouse, listBillHouse } from '@/api/system/SdbBill';
import { ref, nextTick, toRefs } from 'vue';
import pagination from '@/components/Pagination/index.vue';
// const { proxy } = getCurrentInstance() as ComponentInternalInstance;
// const { sys_user_sex } = toRefs<any>(proxy?.useDict('sys_user_sex'));
// const { com_build_use } = toRefs<any>(proxy?.useDict('com_build_use'));
const props = defineProps({
returnvalue: {
type: String,
default: 'houseId'
},
titleName: {
type: String,
default: '选择房屋'
},
/** 是否多选 false 单选 */
isMultiple: {
type: Boolean,
default: false
}
});
const { titleName, returnvalue } = toRefs(props);
const showids = ref([]);
// ✅ 手动设置默认值(替代 withDefaults)
const emit = defineEmits<{
change: [value: string | number | (string | number)[] | BillHouse | BillHouse[]]; // 支持返回数组
}>();
const dialog = ref({
dialogVisible: false,
dialogTitle: titleName.value
});
const queryParams = ref({
pageNum: 1,
pageSize: 10,
houseNo: '',
buildingId: null,
unitNoId: null,
houseUseTypeId: null,
residentName: ''
});
const multipleTableRef = ref();
const tableData = ref<BillHouse[]>([]);
const total = ref(0);
const loading = ref(false);
// 存储选中项
const multipleSelection = ref<BillHouse[]>([]);
const isMultiple = computed(() => props.isMultiple ?? false);
// 优化 handleUserSelection,避免重复查找
const handleUserSelection = () => {
isFetching.value = true;
if (!multipleTableRef.value || !tableData.value.length) {
isFetching.value = false;
return;
}
// 1. 获取当前页所有行的 houseId 集合,用于快速判断
// const currentPageIds = new Set(tableData.value.map((item) => item.houseId));
const rowsToSelect = tableData.value.filter((row) => {
return multipleSelection.value.some((selected) => selected.houseId === row.houseId);
});
multipleTableRef.value.clearSelection();
if (rowsToSelect.length > 0) {
nextTick(() => {
rowsToSelect.forEach((row) => {
multipleTableRef.value?.toggleRowSelection(row, true);
});
isFetching.value = false;
});
} else {
isFetching.value = false;
}
};
// ====================== 方法 ======================
const houseUseTypeList = ref([]);
const isFetching = ref(false);
// 获取列表
function getlist() {
isFetching.value = true; // 🔒 加锁:禁止 selection-change 更新数据
loading.value = true;
listBillHouse(queryParams.value)
.then((res) => {
tableData.value = res.rows;
total.value = res.total;
handleUserSelection();
})
.catch((error) => {
console.error('获取列表失败:', error);
})
.finally(() => {
loading.value = false;
isFetching.value = false;
});
}
/** 楼栋列表 */
const buildinglist = ref([]);
/** 房屋列表 */
const unitlist = ref([]);
/** 获取楼栋 列表 */
function handleChangeHouse() {
getBuildinglistAPI().then((res) => {
buildinglist.value = res.data;
});
}
function handleClear() {
queryParams.value.residentName = '';
getlist();
}
function handleHouseUseChange() {
getlist();
}
/** 单元列表 */
function handleChangebuilding(val: string) {
queryParams.value.unitNoId = null;
unitlist.value = [];
if (queryParams.value.buildingId) {
getHouselistAPI(val).then((res) => {
unitlist.value = res.data.units;
getlist();
});
}
getlist();
}
function handleChangeUnit() {
getlist();
}
// ==============================================
// ✅ 新增:处理 selection-change(多选专用)
// ==============================================
function handleSelectionChange(selection: BillHouse[]) {
// 🛑 如果正在获取数据/恢复状态,直接返回,不要更新 multipleSelection
if (isFetching.value) return;
if (isMultiple.value) {
// 1. 获取当前表格中所有选中行的 ID
const currentSelectedIds = new Set(selection.map((item) => item.houseId));
const otherPageSelections = multipleSelection.value.filter((item) => {
// 判断 item 是否属于当前页
const isCurrentPageItem = tableData.value.some((row) => row.houseId === item.houseId);
if (isCurrentPageItem) {
// 如果是当前页的数据,检查是否在当前 selection 中
return currentSelectedIds.has(item.houseId);
} else {
// 如果不是当前页的数据,保留(假设是之前页选的)
return true;
}
});
// 去重合并
const finalSelection = [...otherPageSelections, ...selection];
// 再次去重以防万一
const uniqueMap = new Map();
finalSelection.forEach((item) => uniqueMap.set(item.houseId, item));
multipleSelection.value = Array.from(uniqueMap.values());
console.log(multipleSelection.value.map((item) => item.houseId));
} else {
// ✅ 补充:单选模式下,selection-change 触发时,直接取最新的一项
// 这样配合 handleRowClick 的 clearSelection + toggle 就能实现完美单选
if (selection.length > 0) {
const lastSelected = selection[selection.length - 1];
multipleSelection.value = [lastSelected];
nextTick(() => {
if (selection.length > 1) {
multipleTableRef.value?.clearSelection();
multipleTableRef.value?.toggleRowSelection(lastSelected, true);
}
});
} else {
multipleSelection.value = [];
}
}
}
// 重置查询
function resetQuery() {
queryParams.value = {
pageNum: 1,
pageSize: 10,
houseUseTypeId: null,
buildingId: null,
unitNoId: null,
houseNo: '',
residentName: ''
};
getlist();
}
// 退出
function conback() {
dialog.value.dialogVisible = false;
resetQuery();
}
// ==============================================
// ✅ 核心修改:根据 returnvalue 返回对应的值
// ==============================================
function confirm() {
dialog.value.dialogVisible = false;
if (isMultiple.value) {
// 多选
if (returnvalue.value === '*') {
// ✅ 返回整个对象数组
emit('change', multipleSelection.value);
} else {
// 返回指定字段数组
emit(
'change',
multipleSelection.value.map((item) => item[returnvalue.value as keyof BillHouse])
);
}
} else {
// 单选
if (returnvalue.value === '*') {
// ✅ 返回整个对象
emit('change', multipleSelection.value[0]);
} else {
// 返回指定字段
emit('change', multipleSelection.value[0][returnvalue.value as keyof BillHouse]);
}
}
multipleSelection.value = [];
multipleTableRef.value.clearSelection();
}
defineExpose({
open: (showidArray: string[] = []) => {
multipleSelection.value = [];
showids.value = showidArray;
if (showidArray && showidArray.length > 0) {
multipleSelection.value = showidArray.map(
(id) =>
({
houseId: id
}) as BillHouse
);
}
getlist();
dialog.value.dialogVisible = true;
listHouseUseType_add_house().then((res) => {
houseUseTypeList.value = res.data;
});
handleChangeHouse();
}
});
</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>