|
|
@@ -133,6 +133,27 @@
|
|
|
<el-row>
|
|
|
<el-col :span="12">
|
|
|
<el-button type="primary" icon="check" size="small" @click="handleAddRoom">分配给二级学院</el-button>
|
|
|
+ <el-button type="warning" icon="RefreshLeft" size="small" @click="handleBatchRecall">批量收回宿舍</el-button>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12" style="text-align: right">
|
|
|
+ <el-button
|
|
|
+ link
|
|
|
+ type="primary"
|
|
|
+ size="small"
|
|
|
+ :loading="expandAllLoading"
|
|
|
+ :disabled="expandAllLoading || selectionLoading || loading"
|
|
|
+ @click="expandAll"
|
|
|
+ >全部展开</el-button
|
|
|
+ >
|
|
|
+ <el-button
|
|
|
+ link
|
|
|
+ type="primary"
|
|
|
+ size="small"
|
|
|
+ :loading="collapseAllLoading"
|
|
|
+ :disabled="collapseAllLoading || selectionLoading || loading"
|
|
|
+ @click="collapseAll"
|
|
|
+ >全部收起</el-button
|
|
|
+ >
|
|
|
</el-col>
|
|
|
</el-row>
|
|
|
</template>
|
|
|
@@ -170,7 +191,8 @@
|
|
|
<!-- 房间及床位树形表格 -->
|
|
|
<el-table
|
|
|
ref="tableRef"
|
|
|
- v-loading="loading"
|
|
|
+ v-loading="loading || selectionLoading || expandAllLoading || collapseAllLoading"
|
|
|
+ element-loading-text="处理中..."
|
|
|
:data="roomList"
|
|
|
row-key="id"
|
|
|
border
|
|
|
@@ -344,6 +366,7 @@ import ElMessageBox from 'element-plus/es/components/message-box/index';
|
|
|
import RoomDialog from './components/RoomDialog.vue';
|
|
|
import BedDialog from './components/BedDialog.vue';
|
|
|
import CollegeAllocationDialog from './components/CollegeAllocationDialog.vue';
|
|
|
+import { batchRecallDormBeds } from '@/api/xg/xgss/dormBedStudent/dormBedStudent';
|
|
|
|
|
|
// const { proxy } = getCurrentInstance();
|
|
|
|
|
|
@@ -356,6 +379,14 @@ const showSearch = ref(true);
|
|
|
const loading = ref(false);
|
|
|
const expandedRowKeys = ref<string[]>([]);
|
|
|
|
|
|
+// 加载状态:展开/收起/选择
|
|
|
+const expandAllLoading = ref(false);
|
|
|
+const collapseAllLoading = ref(false);
|
|
|
+const selectionLoading = ref(false);
|
|
|
+
|
|
|
+// 小延迟,确保加载动画先渲染
|
|
|
+const delay = (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms));
|
|
|
+
|
|
|
// 选择状态
|
|
|
const selectedRows = ref<any[]>([]);
|
|
|
const selectedRoomCount = ref(0);
|
|
|
@@ -643,6 +674,61 @@ const handleAddRoom = () => {
|
|
|
collegeAllocationDialog.visible = true;
|
|
|
};
|
|
|
|
|
|
+/** 批量收回宿舍 */
|
|
|
+const handleBatchRecall = async () => {
|
|
|
+ if (!selectedBuilding.value) {
|
|
|
+ ElMessage.warning('请先选择宿舍楼');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const selectedBeds = selectedRows.value.filter((row) => row.isBed).map((row) => row.id);
|
|
|
+ if (selectedBeds.length === 0) {
|
|
|
+ ElMessage.warning('请先选择要收回的床位');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ const content = `确认收回选中的 ${selectedBeds.length} 个床位吗?\n\n重要提示:回收后,学生已分配的宿舍都会回收,无法恢复`;
|
|
|
+ await ElMessageBox.confirm(content, '提示', {
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning'
|
|
|
+ });
|
|
|
+ } catch {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ await batchRecallDormBeds({ bedIds: selectedBeds });
|
|
|
+ ElMessage.success('批量收回成功');
|
|
|
+ // 刷新数据
|
|
|
+ selectableRowsCache.value = [];
|
|
|
+ loadRoomData();
|
|
|
+ } catch (e) {
|
|
|
+ ElMessage.error('批量收回失败');
|
|
|
+ console.error(e);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 全部展开 */
|
|
|
+const expandAll = async () => {
|
|
|
+ if (expandAllLoading.value || selectionLoading.value || !roomList.value?.length) return;
|
|
|
+ expandAllLoading.value = true;
|
|
|
+ await nextTick();
|
|
|
+ await delay(16);
|
|
|
+ expandedRowKeys.value = roomList.value.map((room) => String(room.id));
|
|
|
+ await nextTick();
|
|
|
+ expandAllLoading.value = false;
|
|
|
+};
|
|
|
+
|
|
|
+/** 全部收起 */
|
|
|
+const collapseAll = async () => {
|
|
|
+ if (collapseAllLoading.value || selectionLoading.value) return;
|
|
|
+ collapseAllLoading.value = true;
|
|
|
+ await nextTick();
|
|
|
+ await delay(16);
|
|
|
+ expandedRowKeys.value = [];
|
|
|
+ await nextTick();
|
|
|
+ collapseAllLoading.value = false;
|
|
|
+};
|
|
|
+
|
|
|
/** 编辑房间 */
|
|
|
const handleEditRoom = (row: any) => {
|
|
|
roomDialog.title = '编辑房间';
|
|
|
@@ -741,13 +827,13 @@ const handleCollegeAllocationSuccess = () => {
|
|
|
|
|
|
/** 处理行的展开/收起 */
|
|
|
const handleExpandChange = (row: any, expanded: boolean) => {
|
|
|
- const rowId = String(row.roomId);
|
|
|
+ const expandKey = String(row.id);
|
|
|
if (expanded) {
|
|
|
// 添加到已展开行数组
|
|
|
- expandedRowKeys.value.push(rowId);
|
|
|
+ expandedRowKeys.value.push(expandKey);
|
|
|
} else {
|
|
|
// 从已展开行数组中移除
|
|
|
- const index = expandedRowKeys.value.findIndex((key) => key === rowId);
|
|
|
+ const index = expandedRowKeys.value.findIndex((key) => key === expandKey);
|
|
|
if (index !== -1) {
|
|
|
expandedRowKeys.value.splice(index, 1);
|
|
|
}
|
|
|
@@ -854,7 +940,10 @@ const getAllSelectableRows = () => {
|
|
|
const selectableRowsCache = ref<any[]>([]);
|
|
|
|
|
|
/** 处理全选事件 */
|
|
|
-const handleSelectAll = (selection: any[]) => {
|
|
|
+const handleSelectAll = async (selection: any[]) => {
|
|
|
+ if (selectionLoading.value) return;
|
|
|
+
|
|
|
+ selectionLoading.value = true;
|
|
|
// 避免在全选操作时触发联动逻辑
|
|
|
isUpdatingSelection.value = true;
|
|
|
|
|
|
@@ -862,6 +951,9 @@ const handleSelectAll = (selection: any[]) => {
|
|
|
// 判断是全选还是取消全选
|
|
|
const isSelectAll = selection.length > 0;
|
|
|
|
|
|
+ await nextTick();
|
|
|
+ await delay(16);
|
|
|
+
|
|
|
if (isSelectAll) {
|
|
|
console.log('================>全选0');
|
|
|
// 全选操作:选择所有可用的行(包括房间和床位)
|
|
|
@@ -892,6 +984,7 @@ const handleSelectAll = (selection: any[]) => {
|
|
|
}
|
|
|
} finally {
|
|
|
isUpdatingSelection.value = false;
|
|
|
+ selectionLoading.value = false;
|
|
|
}
|
|
|
};
|
|
|
|