| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829 |
- <template>
- <div class="room-management-container"> <!-- 修改为 room-management-container -->
- <h1>房间管理</h1>
- <!-- 提示信息 -->
- <div v-if="message" :class="['message', messageType]">
- {{ message }}
- </div>
- <button class="add-room-button" @click="showModal = true">新增房间</button>
- <!-- 新增房间的模态框 -->
- <div v-if="showModal" class="modal">
- <div class="modal-content">
- <span class="close" @click="showModal = false">×</span>
- <h2>新增房间</h2>
- <input v-model="newRoomName" placeholder="请输入房间名称" />
- <input v-model="newRoomDescription" placeholder="请输入房间描述" />
- <input v-model="newRoomFloor" placeholder="请输入楼层" type="number" />
- <select v-model="newRoomOrientation">
- <option value="" disabled>请选择朝向</option>
- <option value="东">东</option>
- <option value="南">南</option>
- <option value="西">西</option>
- <option value="北">北</option>
- </select>
- <button class="modal-button" @click="addNewRoom">确定</button>
- </div>
- </div>
- <!-- 显示所有房间的列表 -->
- <h2>所有房间</h2>
- <input v-model="roomFilter" placeholder="搜索房间名称" class="filter-input" />
- <table class="room-table">
- <thead>
- <tr>
- <th>房间名称</th>
- <th>描述</th>
- <th>楼层</th>
- <th>朝向</th>
- <th>操作</th>
- </tr>
- </thead>
- <tbody>
- <tr v-for="room in paginatedRooms" :key="room.id">
- <td>{{ room.room_name }}</td>
- <td>{{ room.description }}</td>
- <td>{{ room.floor }}</td>
- <td>{{ room.orientation }}</td>
- <td>
- <!-- 只有绑定设备的房间才显示"查看设备"按钮 -->
- <button
- v-if="room.device_count > 0"
- class="view-devices-button"
- @click="toggleDevices(room.id)"
- >
- 查看设备
- </button>
- <button class="edit-button" @click="openEditModal(room)">编辑</button>
- </td>
- </tr>
- </tbody>
- </table>
- <div class="pagination">
- <button @click="prevRoomPage" :disabled="currentRoomPage === 1">上一页</button>
- <span>第 {{ currentRoomPage }} 页</span>
- <button @click="nextRoomPage" :disabled="currentRoomPage === totalRoomPages">下一页</button>
- </div>
- <!-- 编辑房间的模态框 -->
- <div v-if="showEditModal" class="modal">
- <div class="modal-content">
- <span class="close" @click="showEditModal = false">×</span>
- <h2>编辑房间</h2>
- <input v-model="editRoom.room_name" placeholder="请输入房间名称" />
- <input v-model="editRoom.description" placeholder="请输入房间描述" />
- <input v-model="editRoom.floor" placeholder="请输入楼层" type="number" />
- <select v-model="editRoom.orientation">
- <option value="" disabled>请选择朝向</option>
- <option value="东">东</option>
- <option value="南">南</option>
- <option value="西">西</option>
- <option value="北">北</option>
- </select>
- <button class="modal-button" @click="saveEditedRoom">保存</button>
- <button
- v-if="editRoom.device_count === 0"
- class="delete-button"
- @click="deleteRoom(editRoom.id)"
- >
- 删除房间
- </button>
- </div>
- </div>
- <!-- 查看设备弹框 -->
- <div v-if="showDevicesModal" class="device-modal">
- <div class="device-modal-content">
- <span class="close" @click="showDevicesModal = false">×</span>
- <h2>已绑定设备</h2>
- <table class="device-table">
- <thead>
- <tr>
- <th>设备ID</th>
- <th>设备名称</th>
- <th>在线状态</th>
- <th>温度</th>
- <th>继电器状态</th>
- <th>人体传感器状态</th>
- <th>操作</th>
- </tr>
- </thead>
- <tbody>
- <tr v-for="device in boundDevices" :key="device.device_id">
- <td>{{ device.device_id }}</td>
- <td>{{ device.name }}</td>
- <td>
- <span :style="{ color: device.status === 'online' ? 'green' : 'red' }">
- {{ device.status === 'online' ? '在线' : '离线' }}
- </span>
- </td>
- <td>{{ device.temperature }}°C</td>
- <td>
- <span :style="{ color: device.switch_status === 'on' ? 'green' : 'red' }">
- {{ device.switch_status === 'on' ? '开启' : '关闭' }}
- </span>
- </td>
- <td>
- <span :style="{ color: device.level_status === 'high' ? 'green' : 'red' }">
- {{ device.level_status === 'high' ? '有人' : '无人' }}
- </span>
- </td>
- <td>
- <!-- 绑定继电器按钮 -->
- <button
- v-if="device.device_id.includes('24G-') && hasRelayInRoom"
- class="bind-button"
- @click="bindRelayToSensor(device.device_id)"
- >
- 绑定继电器
- </button>
- </td>
- </tr>
- </tbody>
- </table>
- </div>
- </div>
- </div>
- </template>
- <script>
- export default {
- name: 'RoomManagement',
- data() {
- return {
- message: '',
- messageType: '',
- rooms: [],
- roomFilter: '',
- showModal: false,
- newRoomName: '',
- newRoomDescription: '',
- newRoomFloor: null,
- newRoomOrientation: '',
- currentRoomPage: 1,
- itemsPerPage: 10,
- showDevicesModal: false,
- boundDevices: [],
- showEditModal: false,
- editRoom: {
- id: null,
- room_name: '',
- description: '',
- floor: null,
- orientation: '',
- device_count: 0,
- },
- hasHumanSensor: false, // 是否有人体传感器
- hasRelayInRoom: false, // 是否有继电器
- roomId: null, // 当前查看的房间ID
- };
- },
- computed: {
- filteredRooms() {
- return this.rooms.filter(room =>
- room.room_name.includes(this.roomFilter)
- );
- },
- paginatedRooms() {
- const start = (this.currentRoomPage - 1) * this.itemsPerPage;
- const end = start + this.itemsPerPage;
- return this.filteredRooms.slice(start, end);
- },
- totalRoomPages() {
- return Math.ceil(this.filteredRooms.length / this.itemsPerPage);
- },
- },
- async created() {
- await this.fetchRooms();
- },
- methods: {
- // 打开编辑房间的模态框
- openEditModal(room) {
- this.editRoom = { ...room }; // 将当前房间信息赋值给 editRoom
- this.showEditModal = true; // 显示编辑模态框
- },
- prevRoomPage() {
- if (this.currentRoomPage > 1) this.currentRoomPage--;
- },
- nextRoomPage() {
- if (this.currentRoomPage < this.totalRoomPages) this.currentRoomPage++;
- },
- async fetchRooms() {
- try {
- // 获取房间列表
- const response = await fetch('/api/rooms');
- if (!response.ok) {
- console.error('Failed to fetch rooms:', response.statusText);
- return;
- }
- const rooms = await response.json();
- // 为每个房间获取绑定的设备数量
- const roomsWithDeviceCount = await Promise.all(
- rooms.map(async (room) => {
- const devicesResponse = await fetch(`/api/devices-by-room?roomId=${room.id}`);
- if (!devicesResponse.ok) {
- console.error('Failed to fetch devices for room:', room.id);
- return { ...room, device_count: 0 };
- }
- const devices = await devicesResponse.json();
- return { ...room, device_count: devices.length };
- })
- );
- this.rooms = roomsWithDeviceCount;
- } catch (error) {
- console.error('Error fetching rooms:', error);
- }
- },
- // 绑定继电器到人体传感器
- async bindRelayToSensor(sensorId) {
- try {
- const response = await fetch('/api/devices/bind-relay-to-sensor', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify({
- sensorId: sensorId,
- roomId: this.roomId,
- }),
- });
- if (response.ok) {
- const result = await response.json();
- this.message = result.message || '继电器绑定成功';
- this.messageType = 'success';
- console.log('bindRelayToSensor 返回结果:', result);
- // 重新获取设备列表以更新界面
- await this.toggleDevices(this.roomId);
- } else {
- const result = await response.json();
- this.message = result.message || '绑定继电器时出错';
- this.messageType = 'error';
- console.error('绑定继电器时出错');
- }
- this.autoHideMessage();
- } catch (error) {
- this.message = '绑定设备时出错';
- this.messageType = 'error';
- console.error('绑定设备时出错:', error);
- this.autoHideMessage();
- }
- },
- async toggleDevices(roomId) {
- this.roomId = roomId; // 保存当前房间ID
- try {
- const response = await fetch('/api/devices-by-room?roomId=' + roomId);
- if (response.ok) {
- this.boundDevices = await response.json();
- // 检查房间中是否同时存在人体传感器和继电器
- this.hasHumanSensor = this.boundDevices.some(
- (device) => device.device_id.includes('24G-')
- );
- this.hasRelayInRoom = this.boundDevices.some(
- (device) => device.device_id.includes('ESP32-')
- );
- this.showDevicesModal = true;
- } else {
- console.error('Failed to fetch devices:', response.statusText);
- }
- } catch (error) {
- console.error('Error fetching devices:', error);
- }
- },
- async addNewRoom() {
- try {
- const response = await fetch('/api/rooms', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify({
- room_name: this.newRoomName,
- description: this.newRoomDescription,
- floor: this.newRoomFloor,
- orientation: this.newRoomOrientation,
- }),
- });
- if (response.ok) {
- const result = await response.json();
- this.message = result.message || '房间新增成功';
- this.messageType = 'success';
- await this.fetchRooms();
- this.showModal = false;
- this.newRoomName = '';
- this.newRoomDescription = '';
- this.newRoomFloor = null;
- this.newRoomOrientation = '';
- } else {
- const result = await response.json();
- this.message = result.message || '新增房间时出错';
- this.messageType = 'error';
- console.error('新增房间时出错');
- }
- this.autoHideMessage();
- } catch (error) {
- this.message = '新增房间时出错';
- this.messageType = 'error';
- console.error('新增房间时出错:', error);
- this.autoHideMessage();
- }
- },
- async saveEditedRoom() {
- try {
- const response = await fetch(`/api/rooms/${this.editRoom.id}`, {
- method: 'PUT',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify(this.editRoom),
- });
- if (response.ok) {
- const result = await response.json();
- this.message = result.message || '房间信息更新成功';
- this.messageType = 'success';
- await this.fetchRooms();
- this.showEditModal = false;
- } else {
- const result = await response.json();
- this.message = result.message || '更新房间信息时出错';
- this.messageType = 'error';
- console.error('更新房间信息时出错');
- }
- this.autoHideMessage();
- } catch (error) {
- this.message = '更新房间信息时出错';
- this.messageType = 'error';
- console.error('更新房间信息时出错:', error);
- this.autoHideMessage();
- }
- },
- async deleteRoom(roomId) {
- try {
- const response = await fetch(`/api/rooms/${roomId}`, {
- method: 'DELETE',
- });
- if (response.ok) {
- this.message = '房间删除成功';
- this.messageType = 'success';
- await this.fetchRooms();
- this.showEditModal = false;
- } else {
- const result = await response.json();
- this.message = result.message || '删除房间时出错';
- this.messageType = 'error';
- console.error('删除房间时出错');
- }
- this.autoHideMessage();
- } catch (error) {
- this.message = '删除房间时出错';
- this.messageType = 'error';
- console.error('删除房间时出错:', error);
- this.autoHideMessage();
- }
- },
- autoHideMessage() {
- setTimeout(() => {
- this.message = '';
- }, 2000);
- },
- },
- };
- </script>
- <style>/* 房间管理界面的整体布局 */
- .room-management-container {
- max-height: 90vh; /* 设置最大高度为视口的 90% */
- overflow-y: auto; /* 启用垂直滚动条 */
- padding: 20px; /* 内边距 */
- background-color: #f5f7fa; /* 背景颜色 */
- }
- /* 主标题样式 */
- .page-title {
- font-size: 24px; /* 字体大小 */
- margin-bottom: 20px; /* 底部外边距 */
- color: #333; /* 字体颜色 */
- text-align: center; /* 文字居中 */
- }
- /* 楼层标题样式 */
- .floor-title {
- font-size: 20px; /* 字体大小 */
- margin-bottom: 15px; /* 底部外边距 */
- color: #555; /* 字体颜色 */
- }
- /* 楼层内容区域样式 */
- .floor-content {
- display: flex; /* 弹性布局 */
- gap: 20px; /* 子元素间距 */
- margin-bottom: 30px; /* 底部外边距 */
- }
- /* 房间列表样式 */
- .room-list {
- flex: 1; /* 占据剩余空间 */
- display: flex; /* 弹性布局 */
- flex-wrap: wrap; /* 允许换行 */
- gap: 10px; /* 子元素间距 */
- }
- /* 房间卡片样式 */
- .room-card {
- flex: 1 1 calc(25% - 10px); /* 每行显示 4 个房间卡片 */
- border: 1px solid #e0e0e0; /* 边框 */
- border-radius: 8px; /* 圆角 */
- padding: 15px; /* 内边距 */
- background-color: #fff; /* 背景颜色 */
- box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1); /* 阴影效果 */
- transition: transform 0.2s, box-shadow 0.2s; /* 过渡效果 */
- }
- /* 房间卡片悬停时的样式 */
- .room-card:hover {
- transform: translateY(-3px); /* 上移效果 */
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15); /* 阴影效果 */
- }
- /* 房间卡片标题样式 */
- .room-card h4 {
- font-size: 18px; /* 字体大小 */
- margin: 0 0 10px; /* 底部外边距 */
- color: #333; /* 字体颜色 */
- }
- /* 房间卡片内容样式 */
- .room-card p {
- font-size: 14px; /* 字体大小 */
- margin: 6px 0; /* 上下外边距 */
- color: #666; /* 字体颜色 */
- }
- /* 房间状态样式 */
- .room-card p span {
- font-weight: 500; /* 字体粗细 */
- }
- /* 房间状态为"有人"时的样式 */
- .room-card.occupied {
- background-color: #fff3cd; /* 背景颜色 */
- }
- /* 房间状态为"无人"时的样式 */
- .room-card.unoccupied {
- background-color: #d4edda; /* 背景颜色 */
- }
- /* 房间状态为"人体存在掉线"时的样式 */
- .room-card.sensor-offline {
- background-color: #f8d7da; /* 背景颜色 */
- }
- /* 房间状态为"离线"时的样式 */
- .room-card.offline {
- background-color: #f8f8f8; /* 背景颜色 */
- color: #999; /* 字体颜色 */
- }
- /* 新增房间按钮样式 */
- .add-room-button {
- background: linear-gradient(135deg, #4caf50, #81c784); /* 渐变背景 */
- color: white; /* 字体颜色 */
- border: none; /* 去除边框 */
- padding: 10px 20px; /* 内边距 */
- border-radius: 6px; /* 圆角 */
- font-size: 16px; /* 字体大小 */
- font-weight: 500; /* 字体粗细 */
- cursor: pointer; /* 鼠标指针 */
- transition: all 0.3s ease; /* 过渡效果 */
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* 阴影效果 */
- margin-bottom: 20px; /* 底部外边距 */
- }
- /* 新增房间按钮悬停时的样式 */
- .add-room-button:hover {
- background: linear-gradient(135deg, #45a049, #6bbf70); /* 渐变背景 */
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); /* 阴影效果 */
- }
- /* 模态框按钮样式 */
- .modal-button {
- background: linear-gradient(135deg, #4caf50, #81c784); /* 渐变背景 */
- color: white; /* 字体颜色 */
- border: none; /* 去除边框 */
- padding: 10px 20px; /* 内边距 */
- border-radius: 6px; /* 圆角 */
- font-size: 16px; /* 字体大小 */
- font-weight: 500; /* 字体粗细 */
- cursor: pointer; /* 鼠标指针 */
- transition: all 0.3s ease; /* 过渡效果 */
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* 阴影效果 */
- margin-top: 10px; /* 顶部外边距 */
- }
- /* 模态框按钮悬停时的样式 */
- .modal-button:hover {
- background: linear-gradient(135deg, #45a049, #6bbf70); /* 渐变背景 */
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); /* 阴影效果 */
- }
- /* 输入框和选择框的样式 */
- .modal-content input,
- .modal-content select {
- width: 100%; /* 宽度 */
- padding: 8px; /* 内边距 */
- border: 1px solid #e0e0e0; /* 边框 */
- border-radius: 6px; /* 圆角 */
- font-size: 14px; /* 字体大小 */
- transition: all 0.3s ease; /* 过渡效果 */
- margin-bottom: 15px; /* 底部外边距 */
- }
- /* 输入框和选择框聚焦时的样式 */
- .modal-content input:focus,
- .modal-content select:focus {
- border-color: #4caf50; /* 边框颜色 */
- box-shadow: 0 0 8px rgba(76, 175, 80, 0.3); /* 阴影效果 */
- outline: none; /* 去除默认的聚焦轮廓 */
- }
- /* 输入框和选择框悬停时的样式 */
- .modal-content input:hover,
- .modal-content select:hover {
- border-color: #4caf50; /* 边框颜色 */
- }
- /* 模态框样式 */
- .modal {
- position: fixed; /* 固定定位 */
- top: 0; /* 顶部距离 */
- left: 0; /* 左侧距离 */
- width: 100%; /* 宽度 */
- height: 100%; /* 高度 */
- background-color: rgba(0, 0, 0, 0.5); /* 背景颜色 */
- display: flex; /* 弹性布局 */
- justify-content: center; /* 水平居中 */
- align-items: center; /* 垂直居中 */
- }
- /* 模态框内容样式 */
- .modal-content {
- background-color: white; /* 背景颜色 */
- padding: 20px; /* 内边距 */
- border-radius: 8px; /* 圆角 */
- width: 400px; /* 宽度 */
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); /* 阴影效果 */
- }
- /* 模态框标题样式 */
- .modal-content h2 {
- margin-top: 0; /* 顶部外边距 */
- color: #333; /* 字体颜色 */
- }
- /* 关闭按钮样式 */
- .close {
- float: right; /* 右浮动 */
- font-size: 24px; /* 字体大小 */
- cursor: pointer; /* 鼠标指针 */
- color: #666; /* 字体颜色 */
- }
- /* 关闭按钮悬停时的样式 */
- .close:hover {
- color: #333; /* 字体颜色 */
- }
- /* 分页按钮的样式 */
- .pagination {
- margin-top: 20px; /* 顶部外边距 */
- text-align: center; /* 文字居中 */
- }
- /* 分页按钮的样式 */
- .pagination button {
- padding: 8px 16px; /* 内边距 */
- border: none; /* 去除边框 */
- border-radius: 6px; /* 圆角 */
- font-size: 14px; /* 字体大小 */
- font-weight: 500; /* 字体粗细 */
- cursor: pointer; /* 鼠标指针 */
- transition: all 0.3s ease; /* 过渡效果 */
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* 阴影效果 */
- background-color: #4caf50; /* 背景颜色 */
- color: white; /* 字体颜色 */
- margin: 0 5px; /* 左右外边距 */
- }
- /* 分页按钮悬停时的样式 */
- .pagination button:hover {
- background-color: #45a049; /* 背景颜色 */
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); /* 阴影效果 */
- }
- /* 分页按钮禁用时的样式 */
- .pagination button:disabled {
- background-color: #e0e0e0; /* 背景颜色 */
- color: #999; /* 字体颜色 */
- cursor: not-allowed; /* 禁用鼠标指针 */
- box-shadow: none; /* 去除阴影 */
- }
- /* 表格样式 */
- .room-table {
- width: 100%; /* 表格宽度 */
- border-collapse: separate; /* 使用 separate 而不是 collapse */
- border-spacing: 0; /* 单元格间距 */
- margin-bottom: 20px; /* 底部外边距 */
- background-color: #fff; /* 背景颜色 */
- border-radius: 8px; /* 圆角 */
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); /* 阴影效果 */
- }
- /* 表头样式 */
- .room-table th {
- background-color: #f8f9fa; /* 表头背景颜色 */
- font-weight: 600; /* 字体粗细 */
- color: #333; /* 字体颜色 */
- padding: 12px; /* 内边距 */
- text-align: center; /* 文字居中 */
- border-bottom: 2px solid #e0e0e0; /* 底部边框 */
- }
- /* 表格数据样式 */
- .room-table td {
- padding: 12px; /* 内边距 */
- text-align: center; /* 文字居中 */
- border-bottom: 1px solid #e0e0e0; /* 底部边框 */
- }
- /* 表格行悬停效果 */
- .room-table tr:hover {
- background-color: #f1f1f1; /* 悬停背景颜色 */
- transition: background-color 0.3s ease; /* 过渡效果 */
- }
- /* 表格最后一行去除底部边框 */
- .room-table tr:last-child td {
- border-bottom: none; /* 去除底部边框 */
- }
- /* 查看设备弹框样式 */
- .device-modal {
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- background-color: rgba(0, 0, 0, 0.5);
- display: flex;
- justify-content: center;
- align-items: center;
- }
- .device-modal-content {
- background-color: white;
- padding: 20px;
- border-radius: 8px;
- width: 80%;
- max-width: 800px;
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
- }
- .device-modal-content h2 {
- margin-top: 0;
- color: #333;
- }
- .device-modal-content .close {
- float: right;
- font-size: 24px;
- cursor: pointer;
- color: #666;
- }
- .device-modal-content .close:hover {
- color: #333;
- }
- /* 设备表格样式 */
- .device-table {
- width: 100%;
- border-collapse: separate;
- border-spacing: 0;
- margin-bottom: 20px;
- background-color: #fff;
- border-radius: 8px;
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
- }
- .device-table th {
- background-color: #f8f9fa;
- font-weight: 600;
- color: #333;
- padding: 12px;
- text-align: center;
- border-bottom: 2px solid #e0e0e0;
- }
- .device-table td {
- padding: 12px;
- text-align: center;
- border-bottom: 1px solid #e0e0e0;
- }
- .device-table tr:hover {
- background-color: #f1f1f1;
- transition: background-color 0.3s ease;
- }
- .device-table tr:last-child td {
- border-bottom: none;
- }
- /* 绑定按钮样式 */
- .bind-button {
- background: linear-gradient(135deg, #4caf50, #81c784);
- color: white;
- border: none;
- padding: 8px 16px;
- border-radius: 6px;
- font-size: 14px;
- font-weight: 500;
- cursor: pointer;
- transition: all 0.3s ease;
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
- }
- .bind-button:hover {
- background: linear-gradient(135deg, #45a049, #6bbf70);
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
- }
- /* 查看设备按钮样式 */
- .view-devices-button {
- background: linear-gradient(135deg, #4caf50, #81c784); /* 渐变背景 */
- color: white; /* 字体颜色 */
- border: none; /* 去除边框 */
- padding: 8px 16px; /* 内边距 */
- border-radius: 6px; /* 圆角 */
- font-size: 14px; /* 字体大小 */
- font-weight: 500; /* 字体粗细 */
- cursor: pointer; /* 鼠标指针 */
- transition: all 0.3s ease; /* 过渡效果 */
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* 阴影效果 */
- margin-right: 8px; /* 右侧外边距 */
- }
- .view-devices-button:hover {
- background: linear-gradient(135deg, #45a049, #6bbf70); /* 渐变背景 */
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); /* 阴影效果 */
- }
- /* 编辑按钮样式 */
- .edit-button {
- background: linear-gradient(135deg, #2196f3, #64b5f6); /* 渐变背景 */
- color: white; /* 字体颜色 */
- border: none; /* 去除边框 */
- padding: 8px 16px; /* 内边距 */
- border-radius: 6px; /* 圆角 */
- font-size: 14px; /* 字体大小 */
- font-weight: 500; /* 字体粗细 */
- cursor: pointer; /* 鼠标指针 */
- transition: all 0.3s ease; /* 过渡效果 */
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* 阴影效果 */
- }
- .edit-button:hover {
- background: linear-gradient(135deg, #1e88e5, #42a5f5); /* 渐变背景 */
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); /* 阴影效果 */
- }
- /* 删除按钮样式 */
- .delete-button {
- background: linear-gradient(135deg, #f44336, #e57373);
- color: white;
- border: none;
- padding: 10px 20px;
- border-radius: 6px;
- font-size: 16px;
- font-weight: 500;
- cursor: pointer;
- transition: all 0.3s ease;
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
- margin-top: 10px;
- }
- .delete-button:hover {
- background: linear-gradient(135deg, #e53935, #d32f2f);
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
- }
- </style>
|