|
@@ -0,0 +1,464 @@
|
|
|
|
|
+<template>
|
|
|
|
|
+ <div class="p-2">
|
|
|
|
|
+ <el-row :gutter="20">
|
|
|
|
|
+ <!-- 宿舍树 -->
|
|
|
|
|
+ <el-col :lg="4" :xs="24">
|
|
|
|
|
+ <el-card shadow="hover">
|
|
|
|
|
+ <el-input v-model="buildingName" placeholder="请输入宿舍楼名称" prefix-icon="Search" clearable />
|
|
|
|
|
+ <el-tree
|
|
|
|
|
+ ref="dormTreeRef"
|
|
|
|
|
+ class="mt-2"
|
|
|
|
|
+ node-key="id"
|
|
|
|
|
+ :data="dormOptions"
|
|
|
|
|
+ :props="{ label: 'label', children: 'children', disabled: 'disabled' }"
|
|
|
|
|
+ :expand-on-click-node="false"
|
|
|
|
|
+ :filter-node-method="filterNode"
|
|
|
|
|
+ highlight-current
|
|
|
|
|
+ default-expand-all
|
|
|
|
|
+ @node-click="handleNodeClick"
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-card>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+
|
|
|
|
|
+ <el-col :lg="20" :xs="24">
|
|
|
|
|
+ <transition :enter-active-class="animate.searchAnimate.enter" :leave-active-class="animate.searchAnimate.leave">
|
|
|
|
|
+ <div v-show="showSearch" class="mb-[10px]">
|
|
|
|
|
+ <el-card shadow="hover">
|
|
|
|
|
+ <el-form ref="queryFormRef" :model="queryParams" inline>
|
|
|
|
|
+ <el-form-item label="房间号" prop="roomName">
|
|
|
|
|
+ <el-input v-model="queryParams.roomName" placeholder="请输入房间号" clearable @keyup.enter="handleQuery" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="状态" prop="status">
|
|
|
|
|
+ <el-select v-model="queryParams.status" placeholder="房间状态" clearable>
|
|
|
|
|
+ <el-option label="正常" value="0" />
|
|
|
|
|
+ <el-option label="维修中" value="1" />
|
|
|
|
|
+ <el-option label="停用" value="2" />
|
|
|
|
|
+ </el-select>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item>
|
|
|
|
|
+ <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
|
|
|
|
+ <el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-form>
|
|
|
|
|
+ </el-card>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </transition>
|
|
|
|
|
+
|
|
|
|
|
+ <el-card v-if="!selectedBuilding" shadow="hover" class="empty-tip">
|
|
|
|
|
+ <div class="flex flex-col items-center justify-center h-[400px]">
|
|
|
|
|
+ <el-icon class="text-gray-400 text-5xl mb-4"><InfoFilled /></el-icon>
|
|
|
|
|
+ <p class="text-gray-500 text-lg">请在左侧选择宿舍楼</p>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </el-card>
|
|
|
|
|
+
|
|
|
|
|
+ <template v-else>
|
|
|
|
|
+ <el-card shadow="hover" class="mb-4">
|
|
|
|
|
+ <template #header>
|
|
|
|
|
+ <el-row>
|
|
|
|
|
+ <el-col :span="12">
|
|
|
|
|
+ <span class="font-bold">{{ selectedBuilding?.label }} - 房间管理</span>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :span="12" class="text-right">
|
|
|
|
|
+ <right-toolbar v-model:show-search="showSearch" @query-table="loadRoomData"></right-toolbar>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ </el-row>
|
|
|
|
|
+ </template>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 楼层卡片 -->
|
|
|
|
|
+ <div v-for="floor in floorList" :key="floor" class="mb-4">
|
|
|
|
|
+ <el-divider>
|
|
|
|
|
+ <el-tag type="success" effect="dark" class="mr-2">{{ floor }}层</el-tag>
|
|
|
|
|
+ <el-button type="primary" icon="Plus" size="small" @click="handleAddRoom(floor)">添加房间</el-button>
|
|
|
|
|
+ </el-divider>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="room-container">
|
|
|
|
|
+ <el-empty v-if="getRoomsByFloor(floor).length === 0" description="暂无房间数据" />
|
|
|
|
|
+ <div v-else class="room-grid">
|
|
|
|
|
+ <el-card
|
|
|
|
|
+ v-for="room in getRoomsByFloor(floor)"
|
|
|
|
|
+ :key="room.roomId"
|
|
|
|
|
+ class="room-card"
|
|
|
|
|
+ :class="{ 'room-disabled': room.status !== '0' }"
|
|
|
|
|
+ >
|
|
|
|
|
+ <template #header>
|
|
|
|
|
+ <div class="flex items-center justify-between">
|
|
|
|
|
+ <span class="font-bold">{{ room.roomName }}</span>
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <el-tag v-if="room.status === '0'" type="success" size="small">正常</el-tag>
|
|
|
|
|
+ <el-tag v-else-if="room.status === '1'" type="warning" size="small">维修中</el-tag>
|
|
|
|
|
+ <el-tag v-else type="danger" size="small">停用</el-tag>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ <div class="room-info">
|
|
|
|
|
+ <div class="mb-2"><span class="text-gray-500">类型:</span>{{ room.roomType }}</div>
|
|
|
|
|
+ <div class="mb-2"><span class="text-gray-500">床位:</span>{{ room.used }}/{{ room.capacity }}</div>
|
|
|
|
|
+ <div class="flex justify-between mt-4">
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <el-button type="primary" link size="small" @click="handleManageBeds(room)">床位管理</el-button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <el-button type="primary" link icon="Edit" @click="handleEditRoom(room)" />
|
|
|
|
|
+ <el-button type="danger" link icon="Delete" @click="handleDeleteRoom(room)" />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </el-card>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </el-card>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ </el-row>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 房间管理对话框 -->
|
|
|
|
|
+ <room-dialog
|
|
|
|
|
+ v-model="roomDialog.visible"
|
|
|
|
|
+ :title="roomDialog.title"
|
|
|
|
|
+ :room-id="roomDialog.roomId"
|
|
|
|
|
+ :floor-number="roomDialog.floorNumber"
|
|
|
|
|
+ :building-id="roomDialog.buildingId"
|
|
|
|
|
+ @success="handleRoomSuccess"
|
|
|
|
|
+ />
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 床位管理对话框 -->
|
|
|
|
|
+ <el-dialog v-model="bedManageDialog.visible" :title="`${bedManageDialog.roomName} - 床位管理`" width="800px">
|
|
|
|
|
+ <div class="mb-4 text-right">
|
|
|
|
|
+ <el-button type="primary" icon="Plus" @click="handleAddBed">添加床位</el-button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <el-table v-loading="bedLoading" :data="bedList" border>
|
|
|
|
|
+ <el-table-column label="床位名称" prop="bedName" />
|
|
|
|
|
+ <el-table-column label="状态" align="center">
|
|
|
|
|
+ <template #default="scope">
|
|
|
|
|
+ <el-tag v-if="scope.row.status === '0'" type="success">空闲</el-tag>
|
|
|
|
|
+ <el-tag v-else-if="scope.row.status === '1'" type="warning">已分配</el-tag>
|
|
|
|
|
+ <el-tag v-else type="danger">维修中</el-tag>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column label="学生" prop="studentName" />
|
|
|
|
|
+ <el-table-column label="备注" prop="remark" :show-overflow-tooltip="true" />
|
|
|
|
|
+ <el-table-column label="操作" width="180" align="center">
|
|
|
|
|
+ <template #default="scope">
|
|
|
|
|
+ <el-button type="primary" link icon="Edit" @click="handleEditBed(scope.row)" />
|
|
|
|
|
+ <el-button type="danger" link icon="Delete" @click="handleDeleteBed(scope.row)" />
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ </el-table>
|
|
|
|
|
+ </el-dialog>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 床位表单对话框 -->
|
|
|
|
|
+ <bed-dialog
|
|
|
|
|
+ v-model="bedDialog.visible"
|
|
|
|
|
+ :title="bedDialog.title"
|
|
|
|
|
+ :bed-id="bedDialog.bedId"
|
|
|
|
|
+ :room-id="bedDialog.roomId"
|
|
|
|
|
+ @success="handleBedSuccess"
|
|
|
|
|
+ />
|
|
|
|
|
+ </div>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script setup name="DormRoomManagement" lang="ts">
|
|
|
|
|
+import { ref, computed, reactive, onMounted, nextTick } from 'vue';
|
|
|
|
|
+import { ElMessageBox, ElMessage } from 'element-plus';
|
|
|
|
|
+import { InfoFilled } from '@element-plus/icons-vue';
|
|
|
|
|
+import { DormTreeNode, RoomInfo, BedInfo, DormQuery } from '@/api/xgss/xsssfjgl/types';
|
|
|
|
|
+import {
|
|
|
|
|
+ getDormTree,
|
|
|
|
|
+ listRooms,
|
|
|
|
|
+ delRoom,
|
|
|
|
|
+ listBeds,
|
|
|
|
|
+ delBed,
|
|
|
|
|
+ // 以下为模拟数据
|
|
|
|
|
+ getMockDormTree,
|
|
|
|
|
+ getMockRooms,
|
|
|
|
|
+ getMockBeds
|
|
|
|
|
+} from '@/api/xgss/xsssfjgl';
|
|
|
|
|
+
|
|
|
|
|
+// 引入子组件
|
|
|
|
|
+import RoomDialog from './components/RoomDialog.vue';
|
|
|
|
|
+import BedDialog from './components/BedDialog.vue';
|
|
|
|
|
+
|
|
|
|
|
+// 组件状态
|
|
|
|
|
+const dormTreeRef = ref();
|
|
|
|
|
+const queryFormRef = ref();
|
|
|
|
|
+const buildingName = ref('');
|
|
|
|
|
+const showSearch = ref(true);
|
|
|
|
|
+const animate = reactive({
|
|
|
|
|
+ searchAnimate: {
|
|
|
|
|
+ enter: 'animate__animated animate__fadeInDown',
|
|
|
|
|
+ leave: 'animate__animated animate__fadeOutUp'
|
|
|
|
|
+ }
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+// 宿舍树数据
|
|
|
|
|
+const dormOptions = ref<DormTreeNode[]>([]);
|
|
|
|
|
+const selectedBuilding = ref<DormTreeNode>();
|
|
|
|
|
+
|
|
|
|
|
+// 房间数据
|
|
|
|
|
+const roomList = ref<RoomInfo[]>([]);
|
|
|
|
|
+const floorList = computed(() => {
|
|
|
|
|
+ if (!selectedBuilding.value?.buildingFloors) return [];
|
|
|
|
|
+ return Array.from({ length: selectedBuilding.value.buildingFloors }, (_, i) => i + 1);
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+// 查询参数
|
|
|
|
|
+const queryParams = reactive<DormQuery>({
|
|
|
|
|
+ pageNum: 1,
|
|
|
|
|
+ pageSize: 100,
|
|
|
|
|
+ buildingId: undefined,
|
|
|
|
|
+ roomName: '',
|
|
|
|
|
+ status: undefined
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+// 房间对话框
|
|
|
|
|
+const roomDialog = reactive({
|
|
|
|
|
+ visible: false,
|
|
|
|
|
+ title: '',
|
|
|
|
|
+ roomId: undefined as string | number | undefined,
|
|
|
|
|
+ floorNumber: 1,
|
|
|
|
|
+ buildingId: '' as string | number
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+// 床位管理对话框
|
|
|
|
|
+const bedManageDialog = reactive({
|
|
|
|
|
+ visible: false,
|
|
|
|
|
+ roomId: '' as string | number,
|
|
|
|
|
+ roomName: ''
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+// 床位表单对话框
|
|
|
|
|
+const bedDialog = reactive({
|
|
|
|
|
+ visible: false,
|
|
|
|
|
+ title: '',
|
|
|
|
|
+ bedId: undefined as string | number | undefined,
|
|
|
|
|
+ roomId: '' as string | number
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+// 床位数据
|
|
|
|
|
+const bedList = ref<BedInfo[]>([]);
|
|
|
|
|
+const bedLoading = ref(false);
|
|
|
|
|
+
|
|
|
|
|
+/** 通过条件过滤节点 */
|
|
|
|
|
+const filterNode = (value: string, data: DormTreeNode) => {
|
|
|
|
|
+ if (!value) return true;
|
|
|
|
|
+ return data.label.indexOf(value) !== -1;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+/** 监听宿舍楼名称变化,筛选树 */
|
|
|
|
|
+const watchBuildingName = () => {
|
|
|
|
|
+ dormTreeRef.value?.filter(buildingName.value);
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+/** 获取宿舍树数据 */
|
|
|
|
|
+const getDormTreeData = async () => {
|
|
|
|
|
+ try {
|
|
|
|
|
+ // const res = await getDormTree();
|
|
|
|
|
+ // 使用模拟数据
|
|
|
|
|
+ const res = getMockDormTree();
|
|
|
|
|
+ dormOptions.value = res.data;
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('获取宿舍树失败', error);
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+/** 节点单击事件 */
|
|
|
|
|
+const handleNodeClick = (data: DormTreeNode) => {
|
|
|
|
|
+ if (data.type !== 'building') {
|
|
|
|
|
+ // 如果不是宿舍楼,不进行操作
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ selectedBuilding.value = data;
|
|
|
|
|
+ queryParams.buildingId = data.id;
|
|
|
|
|
+ loadRoomData();
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+/** 加载房间数据 */
|
|
|
|
|
+const loadRoomData = async () => {
|
|
|
|
|
+ if (!queryParams.buildingId) return;
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ // const res = await listRooms(queryParams);
|
|
|
|
|
+ // 使用模拟数据
|
|
|
|
|
+ const res = getMockRooms(queryParams.buildingId);
|
|
|
|
|
+ roomList.value = res.rows;
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('获取房间列表失败', error);
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+/** 根据楼层获取房间数据 */
|
|
|
|
|
+const getRoomsByFloor = (floor: number) => {
|
|
|
|
|
+ return roomList.value.filter((room) => room.floorNumber === floor);
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+/** 搜索按钮操作 */
|
|
|
|
|
+const handleQuery = () => {
|
|
|
|
|
+ queryParams.pageNum = 1;
|
|
|
|
|
+ loadRoomData();
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+/** 重置按钮操作 */
|
|
|
|
|
+const resetQuery = () => {
|
|
|
|
|
+ queryFormRef.value?.resetFields();
|
|
|
|
|
+ queryParams.pageNum = 1;
|
|
|
|
|
+ queryParams.roomName = '';
|
|
|
|
|
+ queryParams.status = undefined;
|
|
|
|
|
+ handleQuery();
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+/** 添加房间 */
|
|
|
|
|
+const handleAddRoom = (floor: number) => {
|
|
|
|
|
+ if (!selectedBuilding.value) return;
|
|
|
|
|
+
|
|
|
|
|
+ roomDialog.title = '添加房间';
|
|
|
|
|
+ roomDialog.roomId = undefined;
|
|
|
|
|
+ roomDialog.floorNumber = floor;
|
|
|
|
|
+ roomDialog.buildingId = selectedBuilding.value.id;
|
|
|
|
|
+ roomDialog.visible = true;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+/** 编辑房间 */
|
|
|
|
|
+const handleEditRoom = (room: RoomInfo) => {
|
|
|
|
|
+ roomDialog.title = '编辑房间';
|
|
|
|
|
+ roomDialog.roomId = room.roomId;
|
|
|
|
|
+ roomDialog.floorNumber = room.floorNumber;
|
|
|
|
|
+ roomDialog.buildingId = room.buildingId;
|
|
|
|
|
+ roomDialog.visible = true;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+/** 删除房间 */
|
|
|
|
|
+const handleDeleteRoom = (row: RoomInfo) => {
|
|
|
|
|
+ ElMessageBox.confirm(`确定要删除房间 ${row.roomName} 吗?`, '警告', {
|
|
|
|
|
+ confirmButtonText: '确定',
|
|
|
|
|
+ cancelButtonText: '取消',
|
|
|
|
|
+ type: 'warning'
|
|
|
|
|
+ })
|
|
|
|
|
+ .then(async () => {
|
|
|
|
|
+ try {
|
|
|
|
|
+ // await delRoom(row.roomId);
|
|
|
|
|
+ // 模拟删除成功
|
|
|
|
|
+ ElMessage.success('删除成功');
|
|
|
|
|
+ loadRoomData();
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('删除房间失败', error);
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ .catch(() => {});
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+/** 房间操作成功回调 */
|
|
|
|
|
+const handleRoomSuccess = () => {
|
|
|
|
|
+ loadRoomData();
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+/** 管理床位 */
|
|
|
|
|
+const handleManageBeds = async (room: RoomInfo) => {
|
|
|
|
|
+ bedManageDialog.roomId = room.roomId;
|
|
|
|
|
+ bedManageDialog.roomName = room.roomName;
|
|
|
|
|
+ bedManageDialog.visible = true;
|
|
|
|
|
+
|
|
|
|
|
+ await loadBedData(room.roomId);
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+/** 加载床位数据 */
|
|
|
|
|
+const loadBedData = async (roomId: string | number) => {
|
|
|
|
|
+ bedLoading.value = true;
|
|
|
|
|
+ try {
|
|
|
|
|
+ // const res = await listBeds(roomId);
|
|
|
|
|
+ // 使用模拟数据
|
|
|
|
|
+ const res = getMockBeds(roomId);
|
|
|
|
|
+ bedList.value = res.data;
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('获取床位列表失败', error);
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ bedLoading.value = false;
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+/** 添加床位 */
|
|
|
|
|
+const handleAddBed = () => {
|
|
|
|
|
+ bedDialog.title = '添加床位';
|
|
|
|
|
+ bedDialog.bedId = undefined;
|
|
|
|
|
+ bedDialog.roomId = bedManageDialog.roomId;
|
|
|
|
|
+ bedDialog.visible = true;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+/** 编辑床位 */
|
|
|
|
|
+const handleEditBed = (bed: BedInfo) => {
|
|
|
|
|
+ bedDialog.title = '编辑床位';
|
|
|
|
|
+ bedDialog.bedId = bed.bedId;
|
|
|
|
|
+ bedDialog.roomId = bed.roomId;
|
|
|
|
|
+ bedDialog.visible = true;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+/** 删除床位 */
|
|
|
|
|
+const handleDeleteBed = (row: BedInfo) => {
|
|
|
|
|
+ ElMessageBox.confirm(`确定要删除床位 ${row.bedName} 吗?`, '警告', {
|
|
|
|
|
+ confirmButtonText: '确定',
|
|
|
|
|
+ cancelButtonText: '取消',
|
|
|
|
|
+ type: 'warning'
|
|
|
|
|
+ })
|
|
|
|
|
+ .then(async () => {
|
|
|
|
|
+ try {
|
|
|
|
|
+ // await delBed(row.bedId);
|
|
|
|
|
+ // 模拟删除成功
|
|
|
|
|
+ ElMessage.success('删除成功');
|
|
|
|
|
+ loadBedData(bedManageDialog.roomId);
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('删除床位失败', error);
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ .catch(() => {});
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+/** 床位操作成功回调 */
|
|
|
|
|
+const handleBedSuccess = () => {
|
|
|
|
|
+ loadBedData(bedManageDialog.roomId);
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+onMounted(() => {
|
|
|
|
|
+ getDormTreeData();
|
|
|
|
|
+
|
|
|
|
|
+ // 监听宿舍楼名称变化
|
|
|
|
|
+ nextTick(() => {
|
|
|
|
|
+ buildingName.value = '';
|
|
|
|
|
+ watchBuildingName();
|
|
|
|
|
+ });
|
|
|
|
|
+});
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
|
|
+<style scoped>
|
|
|
|
|
+.room-container {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.room-grid {
|
|
|
|
|
+ display: grid;
|
|
|
|
|
+ grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
|
|
|
|
|
+ gap: 16px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.room-card {
|
|
|
|
|
+ margin-bottom: 0;
|
|
|
|
|
+ transition: all 0.3s;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.room-card:hover {
|
|
|
|
|
+ transform: translateY(-5px);
|
|
|
|
|
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.room-disabled {
|
|
|
|
|
+ opacity: 0.7;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.room-info {
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.empty-tip {
|
|
|
|
|
+ min-height: 400px;
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|