提交宿舍房间设置的前端界面
This commit is contained in:
1 parent
7ce20647f0
commit
12b4b58647
28 files changed
+1623
-17
No files matched your search
@@ -0,0 +1,62 @@
|
||||
# 宿舍楼房间管理功能开发记录
|
||||
|
||||
**日期:** 2025-07-03 14:30:25
|
||||
**开发人员:** Cursor
|
||||
**功能模块:** 学生宿舍管理系统 - 宿舍楼房间管理
|
||||
|
||||
## 变更内容
|
||||
|
||||
### 1. 功能概述
|
||||
|
||||
开发了宿舍楼房间管理界面,实现了以下功能:
|
||||
- 左侧树形结构展示校区-宿舍区-宿舍楼的层级关系
|
||||
- 右侧按楼层展示房间信息,采用卡片式布局
|
||||
- 支持房间的添加、编辑、删除操作
|
||||
- 支持床位的添加、编辑、删除操作
|
||||
- 支持按房间号和状态进行筛选
|
||||
|
||||
### 2. 文件变更
|
||||
|
||||
#### 新增文件
|
||||
- `web/src/views/xsssfjgl/index.vue` - 宿舍楼房间管理主界面
|
||||
- `web/src/views/xsssfjgl/components/RoomDialog.vue` - 房间编辑对话框组件
|
||||
- `web/src/views/xsssfjgl/components/BedDialog.vue` - 床位编辑对话框组件
|
||||
- `web/src/api/xsssfjgl/index.ts` - API接口实现
|
||||
- `web/src/api/xsssfjgl/types.ts` - API类型定义
|
||||
|
||||
### 3. 技术实现
|
||||
|
||||
#### 3.1 树形结构设计
|
||||
- 采用Element Plus的Tree组件实现
|
||||
- 配置了disabled属性,使校区和宿舍区节点不可选
|
||||
- 只有宿舍楼节点可以被选中,并触发右侧数据加载
|
||||
|
||||
#### 3.2 房间展示
|
||||
- 按楼层分组展示房间信息
|
||||
- 使用Grid布局实现自适应卡片排列
|
||||
- 每张卡片包含房间号、类型、床位使用情况和操作按钮
|
||||
|
||||
#### 3.3 床位管理
|
||||
- 点击"床位管理"按钮弹出对话框
|
||||
- 表格展示该房间的所有床位信息
|
||||
- 支持床位的增删改操作
|
||||
|
||||
#### 3.4 数据处理
|
||||
- 前期使用模拟数据进行界面开发
|
||||
- 预留了真实API接口,便于后期接入后端服务
|
||||
- 完整实现了增删改查的前端逻辑
|
||||
|
||||
## 后续工作
|
||||
|
||||
1. 对接后端API,替换模拟数据
|
||||
2. 根据实际业务需求调整界面细节
|
||||
3. 增加权限控制逻辑
|
||||
4. 完善数据校验和错误处理
|
||||
5. 添加单元测试
|
||||
|
||||
## 注意事项
|
||||
|
||||
- 目前使用模拟数据,未与后端对接
|
||||
- 表单校验规则已基本实现,但可能需要根据业务规则调整
|
||||
- v-model:show-search 等指令存在linter错误,后续需要修复
|
||||
- 组件导入和类型引用存在linter错误,需要调整项目配置
|
||||
@@ -0,0 +1,489 @@
|
||||
# 宿舍房间管理API文档
|
||||
|
||||
**版本:** 1.0.0
|
||||
**作者:** Cursor
|
||||
**更新日期:** 2025-07-03
|
||||
|
||||
## 目录
|
||||
|
||||
- [1. 概述](#1-概述)
|
||||
- [2. 接口基础信息](#2-接口基础信息)
|
||||
- [3. 宿舍楼树形结构接口](#3-宿舍楼树形结构接口)
|
||||
- [4. 房间管理接口](#4-房间管理接口)
|
||||
- [5. 床位管理接口](#5-床位管理接口)
|
||||
- [6. 数据字典](#6-数据字典)
|
||||
- [7. 错误码说明](#7-错误码说明)
|
||||
- [8. 移动端实现](#8-移动端实现)
|
||||
|
||||
## 1. 概述
|
||||
|
||||
本文档描述了宿舍楼房间管理模块的接口规范,包括宿舍楼树形结构查询、房间增删改查和床位管理等功能。
|
||||
|
||||
### 1.1 应用场景
|
||||
|
||||
- 学工处管理宿舍楼房间信息
|
||||
- 学生宿舍分配
|
||||
- 宿舍房间和床位状态维护
|
||||
|
||||
### 1.2 功能列表
|
||||
|
||||
- 宿舍楼树形结构查询
|
||||
- 房间列表查询(支持分页和条件筛选)
|
||||
- 房间新增、修改、删除
|
||||
- 床位列表查询
|
||||
- 床位新增、修改、删除
|
||||
|
||||
## 2. 接口基础信息
|
||||
|
||||
### 2.1 接口规范
|
||||
|
||||
- 接口采用RESTful风格
|
||||
- 请求和响应数据格式均为JSON
|
||||
- 所有接口均需要携带Token进行认证
|
||||
- 接口基础路径: `/xsssfjgl`
|
||||
|
||||
### 2.2 统一响应格式
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200, // 响应状态码,200表示成功
|
||||
"msg": "操作成功", // 响应消息
|
||||
"data": {} // 响应数据,根据接口定义不同而不同
|
||||
}
|
||||
```
|
||||
|
||||
### 2.3 分页查询响应格式
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "查询成功",
|
||||
"rows": [], // 数据列表
|
||||
"total": 0 // 总记录数
|
||||
}
|
||||
```
|
||||
|
||||
## 3. 宿舍楼树形结构接口
|
||||
|
||||
### 3.1 获取宿舍树形结构
|
||||
|
||||
**接口说明:** 获取校区-宿舍区-宿舍楼的树形结构数据
|
||||
|
||||
- **请求方式:** GET
|
||||
- **请求路径:** `/xsssfjgl/tree`
|
||||
- **请求参数:** 无
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"data": [
|
||||
{
|
||||
"id": 1,
|
||||
"label": "东校区",
|
||||
"type": "campus",
|
||||
"disabled": true,
|
||||
"children": [
|
||||
{
|
||||
"id": 11,
|
||||
"label": "东区宿舍",
|
||||
"type": "area",
|
||||
"disabled": true,
|
||||
"children": [
|
||||
{
|
||||
"id": 111,
|
||||
"label": "东区1号楼",
|
||||
"type": "building",
|
||||
"buildingFloors": 6
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**字段说明:**
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
| ---- | ---- | ---- |
|
||||
| id | string/number | 节点ID |
|
||||
| label | string | 节点名称 |
|
||||
| type | string | 节点类型:campus(校区)、area(宿舍区)、building(宿舍楼) |
|
||||
| disabled | boolean | 是否禁用选择 |
|
||||
| children | array | 子节点 |
|
||||
| buildingFloors | number | 宿舍楼层数,仅type为building时有效 |
|
||||
|
||||
## 4. 房间管理接口
|
||||
|
||||
### 4.1 获取房间列表
|
||||
|
||||
**接口说明:** 分页查询房间信息
|
||||
|
||||
- **请求方式:** GET
|
||||
- **请求路径:** `/xsssfjgl/room/list`
|
||||
- **请求参数:**
|
||||
|
||||
| 参数名 | 必填 | 类型 | 说明 |
|
||||
| ---- | ---- | ---- | ---- |
|
||||
| pageNum | 是 | number | 页码,从1开始 |
|
||||
| pageSize | 是 | number | 每页记录数 |
|
||||
| buildingId | 是 | string/number | 宿舍楼ID |
|
||||
| roomName | 否 | string | 房间名称,支持模糊查询 |
|
||||
| floorNumber | 否 | number | 楼层号 |
|
||||
| status | 否 | string | 房间状态:0-正常,1-维修中,2-停用 |
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "查询成功",
|
||||
"rows": [
|
||||
{
|
||||
"roomId": "111101",
|
||||
"roomName": "101",
|
||||
"floorNumber": 1,
|
||||
"buildingId": 111,
|
||||
"capacity": 4,
|
||||
"used": 2,
|
||||
"roomType": "标准间",
|
||||
"status": "0",
|
||||
"remark": "",
|
||||
"createBy": "admin",
|
||||
"createTime": "2023-01-01 00:00:00",
|
||||
"updateBy": "admin",
|
||||
"updateTime": "2023-01-01 00:00:00"
|
||||
}
|
||||
],
|
||||
"total": 60
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 获取房间详情
|
||||
|
||||
**接口说明:** 根据房间ID获取详细信息
|
||||
|
||||
- **请求方式:** GET
|
||||
- **请求路径:** `/xsssfjgl/room/{roomId}`
|
||||
- **请求参数:**
|
||||
|
||||
| 参数名 | 必填 | 类型 | 说明 |
|
||||
| ---- | ---- | ---- | ---- |
|
||||
| roomId | 是 | string/number | 房间ID |
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"data": {
|
||||
"roomId": "111101",
|
||||
"roomName": "101",
|
||||
"floorNumber": 1,
|
||||
"buildingId": 111,
|
||||
"capacity": 4,
|
||||
"used": 2,
|
||||
"roomType": "标准间",
|
||||
"status": "0",
|
||||
"remark": "",
|
||||
"createBy": "admin",
|
||||
"createTime": "2023-01-01 00:00:00",
|
||||
"updateBy": "admin",
|
||||
"updateTime": "2023-01-01 00:00:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 新增房间
|
||||
|
||||
**接口说明:** 新增宿舍房间
|
||||
|
||||
- **请求方式:** POST
|
||||
- **请求路径:** `/xsssfjgl/room`
|
||||
- **请求参数:**
|
||||
|
||||
```json
|
||||
{
|
||||
"roomName": "101",
|
||||
"floorNumber": 1,
|
||||
"buildingId": 111,
|
||||
"capacity": 4,
|
||||
"roomType": "标准间",
|
||||
"status": "0",
|
||||
"remark": "新增房间"
|
||||
}
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功"
|
||||
}
|
||||
```
|
||||
|
||||
### 4.4 修改房间
|
||||
|
||||
**接口说明:** 修改宿舍房间信息
|
||||
|
||||
- **请求方式:** PUT
|
||||
- **请求路径:** `/xsssfjgl/room`
|
||||
- **请求参数:**
|
||||
|
||||
```json
|
||||
{
|
||||
"roomId": "111101",
|
||||
"roomName": "101",
|
||||
"floorNumber": 1,
|
||||
"buildingId": 111,
|
||||
"capacity": 4,
|
||||
"roomType": "标准间",
|
||||
"status": "0",
|
||||
"remark": "修改房间信息"
|
||||
}
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功"
|
||||
}
|
||||
```
|
||||
|
||||
### 4.5 删除房间
|
||||
|
||||
**接口说明:** 删除宿舍房间
|
||||
|
||||
- **请求方式:** DELETE
|
||||
- **请求路径:** `/xsssfjgl/room/{roomIds}`
|
||||
- **请求参数:**
|
||||
|
||||
| 参数名 | 必填 | 类型 | 说明 |
|
||||
| ---- | ---- | ---- | ---- |
|
||||
| roomIds | 是 | string | 房间ID,多个ID用逗号分隔 |
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功"
|
||||
}
|
||||
```
|
||||
|
||||
## 5. 床位管理接口
|
||||
|
||||
### 5.1 获取床位列表
|
||||
|
||||
**接口说明:** 查询指定房间的床位列表
|
||||
|
||||
- **请求方式:** GET
|
||||
- **请求路径:** `/xsssfjgl/bed/list`
|
||||
- **请求参数:**
|
||||
|
||||
| 参数名 | 必填 | 类型 | 说明 |
|
||||
| ---- | ---- | ---- | ---- |
|
||||
| roomId | 是 | string/number | 房间ID |
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"data": [
|
||||
{
|
||||
"bedId": "111101-1",
|
||||
"bedName": "1号床",
|
||||
"roomId": "111101",
|
||||
"status": "0",
|
||||
"studentId": null,
|
||||
"studentName": null,
|
||||
"remark": "",
|
||||
"createBy": "admin",
|
||||
"createTime": "2023-01-01 00:00:00",
|
||||
"updateBy": "admin",
|
||||
"updateTime": "2023-01-01 00:00:00"
|
||||
},
|
||||
{
|
||||
"bedId": "111101-2",
|
||||
"bedName": "2号床",
|
||||
"roomId": "111101",
|
||||
"status": "1",
|
||||
"studentId": 10001,
|
||||
"studentName": "张三",
|
||||
"remark": "",
|
||||
"createBy": "admin",
|
||||
"createTime": "2023-01-01 00:00:00",
|
||||
"updateBy": "admin",
|
||||
"updateTime": "2023-01-01 00:00:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 5.2 新增床位
|
||||
|
||||
**接口说明:** 新增床位
|
||||
|
||||
- **请求方式:** POST
|
||||
- **请求路径:** `/xsssfjgl/bed`
|
||||
- **请求参数:**
|
||||
|
||||
```json
|
||||
{
|
||||
"bedName": "3号床",
|
||||
"roomId": "111101",
|
||||
"status": "0",
|
||||
"remark": "新增床位"
|
||||
}
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功"
|
||||
}
|
||||
```
|
||||
|
||||
### 5.3 修改床位
|
||||
|
||||
**接口说明:** 修改床位信息
|
||||
|
||||
- **请求方式:** PUT
|
||||
- **请求路径:** `/xsssfjgl/bed`
|
||||
- **请求参数:**
|
||||
|
||||
```json
|
||||
{
|
||||
"bedId": "111101-3",
|
||||
"bedName": "3号床",
|
||||
"roomId": "111101",
|
||||
"status": "1",
|
||||
"remark": "修改床位信息"
|
||||
}
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功"
|
||||
}
|
||||
```
|
||||
|
||||
### 5.4 删除床位
|
||||
|
||||
**接口说明:** 删除床位
|
||||
|
||||
- **请求方式:** DELETE
|
||||
- **请求路径:** `/xsssfjgl/bed/{bedIds}`
|
||||
- **请求参数:**
|
||||
|
||||
| 参数名 | 必填 | 类型 | 说明 |
|
||||
| ---- | ---- | ---- | ---- |
|
||||
| bedIds | 是 | string | 床位ID,多个ID用逗号分隔 |
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功"
|
||||
}
|
||||
```
|
||||
|
||||
## 6. 数据字典
|
||||
|
||||
### 6.1 房间状态
|
||||
|
||||
| 状态码 | 说明 |
|
||||
| ---- | ---- |
|
||||
| 0 | 正常 |
|
||||
| 1 | 维修中 |
|
||||
| 2 | 停用 |
|
||||
|
||||
### 6.2 床位状态
|
||||
|
||||
| 状态码 | 说明 |
|
||||
| ---- | ---- |
|
||||
| 0 | 空闲 |
|
||||
| 1 | 已分配 |
|
||||
| 2 | 维修中 |
|
||||
|
||||
### 6.3 房间类型
|
||||
|
||||
| 类型 | 说明 |
|
||||
| ---- | ---- |
|
||||
| 标准间 | 标准宿舍,通常4-6人 |
|
||||
| 单人间 | 单人宿舍 |
|
||||
| 套间 | 带独立卫浴的宿舍 |
|
||||
|
||||
## 7. 错误码说明
|
||||
|
||||
| 错误码 | 说明 |
|
||||
| ---- | ---- |
|
||||
| 200 | 操作成功 |
|
||||
| 400 | 请求参数错误 |
|
||||
| 401 | 未授权 |
|
||||
| 403 | 禁止访问 |
|
||||
| 404 | 资源不存在 |
|
||||
| 500 | 系统内部错误 |
|
||||
| 1001 | 房间名称已存在 |
|
||||
| 1002 | 房间包含已分配的床位,无法删除 |
|
||||
| 1003 | 床位已分配给学生,无法删除 |
|
||||
|
||||
## 8. 移动端实现
|
||||
|
||||
### 8.1 移动端适配说明
|
||||
|
||||
移动端将实现以下功能:
|
||||
- 宿舍楼列表查看(无树形结构,改用列表+筛选)
|
||||
- 房间信息查看
|
||||
- 床位信息查看
|
||||
|
||||
暂不支持在移动端进行房间和床位的增删改操作,仅支持查询功能。
|
||||
|
||||
### 8.2 特殊API
|
||||
|
||||
移动端将使用与PC端相同的API,但增加以下特殊接口:
|
||||
|
||||
**获取宿舍楼列表:**
|
||||
|
||||
- **请求方式:** GET
|
||||
- **请求路径:** `/xsssfjgl/mobile/buildings`
|
||||
- **请求参数:**
|
||||
|
||||
| 参数名 | 必填 | 类型 | 说明 |
|
||||
| ---- | ---- | ---- | ---- |
|
||||
| campusId | 否 | string/number | 校区ID |
|
||||
| areaId | 否 | string/number | 宿舍区ID |
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"data": [
|
||||
{
|
||||
"buildingId": 111,
|
||||
"buildingName": "东区1号楼",
|
||||
"campusName": "东校区",
|
||||
"areaName": "东区宿舍",
|
||||
"floors": 6
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,260 @@
|
||||
import request from '@/utils/request';
|
||||
import { DormQuery, RoomForm, BedForm, DormTreeNode, RoomInfo, BedInfo } from './types';
|
||||
|
||||
// API前缀
|
||||
const baseUrl = '/xsssfjgl';
|
||||
|
||||
/**
|
||||
* 获取宿舍树形结构
|
||||
*/
|
||||
export function getDormTree() {
|
||||
return request({
|
||||
url: baseUrl + '/tree',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取房间列表
|
||||
* @param query 查询条件
|
||||
* @returns 房间列表
|
||||
*/
|
||||
export function listRooms(query: DormQuery) {
|
||||
return request({
|
||||
url: baseUrl + '/room/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取房间详情
|
||||
* @param roomId 房间ID
|
||||
* @returns 房间详情
|
||||
*/
|
||||
export function getRoom(roomId: string | number) {
|
||||
return request({
|
||||
url: baseUrl + '/room/' + roomId,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增房间
|
||||
* @param data 房间信息
|
||||
* @returns 结果
|
||||
*/
|
||||
export function addRoom(data: RoomForm) {
|
||||
return request({
|
||||
url: baseUrl + '/room',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改房间
|
||||
* @param data 房间信息
|
||||
* @returns 结果
|
||||
*/
|
||||
export function updateRoom(data: RoomForm) {
|
||||
return request({
|
||||
url: baseUrl + '/room',
|
||||
method: 'put',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除房间
|
||||
* @param roomIds 房间ID字符串
|
||||
* @returns 结果
|
||||
*/
|
||||
export function delRoom(roomIds: string | number) {
|
||||
return request({
|
||||
url: baseUrl + '/room/' + roomIds,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取床位列表
|
||||
* @param roomId 房间ID
|
||||
* @returns 床位列表
|
||||
*/
|
||||
export function listBeds(roomId: string | number) {
|
||||
return request({
|
||||
url: baseUrl + '/bed/list',
|
||||
method: 'get',
|
||||
params: { roomId }
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增床位
|
||||
* @param data 床位信息
|
||||
* @returns 结果
|
||||
*/
|
||||
export function addBed(data: BedForm) {
|
||||
return request({
|
||||
url: baseUrl + '/bed',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改床位
|
||||
* @param data 床位信息
|
||||
* @returns 结果
|
||||
*/
|
||||
export function updateBed(data: BedForm) {
|
||||
return request({
|
||||
url: baseUrl + '/bed',
|
||||
method: 'put',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除床位
|
||||
* @param bedIds 床位ID字符串
|
||||
* @returns 结果
|
||||
*/
|
||||
export function delBed(bedIds: string | number) {
|
||||
return request({
|
||||
url: baseUrl + '/bed/' + bedIds,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
|
||||
// 模拟数据 - 在API接口完成前使用
|
||||
// 生成宿舍树形结构的模拟数据
|
||||
export function getMockDormTree(): { data: DormTreeNode[] } {
|
||||
const mockData: DormTreeNode[] = [
|
||||
{
|
||||
id: 1,
|
||||
label: '东校区',
|
||||
type: 'campus',
|
||||
disabled: true,
|
||||
children: [
|
||||
{
|
||||
id: 11,
|
||||
label: '东区宿舍',
|
||||
type: 'area',
|
||||
disabled: true,
|
||||
children: [
|
||||
{
|
||||
id: 111,
|
||||
label: '东区1号楼',
|
||||
type: 'building',
|
||||
buildingFloors: 6
|
||||
},
|
||||
{
|
||||
id: 112,
|
||||
label: '东区2号楼',
|
||||
type: 'building',
|
||||
buildingFloors: 8
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
label: '西校区',
|
||||
type: 'campus',
|
||||
disabled: true,
|
||||
children: [
|
||||
{
|
||||
id: 21,
|
||||
label: '西区宿舍',
|
||||
type: 'area',
|
||||
disabled: true,
|
||||
children: [
|
||||
{
|
||||
id: 211,
|
||||
label: '西区1号楼',
|
||||
type: 'building',
|
||||
buildingFloors: 7
|
||||
},
|
||||
{
|
||||
id: 212,
|
||||
label: '西区2号楼',
|
||||
type: 'building',
|
||||
buildingFloors: 5
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
return { data: mockData };
|
||||
}
|
||||
|
||||
// 生成房间数据的模拟数据
|
||||
export function getMockRooms(buildingId: string | number, floorNumber?: number): { rows: RoomInfo[], total: number } {
|
||||
const rooms: RoomInfo[] = [];
|
||||
|
||||
// 根据buildingId判断楼层数
|
||||
let floors = 6;
|
||||
if (buildingId === 112) floors = 8;
|
||||
else if (buildingId === 211) floors = 7;
|
||||
else if (buildingId === 212) floors = 5;
|
||||
|
||||
// 如果指定了楼层,只生成该楼层的数据
|
||||
const startFloor = floorNumber || 1;
|
||||
const endFloor = floorNumber || floors;
|
||||
|
||||
for (let floor = startFloor; floor <= endFloor; floor++) {
|
||||
for (let i = 1; i <= 10; i++) {
|
||||
const roomNumber = `${floor}${i.toString().padStart(2, '0')}`;
|
||||
rooms.push({
|
||||
roomId: `${buildingId}${roomNumber}`,
|
||||
roomName: roomNumber,
|
||||
floorNumber: floor,
|
||||
buildingId: buildingId,
|
||||
capacity: 4,
|
||||
used: Math.floor(Math.random() * 5),
|
||||
roomType: '标准间',
|
||||
status: Math.random() > 0.9 ? '1' : '0',
|
||||
remark: '',
|
||||
createBy: 'admin',
|
||||
createTime: '2023-01-01 00:00:00',
|
||||
updateBy: 'admin',
|
||||
updateTime: '2023-01-01 00:00:00'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
rows: rooms.filter(room => !floorNumber || room.floorNumber === floorNumber),
|
||||
total: rooms.length
|
||||
};
|
||||
}
|
||||
|
||||
// 生成床位数据的模拟数据
|
||||
export function getMockBeds(roomId: string | number): { data: BedInfo[] } {
|
||||
const beds: BedInfo[] = [];
|
||||
const capacity = 4;
|
||||
|
||||
for (let i = 1; i <= capacity; i++) {
|
||||
const status = Math.random() > 0.6 ? '1' : '0';
|
||||
beds.push({
|
||||
bedId: `${roomId}-${i}`,
|
||||
bedName: `${i}号床`,
|
||||
roomId: roomId,
|
||||
status: status,
|
||||
studentId: status === '1' ? 10000 + Math.floor(Math.random() * 5000) : undefined,
|
||||
studentName: status === '1' ? `学生${Math.floor(Math.random() * 1000)}` : undefined,
|
||||
remark: '',
|
||||
createBy: 'admin',
|
||||
createTime: '2023-01-01 00:00:00',
|
||||
updateBy: 'admin',
|
||||
updateTime: '2023-01-01 00:00:00'
|
||||
});
|
||||
}
|
||||
|
||||
return { data: beds };
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
// 基础字段类型
|
||||
export interface BaseEntity {
|
||||
createBy: number | string;
|
||||
createTime: string;
|
||||
updateBy: number | string;
|
||||
updateTime: string;
|
||||
}
|
||||
|
||||
// 分页查询参数
|
||||
export interface PageQuery {
|
||||
pageNum: number;
|
||||
pageSize: number;
|
||||
}
|
||||
|
||||
// 树形数据节点类型
|
||||
export interface DormTreeNode {
|
||||
id: string | number;
|
||||
label: string;
|
||||
children?: DormTreeNode[];
|
||||
type: 'campus' | 'area' | 'building'; // 节点类型:校区、宿舍区、宿舍楼
|
||||
disabled?: boolean; // 是否禁用选择
|
||||
buildingFloors?: number; // 宿舍楼层数
|
||||
}
|
||||
|
||||
// 房间信息
|
||||
export interface RoomInfo extends BaseEntity {
|
||||
roomId: string | number;
|
||||
roomName: string;
|
||||
floorNumber: number;
|
||||
buildingId: string | number;
|
||||
capacity: number;
|
||||
used: number;
|
||||
roomType: string;
|
||||
status: string; // 0-正常 1-维修中 2-停用
|
||||
remark: string;
|
||||
}
|
||||
|
||||
// 床位信息
|
||||
export interface BedInfo extends BaseEntity {
|
||||
bedId: string | number;
|
||||
bedName: string;
|
||||
roomId: string | number;
|
||||
status: string; // 0-空闲 1-已分配 2-维修中
|
||||
studentId?: string | number;
|
||||
studentName?: string;
|
||||
remark: string;
|
||||
}
|
||||
|
||||
// 查询参数
|
||||
export interface DormQuery extends PageQuery {
|
||||
buildingId?: string | number;
|
||||
roomName?: string;
|
||||
floorNumber?: number;
|
||||
status?: string;
|
||||
}
|
||||
|
||||
// 房间表单
|
||||
export interface RoomForm {
|
||||
roomId?: string | number;
|
||||
roomName: string;
|
||||
floorNumber: number;
|
||||
buildingId: string | number;
|
||||
capacity: number;
|
||||
roomType: string;
|
||||
status: string;
|
||||
remark?: string;
|
||||
}
|
||||
|
||||
// 床位表单
|
||||
export interface BedForm {
|
||||
bedId?: string | number;
|
||||
bedName: string;
|
||||
roomId: string | number;
|
||||
status: string;
|
||||
remark?: string;
|
||||
}
|
||||
File renamed without changes.
@@ -99,4 +99,8 @@ onMounted(() => {
|
||||
.show-btn {
|
||||
margin-left: 12px;
|
||||
}
|
||||
.top-right-btn {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
</style>
|
||||
+4
-4
@@ -161,10 +161,10 @@ import {
|
||||
updateDormBuilding,
|
||||
listCampusOptions,
|
||||
listAreaTreeData
|
||||
} from '@/api/sslxx/dormBuilding';
|
||||
import { DormBuildingVO, DormBuildingQuery, DormBuildingForm } from '@/api/sslxx/dormBuilding/types';
|
||||
import { DormCampusVO } from '@/api/xqxx/dormCampus/types';
|
||||
import { DormAreaVO } from '@/api/ssqxx/dormArea/types';
|
||||
} from '@/api/xgss/sslxx/dormBuilding';
|
||||
import { DormBuildingVO, DormBuildingQuery, DormBuildingForm } from '@/api/xgss/sslxx/dormBuilding/types';
|
||||
import { DormCampusVO } from '@/api/xgss/xqxx/dormCampus/types';
|
||||
import { DormAreaVO } from '@/api/xgss/ssqxx/dormArea/types';
|
||||
import { getCurrentInstance, ComponentInternalInstance, ref, reactive, toRefs, onMounted } from 'vue';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
+4
-4
@@ -112,10 +112,10 @@
|
||||
</template>
|
||||
|
||||
<script setup name="DormArea" lang="ts">
|
||||
import { listDormArea, getDormArea, delDormArea, addDormArea, updateDormArea } from '@/api/ssqxx/dormArea';
|
||||
import { DormAreaVO, DormAreaQuery, DormAreaForm } from '@/api/ssqxx/dormArea/types';
|
||||
import { listDormCampus } from '@/api/xqxx/dormCampus';
|
||||
import type { DormCampusVO } from '@/api/xqxx/dormCampus/types';
|
||||
import { listDormArea, getDormArea, delDormArea, addDormArea, updateDormArea } from '@/api/xgss/ssqxx/dormArea';
|
||||
import { DormAreaVO, DormAreaQuery, DormAreaForm } from '@/api/xgss/ssqxx/dormArea/types';
|
||||
import { listDormCampus } from '@/api/xgss/xqxx/dormCampus';
|
||||
import type { DormCampusVO } from '@/api/xgss/xqxx/dormCampus/types';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
|
||||
+2
-2
@@ -94,8 +94,8 @@
|
||||
</template>
|
||||
|
||||
<script setup name="DormCampus" lang="ts">
|
||||
import { listDormCampus, getDormCampus, delDormCampus, addDormCampus, updateDormCampus } from '@/api/xqxx/dormCampus';
|
||||
import { DormCampusVO, DormCampusQuery, DormCampusForm } from '@/api/xqxx/dormCampus/types';
|
||||
import { listDormCampus, getDormCampus, delDormCampus, addDormCampus, updateDormCampus } from '@/api/xgss/xqxx/dormCampus';
|
||||
import { DormCampusVO, DormCampusQuery, DormCampusForm } from '@/api/xgss/xqxx/dormCampus/types';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
<template>
|
||||
<el-dialog v-model="visible" :title="title" width="500px" append-to-body @close="closeDialog">
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="床位名称" prop="bedName">
|
||||
<el-input v-model="form.bedName" placeholder="请输入床位名称" maxlength="20" />
|
||||
</el-form-item>
|
||||
<el-form-item label="床位状态" prop="status">
|
||||
<el-radio-group v-model="form.status">
|
||||
<el-radio label="0">空闲</el-radio>
|
||||
<el-radio label="1">已分配</el-radio>
|
||||
<el-radio label="2">维修中</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" type="textarea" placeholder="请输入备注内容" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, watch } from 'vue';
|
||||
import type { FormInstance, FormRules } from 'element-plus';
|
||||
import { BedForm } from '@/api/xgss/xsssfjgl/types';
|
||||
import { addBed, updateBed } from '@/api/xgss/xsssfjgl';
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: boolean;
|
||||
title: string;
|
||||
bedId?: string | number;
|
||||
roomId: string | number;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'success']);
|
||||
|
||||
const formRef = ref<FormInstance>();
|
||||
const visible = ref(false);
|
||||
|
||||
// 表单数据
|
||||
const initFormData: BedForm = {
|
||||
bedName: '',
|
||||
roomId: '',
|
||||
status: '0',
|
||||
remark: ''
|
||||
};
|
||||
|
||||
const form = reactive<BedForm>({ ...initFormData });
|
||||
|
||||
// 表单校验规则
|
||||
const rules = reactive<FormRules>({
|
||||
bedName: [{ required: true, message: '床位名称不能为空', trigger: 'blur' }],
|
||||
status: [{ required: true, message: '床位状态不能为空', trigger: 'change' }]
|
||||
});
|
||||
|
||||
// 监听visible属性变化
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val) => {
|
||||
visible.value = val;
|
||||
if (val) {
|
||||
resetForm();
|
||||
// 设置表单初始值
|
||||
form.roomId = props.roomId;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// 监听visible变化,同步回父组件
|
||||
watch(
|
||||
() => visible.value,
|
||||
(val) => {
|
||||
emit('update:modelValue', val);
|
||||
}
|
||||
);
|
||||
|
||||
// 关闭对话框
|
||||
const closeDialog = () => {
|
||||
visible.value = false;
|
||||
resetForm();
|
||||
};
|
||||
|
||||
// 重置表单
|
||||
const resetForm = () => {
|
||||
Object.assign(form, { ...initFormData });
|
||||
formRef.value?.resetFields();
|
||||
};
|
||||
|
||||
// 提交表单
|
||||
const submitForm = () => {
|
||||
formRef.value?.validate(async (valid) => {
|
||||
if (valid) {
|
||||
try {
|
||||
if (props.bedId) {
|
||||
// 修改
|
||||
form.bedId = props.bedId;
|
||||
await updateBed(form);
|
||||
} else {
|
||||
// 新增
|
||||
await addBed(form);
|
||||
}
|
||||
closeDialog();
|
||||
emit('success');
|
||||
} catch (error) {
|
||||
console.error('操作失败', error);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,136 @@
|
||||
<template>
|
||||
<el-dialog v-model="visible" :title="title" width="500px" append-to-body @close="closeDialog">
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="楼层" prop="floorNumber">
|
||||
<el-input v-model="form.floorNumber" placeholder="请输入楼层" :disabled="true" />
|
||||
</el-form-item>
|
||||
<el-form-item label="房间名称" prop="roomName">
|
||||
<el-input v-model="form.roomName" placeholder="请输入房间名称" maxlength="20" />
|
||||
</el-form-item>
|
||||
<el-form-item label="房间类型" prop="roomType">
|
||||
<el-select v-model="form.roomType" placeholder="请选择房间类型" clearable style="width: 100%">
|
||||
<el-option label="标准间" value="标准间" />
|
||||
<el-option label="单人间" value="单人间" />
|
||||
<el-option label="套间" value="套间" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="床位数量" prop="capacity">
|
||||
<el-input-number v-model="form.capacity" :min="1" :max="8" controls-position="right" style="width: 100%" />
|
||||
</el-form-item>
|
||||
<el-form-item label="房间状态" prop="status">
|
||||
<el-radio-group v-model="form.status">
|
||||
<el-radio label="0">正常</el-radio>
|
||||
<el-radio label="1">维修中</el-radio>
|
||||
<el-radio label="2">停用</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" type="textarea" placeholder="请输入备注内容" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, watch } from 'vue';
|
||||
import type { FormInstance, FormRules } from 'element-plus';
|
||||
import { RoomForm } from '@/api/xgss/xsssfjgl/types';
|
||||
import { addRoom, updateRoom } from '@/api/xgss/xsssfjgl';
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: boolean;
|
||||
title: string;
|
||||
roomId?: string | number;
|
||||
floorNumber: number;
|
||||
buildingId: string | number;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'success']);
|
||||
|
||||
const formRef = ref<FormInstance>();
|
||||
const visible = ref(false);
|
||||
|
||||
// 表单数据
|
||||
const initFormData: RoomForm = {
|
||||
roomName: '',
|
||||
floorNumber: 1,
|
||||
buildingId: '',
|
||||
capacity: 4,
|
||||
roomType: '标准间',
|
||||
status: '0',
|
||||
remark: ''
|
||||
};
|
||||
|
||||
const form = reactive<RoomForm>({ ...initFormData });
|
||||
|
||||
// 表单校验规则
|
||||
const rules = reactive<FormRules>({
|
||||
roomName: [{ required: true, message: '房间名称不能为空', trigger: 'blur' }],
|
||||
floorNumber: [{ required: true, message: '楼层不能为空', trigger: 'blur' }],
|
||||
capacity: [{ required: true, message: '床位数量不能为空', trigger: 'change' }],
|
||||
roomType: [{ required: true, message: '房间类型不能为空', trigger: 'change' }],
|
||||
status: [{ required: true, message: '房间状态不能为空', trigger: 'change' }]
|
||||
});
|
||||
|
||||
// 监听visible属性变化
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val) => {
|
||||
visible.value = val;
|
||||
if (val) {
|
||||
resetForm();
|
||||
// 设置表单初始值
|
||||
form.floorNumber = props.floorNumber;
|
||||
form.buildingId = props.buildingId;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// 监听visible变化,同步回父组件
|
||||
watch(
|
||||
() => visible.value,
|
||||
(val) => {
|
||||
emit('update:modelValue', val);
|
||||
}
|
||||
);
|
||||
|
||||
// 关闭对话框
|
||||
const closeDialog = () => {
|
||||
visible.value = false;
|
||||
resetForm();
|
||||
};
|
||||
|
||||
// 重置表单
|
||||
const resetForm = () => {
|
||||
Object.assign(form, { ...initFormData });
|
||||
formRef.value?.resetFields();
|
||||
};
|
||||
|
||||
// 提交表单
|
||||
const submitForm = () => {
|
||||
formRef.value?.validate(async (valid) => {
|
||||
if (valid) {
|
||||
try {
|
||||
if (props.roomId) {
|
||||
// 修改
|
||||
form.roomId = props.roomId;
|
||||
await updateRoom(form);
|
||||
} else {
|
||||
// 新增
|
||||
await addRoom(form);
|
||||
}
|
||||
closeDialog();
|
||||
emit('success');
|
||||
} catch (error) {
|
||||
console.error('操作失败', error);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
</script>
|
||||
@@ -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>
|
||||
+2
-2
@@ -47,8 +47,8 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, reactive, computed, watch, onMounted } from 'vue';
|
||||
import { getTeacherList } from '@/api/xsssgly/dormManager';
|
||||
import { addDormManager, updateDormManager } from '@/api/ssglyxx/dormManager/index';
|
||||
import { getTeacherList } from '@/api/xgss/xsssgly/dormManager';
|
||||
import { addDormManager, updateDormManager } from '@/api/xgss/ssglyxx/dormManager/index';
|
||||
import { ElMessage } from 'element-plus';
|
||||
|
||||
export default defineComponent({
|
||||
File renamed without changes.
+5
-5
@@ -82,11 +82,11 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, reactive, computed, watch, onMounted } from 'vue';
|
||||
import { listDormCampus } from '@/api/xqxx/dormCampus';
|
||||
import { getAreaTree } from '@/api/ssqxx/dormArea';
|
||||
import { getBuildingTree } from '@/api/sslxx/dormBuilding';
|
||||
import type { TreeSelectVo } from '@/api/ssqxx/dormArea/types';
|
||||
import type { BuildingTreeSelectVo } from '@/api/sslxx/dormBuilding/types';
|
||||
import { listDormCampus } from '@/api/xgss/xqxx/dormCampus';
|
||||
import { getAreaTree } from '@/api/xgss/ssqxx/dormArea';
|
||||
import { getBuildingTree } from '@/api/xgss/sslxx/dormBuilding';
|
||||
import type { TreeSelectVo } from '@/api/xgss/ssqxx/dormArea/types';
|
||||
import type { BuildingTreeSelectVo } from '@/api/xgss/sslxx/dormBuilding/types';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ScopeDialog',
|
||||
File renamed without changes.
Reference in new issue
Block a user