8/25 dev bug
This commit is contained in:
@@ -36,8 +36,15 @@
|
||||
<el-button @click="resetQuery">重置</el-button>
|
||||
</div>
|
||||
</nav>
|
||||
<el-table ref="multipleTableRef" :data="tableData" border @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table v-loading="loading" ref="multipleTableRef" :data="tableData" border>
|
||||
<el-table-column width="55" align="center">
|
||||
<template #header>
|
||||
<el-checkbox v-model="isSelectAll" :indeterminate="isIndeterminate" @change="handleSelectAllChange" />
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<el-checkbox :model-value="isRowSelected(scope.row)" @change="(val: boolean) => handleRowCheckChange(scope.row, val)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="序号" align="center" width="55" type="index" />
|
||||
<el-table-column label="楼栋号" align="center">
|
||||
<template #default="scope">
|
||||
@@ -70,7 +77,7 @@
|
||||
<div class="dialog-footer flex flex-items-center flex-justify-between">
|
||||
<pagination
|
||||
style="margin-top: 0"
|
||||
layout="total, prev, pager, next, jumper"
|
||||
layout="sizes, prev, pager, next, jumper"
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNum"
|
||||
@@ -79,7 +86,7 @@
|
||||
/>
|
||||
<div>
|
||||
<el-button @click="conback">退出</el-button>
|
||||
<el-button type="primary" @click="confirm"> 确定 </el-button>
|
||||
<el-button type="primary" @click="confirm" :loading="loading"> 确定 </el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -89,7 +96,7 @@
|
||||
<script setup lang="ts">
|
||||
import { getBuildinglistAPI, getHouselistAPI } from '@/api/system/house';
|
||||
import { BillUserlist, queryResidentList_holder } from '@/api/system/SdbBill';
|
||||
import { ref, nextTick, getCurrentInstance, ComponentInternalInstance, toRefs } from 'vue';
|
||||
import { ComponentInternalInstance, getCurrentInstance, ref, toRefs } from 'vue';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const { sys_user_sex } = toRefs<any>(proxy?.useDict('sys_user_sex'));
|
||||
@@ -125,7 +132,7 @@ const dialog = ref({
|
||||
|
||||
const queryParams = ref({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
pageSize: 5,
|
||||
|
||||
buildingId: null,
|
||||
residentName: null,
|
||||
@@ -137,53 +144,104 @@ const multipleTableRef = ref();
|
||||
const tableData = ref<BillUserlist[]>([]);
|
||||
const total = ref(0);
|
||||
const loading = ref(false);
|
||||
const isFetching = ref(false);
|
||||
// 存储选中项
|
||||
/** 存储所有选中项(跨页累计,非全选模式使用) */
|
||||
const multipleSelection = ref<BillUserlist[]>([]);
|
||||
/** 是否已跨页全选(标记模式,不实际持有全部数据) */
|
||||
const isSelectAll = ref(false);
|
||||
/** 表头复选框半选状态(部分选中时为 true) */
|
||||
const isIndeterminate = ref(false);
|
||||
/** 全选模式下被手动取消勾选的 residentId 列表 */
|
||||
const deselectedIds = ref<string[]>([]);
|
||||
|
||||
const isMultiple = computed(() => props.isMultiple ?? false);
|
||||
|
||||
// 优化 handleUserSelection,避免重复查找
|
||||
const handleUserSelection = () => {
|
||||
isFetching.value = true;
|
||||
if (!multipleTableRef.value || !tableData.value.length) {
|
||||
isFetching.value = false;
|
||||
/** 判断某行是否已选中 */
|
||||
function isRowSelected(row: BillUserlist): boolean {
|
||||
if (isSelectAll.value) {
|
||||
// 全选模式:只要不在取消列表中就算选中
|
||||
return !deselectedIds.value.includes(row.residentId);
|
||||
}
|
||||
return multipleSelection.value.some((item) => item.residentId === row.residentId);
|
||||
}
|
||||
|
||||
/** 更新表头复选框状态:全选 / 半选 / 空 */
|
||||
function updateIndeterminate() {
|
||||
if (isSelectAll.value) {
|
||||
// 全选模式下:有取消勾选的行 → 半选,否则 → 全选
|
||||
isIndeterminate.value = deselectedIds.value.length > 0;
|
||||
return;
|
||||
}
|
||||
const rowsToSelect = tableData.value.filter((row) => {
|
||||
return multipleSelection.value.some((selected) => selected.residentId === row.residentId);
|
||||
});
|
||||
multipleTableRef.value.clearSelection();
|
||||
if (rowsToSelect.length > 0) {
|
||||
nextTick(() => {
|
||||
rowsToSelect.forEach((row) => {
|
||||
multipleTableRef.value?.toggleRowSelection(row, true);
|
||||
});
|
||||
isFetching.value = false;
|
||||
});
|
||||
|
||||
const selectedCount = multipleSelection.value.length;
|
||||
const totalCount = total.value;
|
||||
|
||||
if (selectedCount === 0) {
|
||||
isIndeterminate.value = false;
|
||||
} else if (totalCount > 0 && selectedCount >= totalCount) {
|
||||
// 手动逐行全选 → 切换为全选标记模式,释放 multipleSelection 内存
|
||||
isSelectAll.value = true;
|
||||
isIndeterminate.value = false;
|
||||
deselectedIds.value = [];
|
||||
multipleSelection.value = [];
|
||||
} else {
|
||||
isFetching.value = false;
|
||||
isIndeterminate.value = true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** 跨页全选 / 取消全选(仅设标记,不拉取数据) */
|
||||
function handleSelectAllChange(val: boolean) {
|
||||
if (val) {
|
||||
isSelectAll.value = true;
|
||||
deselectedIds.value = [];
|
||||
multipleSelection.value = [];
|
||||
} else {
|
||||
isSelectAll.value = false;
|
||||
deselectedIds.value = [];
|
||||
multipleSelection.value = [];
|
||||
}
|
||||
updateIndeterminate();
|
||||
}
|
||||
|
||||
/** 单行勾选 / 取消勾选 */
|
||||
function handleRowCheckChange(row: BillUserlist, checked: boolean) {
|
||||
if (isSelectAll.value) {
|
||||
// 全选模式:维护取消列表
|
||||
if (checked) {
|
||||
deselectedIds.value = deselectedIds.value.filter((id) => id !== row.residentId);
|
||||
} else {
|
||||
if (!deselectedIds.value.includes(row.residentId)) {
|
||||
deselectedIds.value.push(row.residentId);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 非全选模式:维护选中列表
|
||||
if (checked) {
|
||||
if (!isRowSelected(row)) {
|
||||
multipleSelection.value.push(row);
|
||||
}
|
||||
} else {
|
||||
multipleSelection.value = multipleSelection.value.filter((item) => item.residentId !== row.residentId);
|
||||
}
|
||||
}
|
||||
updateIndeterminate();
|
||||
}
|
||||
|
||||
// ====================== 方法 ======================
|
||||
|
||||
// 获取列表
|
||||
function getList() {
|
||||
isFetching.value = true; // 加锁
|
||||
loading.value = true;
|
||||
queryResidentList_holder(queryParams.value)
|
||||
.then((res) => {
|
||||
tableData.value = res.rows;
|
||||
total.value = res.total;
|
||||
handleUserSelection();
|
||||
updateIndeterminate();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('获取用户列表失败:', error);
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
isFetching.value = false; // 加锁
|
||||
});
|
||||
}
|
||||
|
||||
@@ -215,37 +273,6 @@ function handleChangeBuilding(val: string) {
|
||||
function handleChangeUnit() {
|
||||
getList();
|
||||
}
|
||||
// ==============================================
|
||||
// ✅ 新增:处理 selection-change(多选专用)
|
||||
// ==============================================
|
||||
function handleSelectionChange(selection: BillUserlist[]) {
|
||||
if (isFetching.value) return;
|
||||
if (isMultiple.value) {
|
||||
const currentSelectedIds = new Set(selection.map((item) => item.residentId));
|
||||
const otherPageSelections = multipleSelection.value.filter((item) => {
|
||||
const isCurrentPageItem = tableData.value.some((row) => row.residentId === item.residentId);
|
||||
if (isCurrentPageItem) {
|
||||
return currentSelectedIds.has(item.residentId);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
// 3. 合并:其他页保留的 + 当前页新选中的
|
||||
const finalSelection = [...otherPageSelections, ...selection];
|
||||
// 4. 去重(以防万一)
|
||||
const uniqueMap = new Map();
|
||||
finalSelection.forEach((item) => uniqueMap.set(item.residentId, item));
|
||||
multipleSelection.value = Array.from(uniqueMap.values());
|
||||
console.log(multipleSelection.value.map((item) => item.residentId));
|
||||
} else {
|
||||
// --- 单选逻辑 ---
|
||||
if (selection.length > 0) {
|
||||
multipleSelection.value = [selection[selection.length - 1]];
|
||||
} else {
|
||||
multipleSelection.value = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
// 重置查询
|
||||
function resetQuery() {
|
||||
queryParams.value = {
|
||||
@@ -256,6 +283,7 @@ function resetQuery() {
|
||||
residentName: null,
|
||||
houseNo: null
|
||||
};
|
||||
resetSelection();
|
||||
getList();
|
||||
}
|
||||
|
||||
@@ -265,41 +293,82 @@ function conback() {
|
||||
resetQuery();
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
// ✅ 核心修改:根据 returnvalue 返回对应的值
|
||||
// ==============================================
|
||||
function confirm() {
|
||||
dialog.value.dialogVisible = false;
|
||||
/** 重置所有选中状态 */
|
||||
function resetSelection() {
|
||||
multipleSelection.value = [];
|
||||
isSelectAll.value = false;
|
||||
isIndeterminate.value = false;
|
||||
deselectedIds.value = [];
|
||||
}
|
||||
|
||||
/** 根据 returnvalue 发射选中结果 */
|
||||
function emitResult(data: BillUserlist[]) {
|
||||
if (isMultiple.value) {
|
||||
// 多选
|
||||
if (returnvalue.value === '*') {
|
||||
// ✅ 返回整个对象数组
|
||||
emit('change', multipleSelection.value);
|
||||
emit('change', data);
|
||||
} else {
|
||||
// 返回指定字段数组
|
||||
emit(
|
||||
'change',
|
||||
multipleSelection.value.map((item) => item[returnvalue.value as keyof BillUserlist])
|
||||
data.map((item) => item[returnvalue.value as keyof BillUserlist])
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// 单选
|
||||
if (returnvalue.value === '*') {
|
||||
// ✅ 返回整个对象
|
||||
emit('change', multipleSelection.value[0]);
|
||||
emit('change', data[0]);
|
||||
} else {
|
||||
// 返回指定字段
|
||||
emit('change', multipleSelection.value[0][returnvalue.value as keyof BillUserlist]);
|
||||
emit('change', data[0]?.[returnvalue.value as keyof BillUserlist]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
multipleSelection.value = [];
|
||||
multipleTableRef.value.clearSelection();
|
||||
/** 确定:全选模式下按需拉取全部数据,非全选模式直接使用已选列表 */
|
||||
async function confirm() {
|
||||
if (isSelectAll.value) {
|
||||
// 全选模式:此时才真正拉取全部数据,排除已取消勾选的行
|
||||
loading.value = true;
|
||||
try {
|
||||
const res = await queryResidentList_holder({
|
||||
...queryParams.value,
|
||||
pageNum: 1,
|
||||
pageSize: total.value || undefined
|
||||
});
|
||||
const allData: BillUserlist[] = res.rows || [];
|
||||
const filteredData = allData.filter((item) => !deselectedIds.value.includes(item.residentId));
|
||||
dialog.value.dialogVisible = false;
|
||||
emitResult(filteredData);
|
||||
} catch (error) {
|
||||
console.error('获取全部数据失败:', error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
} else {
|
||||
// 非全选模式:直接使用已收集的选中列表
|
||||
dialog.value.dialogVisible = false;
|
||||
emitResult(multipleSelection.value);
|
||||
}
|
||||
|
||||
resetSelection();
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
open: (arr: string[] = []) => {
|
||||
userid.value = arr;
|
||||
// 重置查询条件,避免残留上次的筛选条件
|
||||
queryParams.value = {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
buildingId: null,
|
||||
residentName: null,
|
||||
houseNo: null,
|
||||
unitNoId: null
|
||||
};
|
||||
// 立即清空旧列表数据,避免闪烁
|
||||
tableData.value = [];
|
||||
total.value = 0;
|
||||
// 重置全选标记
|
||||
isSelectAll.value = false;
|
||||
deselectedIds.value = [];
|
||||
// 根据传入的 ID 数组初始化选中状态
|
||||
if (arr && arr.length > 0) {
|
||||
multipleSelection.value = arr.map(
|
||||
(id) =>
|
||||
@@ -307,8 +376,10 @@ defineExpose({
|
||||
residentId: id
|
||||
}) as BillUserlist
|
||||
);
|
||||
isIndeterminate.value = true;
|
||||
} else {
|
||||
multipleSelection.value = [];
|
||||
isIndeterminate.value = false;
|
||||
}
|
||||
|
||||
getList();
|
||||
|
||||
Reference in New Issue
Block a user