Files
sunProduct/src/components/Holder/index.vue
2026-04-27 08:08:30 +08:00

312 lines
9.5 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>
<!-- 关键:去掉 @selection-change,改用 row-click 实现单选,永不报错! -->
<el-table ref="multipleTableRef" :data="tableData" border @row-click="handleRowClick" @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="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="房间" 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, watch, nextTick, getCurrentInstance, ComponentInternalInstance, toRefs } from 'vue';
import { useHouseStore } from '@/store/modules/house';
const houseStore = useHouseStore();
const treedata = ref([]);
function init() {
houseStore.getCurrentVilageTreeHouse().then((res) => {
console.log(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 ?? 'id'); // 👈 默认 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,
villageId: 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) {
multipleSelection.value = selection;
}
}
// ==============================================
// 最佳单选方案:点击行选中,无报错、无循环、最稳定
// ==============================================
function handleRowClick(row) {
if (isMultiple.value) {
// 多选:点击行切换选中状态
const isSelected = multipleSelection.value.some((item) => item.id === row.id);
if (isSelected) {
multipleSelection.value = multipleSelection.value.filter((item) => item.id !== row.id);
multipleTableRef.value?.toggleRowSelection(row, false);
} else {
multipleSelection.value.push(row);
multipleTableRef.value?.toggleRowSelection(row, true);
}
} else {
// 单选:原有逻辑保持不变
multipleTableRef.value?.clearSelection();
multipleTableRef.value?.toggleRowSelection(row, true);
multipleSelection.value = [row];
}
}
// ==============================================
// ✅ 修改:支持多选回显
// ==============================================
const handleUserSelection = () => {
if (!userid.value || !tableData.value.length) return;
nextTick(() => {
multipleTableRef.value?.clearSelection();
if (isMultiple.value && Array.isArray(userid.value)) {
// 多选回显
const selectedItems: tableType[] = [];
userid.value.forEach((id) => {
const findItem = tableData.value.find((item) => item.userId == id);
if (findItem) {
selectedItems.push(findItem);
multipleTableRef.value?.toggleRowSelection(findItem, true);
}
});
multipleSelection.value = selectedItems;
} else {
// 单选回显(原有逻辑)
const findItem = tableData.value.find((item) => item.id == userid.value);
if (findItem) {
multipleSelection.value = [findItem];
multipleTableRef.value?.toggleRowSelection(findItem, true);
}
}
});
};
watch(userid, handleUserSelection, { immediate: true });
watch(tableData, handleUserSelection);
// 打开选择框
function choiceResidentFun() {
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('-') || '';
}
});
total.value = res.total;
loading.value = false;
});
}
// 重置查询
function resetQuery() {
queryParams.value = {
pageNum: 1,
pageSize: 10,
ownerRelationship: '', // 👈 这里也改
name: '',
type: '', // 👈 这里也改
status: '', // 👈 这里也改
houseId: null,
villageId: 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 {
// 单选
if (returnvalue.value === '*') {
// ✅ 返回整个对象
emit('change', multipleSelection.value[0]);
} else {
console.log(multipleSelection.value[0], returnvalue.value);
// 返回指定字段
emit('change', multipleSelection.value[0][returnvalue.value as keyof tableType]);
}
}
}
}
// 初始化
getlist();
defineExpose({
open: () => {
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>