解决合并冲突
This commit is contained in:
commit
067957256d
263 files changed
+34712
-6492
No files matched your search
@@ -1,416 +0,0 @@
|
||||
# 宿舍管理数据库设计文档
|
||||
|
||||
## 📋 文档信息
|
||||
|
||||
| 项目 | 信息 |
|
||||
|------|------|
|
||||
| **项目名称** | 校园管理系统 - 宿舍管理模块 |
|
||||
| **数据库版本** | MySQL 8.0+ |
|
||||
| **文档版本** | V1.0.0 |
|
||||
| **创建时间** | 2025-01-14 |
|
||||
| **创建人员** | 数据库设计团队 |
|
||||
| **审核状态** | 待审核 |
|
||||
|
||||
## 🎯 设计目标
|
||||
|
||||
### 核心目标
|
||||
- 支持多维度宿舍管理人员分配(全校、校区、宿舍区、宿舍楼、二级学院)
|
||||
- 实现多级向下授权功能(5级权限体系)
|
||||
- 支持权限的动态配置和调整
|
||||
- 提供完整的管理效果评估功能
|
||||
- 确保数据安全和审计追踪
|
||||
|
||||
### 设计原则
|
||||
- **分层设计**:按权限层级进行数据分层
|
||||
- **维度扩展**:支持管理维度的灵活扩展
|
||||
- **权限控制**:严格的数据权限控制机制
|
||||
- **审计追踪**:完整的操作日志和变更记录
|
||||
- **性能优化**:针对多维度查询的性能优化
|
||||
|
||||
## 🗄️ 数据库表设计
|
||||
|
||||
### 1. 宿舍管理维度表
|
||||
|
||||
#### 1.1 宿舍管理维度定义表 (dorm_management_dimension)
|
||||
**表说明**:定义宿舍管理的各个维度,支持维度的灵活扩展
|
||||
|
||||
```sql
|
||||
|
||||
```
|
||||
|
||||
#### 1.2 校区信息表 (dorm_campus)
|
||||
**表说明**:存储校区基本信息
|
||||
|
||||
```sql
|
||||
DROP TABLE IF EXISTS `xg_dorm_campus`;
|
||||
CREATE TABLE `xg_dorm_campus` (
|
||||
`id` bigint(20) NOT NULL COMMENT '主键ID',
|
||||
`campus_code` varchar(50) NOT NULL COMMENT '校区编码',
|
||||
`campus_name` varchar(100) NOT NULL COMMENT '校区名称',
|
||||
`campus_description` varchar(500) DEFAULT NULL COMMENT '校区描述',
|
||||
`sort_order` int(11) DEFAULT '0' COMMENT '排序号',
|
||||
`deleted` char(1) DEFAULT '0' COMMENT '删除标志(0代表存在 1代表删除)',
|
||||
`tenant_id` bigint(20) DEFAULT '0' COMMENT '租户编号',
|
||||
`create_by` bigint(20) DEFAULT NULL COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` bigint(20) DEFAULT NULL COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_campus_code` (`campus_code`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='校区信息表';
|
||||
```
|
||||
|
||||
#### 1.3 宿舍区信息表 (dorm_area)
|
||||
**表说明**:存储宿舍区基本信息,关联校区
|
||||
|
||||
```sql
|
||||
DROP TABLE IF EXISTS `xg_dorm_building`;
|
||||
CREATE TABLE `xg_dorm_building` (
|
||||
`id` bigint(20) NOT NULL COMMENT '主键ID',
|
||||
`building_code` varchar(50) NOT NULL COMMENT '宿舍楼编码',
|
||||
`building_name` varchar(100) NOT NULL COMMENT '宿舍楼名称',
|
||||
`area_id` bigint(20) NOT NULL COMMENT '所属宿舍区ID',
|
||||
`campus_id` bigint(20) NOT NULL COMMENT '所属校区ID',
|
||||
`building_type` char(1) DEFAULT '1' COMMENT '宿舍楼类型(1男生楼 2女生楼 3混合楼)',
|
||||
`building_description` varchar(500) DEFAULT NULL COMMENT '宿舍楼描述',
|
||||
`sort_order` int(11) DEFAULT '0' COMMENT '排序号',
|
||||
`deleted` char(1) DEFAULT '0' COMMENT '删除标志(0代表存在 1代表删除)',
|
||||
`tenant_id` bigint(20) DEFAULT '0' COMMENT '租户编号',
|
||||
`create_by` bigint(20) DEFAULT NULL COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` bigint(20) DEFAULT NULL COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_building_code` (`building_code`),
|
||||
KEY `idx_area_id` (`area_id`),
|
||||
KEY `idx_campus_id` (`campus_id`),
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='宿舍楼信息表';
|
||||
```
|
||||
|
||||
#### 1.4 宿舍楼信息表 (dorm_building)
|
||||
**表说明**:存储宿舍楼基本信息,关联宿舍区
|
||||
|
||||
```sql
|
||||
DROP TABLE IF EXISTS `xg_dorm_area`;
|
||||
CREATE TABLE `xg_dorm_area` (
|
||||
`id` bigint(20) NOT NULL COMMENT '主键ID',
|
||||
`area_code` varchar(50) NOT NULL COMMENT '宿舍区编码',
|
||||
`area_name` varchar(100) NOT NULL COMMENT '宿舍区名称',
|
||||
`campus_id` bigint(20) NOT NULL COMMENT '所属校区ID',
|
||||
`area_description` varchar(500) DEFAULT NULL COMMENT '宿舍区描述',
|
||||
`sort_order` int(11) DEFAULT '0' COMMENT '排序号',
|
||||
`deleted` char(1) DEFAULT '0' COMMENT '删除标志(0代表存在 1代表删除)',
|
||||
`tenant_id` bigint(20) DEFAULT '0' COMMENT '租户编号',
|
||||
`create_by` bigint(20) DEFAULT NULL COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` bigint(20) DEFAULT NULL COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_area_code` (`area_code`),
|
||||
KEY `idx_campus_id` (`campus_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='宿舍区信息表';
|
||||
```
|
||||
|
||||
#### 1.5 宿舍房间表 (dorm_room)
|
||||
**表说明**:存储宿舍房间基本信息,关联宿舍楼,包含楼层属性
|
||||
|
||||
```sql
|
||||
DROP TABLE IF EXISTS `xg_dorm_room`;
|
||||
CREATE TABLE `xg_dorm_room` (
|
||||
`id` bigint(20) NOT NULL COMMENT '主键ID',
|
||||
`room_code` varchar(50) NOT NULL COMMENT '房间编号',
|
||||
`room_name` varchar(100) NOT NULL COMMENT '房间名称',
|
||||
`building_id` bigint(20) NOT NULL COMMENT '所属宿舍楼ID',
|
||||
`floor_num` int(11) NOT NULL COMMENT '楼层',
|
||||
`room_type` char(1) DEFAULT '1' COMMENT '房间类型(1学生宿舍 3教师宿舍)',
|
||||
`actual_beds` int(11) DEFAULT 4 COMMENT '实际床位数',
|
||||
`room_area` decimal(10,2) DEFAULT NULL COMMENT '房间面积(平方米)',
|
||||
`room_status` char(1) DEFAULT '0' COMMENT '房间状态(0可用 1维修中 2已报废)',
|
||||
`deleted` char(1) DEFAULT '0' COMMENT '删除标志(0代表存在 1代表删除)',
|
||||
`tenant_id` bigint(20) DEFAULT '0' COMMENT '租户编号',
|
||||
`create_by` bigint(20) DEFAULT NULL COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` bigint(20) DEFAULT NULL COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_room_code` (`room_code`),
|
||||
KEY `idx_building_id` (`building_id`),
|
||||
KEY `idx_floor_num` (`floor_num`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='宿舍房间信息表';
|
||||
```
|
||||
|
||||
#### 1.6 宿舍床位表 (dorm_bed)
|
||||
**表说明**:存储宿舍床位基本信息,关联宿舍房间
|
||||
|
||||
```sql
|
||||
DROP TABLE IF EXISTS `xg_dorm_bed`;
|
||||
CREATE TABLE `xg_dorm_bed` (
|
||||
`id` bigint(20) NOT NULL COMMENT '主键ID',
|
||||
`bed_code` varchar(50) NOT NULL COMMENT '床位编号',
|
||||
`bed_name` varchar(100) NOT NULL COMMENT '床位名称',
|
||||
`room_id` bigint(20) NOT NULL COMMENT '所属房间ID',
|
||||
`bed_type` char(1) DEFAULT '1' COMMENT '床位类型(1下铺 2上铺 3中铺 4独立床)',
|
||||
`bed_status` char(1) DEFAULT '0' COMMENT '床位状态(0空闲 1已分配 2维修中)',
|
||||
`deleted` char(1) DEFAULT '0' COMMENT '删除标志(0代表存在 1代表删除)',
|
||||
`tenant_id` bigint(20) DEFAULT '0' COMMENT '租户编号',
|
||||
`create_by` bigint(20) DEFAULT NULL COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` bigint(20) DEFAULT NULL COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_bed_code` (`bed_code`),
|
||||
KEY `idx_room_id` (`room_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='宿舍床位信息表';
|
||||
|
||||
DROP TABLE IF EXISTS `xg_dorm_bed_student`;
|
||||
CREATE TABLE `xg_dorm_bed_student` (
|
||||
`id` bigint(20) NOT NULL COMMENT '主键ID',
|
||||
`college_id` bigint(20) NOT NULL COMMENT '分配学院ID',
|
||||
`student_id` bigint(20) NOT NULL COMMENT '分配学生ID',
|
||||
`bed_id` bigint(20) NOT NULL COMMENT '床位ID',
|
||||
`room_id` bigint(20) NOT NULL COMMENT '房间ID',
|
||||
`building_id` bigint(20) NOT NULL COMMENT '宿舍楼ID',
|
||||
`area_id` bigint(20) NOT NULL COMMENT '宿舍区ID',
|
||||
`campus_id` bigint(20) NOT NULL COMMENT '校区ID',
|
||||
`status` char(1) DEFAULT '0' COMMENT '状态(0正常 1已退宿)',
|
||||
`assign_time` datetime NOT NULL COMMENT '分配时间',
|
||||
`checkout_time` datetime DEFAULT NULL COMMENT '退宿时间',
|
||||
`deleted` char(1) DEFAULT '0' COMMENT '删除标志(0代表存在 1代表删除)',
|
||||
`tenant_id` bigint(20) DEFAULT '0' COMMENT '租户编号',
|
||||
`create_by` bigint(20) DEFAULT NULL COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` bigint(20) DEFAULT NULL COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_student_bed` (`student_id`, `bed_id`),
|
||||
KEY `idx_college_id` (`college_id`),
|
||||
KEY `idx_student_id` (`student_id`),
|
||||
KEY `idx_bed_id` (`bed_id`),
|
||||
KEY `idx_room_id` (`room_id`),
|
||||
KEY `idx_building_id` (`building_id`),
|
||||
KEY `idx_area_id` (`area_id`),
|
||||
KEY `idx_campus_id` (`campus_id`),
|
||||
KEY `idx_assign_time` (`assign_time`),
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='床位学生分配关系表';
|
||||
```
|
||||
|
||||
### 2. 宿舍管理人员相关表
|
||||
|
||||
#### 2.1 宿舍管理员表 (dorm_manager)
|
||||
**表说明**:存储全校、校区、宿舍区、宿舍楼管理员的基本信息
|
||||
|
||||
```sql
|
||||
DROP TABLE IF EXISTS `xg_dorm_manager`;
|
||||
CREATE TABLE `xg_dorm_manager` (
|
||||
`id` bigint(20) NOT NULL COMMENT '主键ID',
|
||||
`manager_name` varchar(100) NOT NULL COMMENT '管理员姓名',
|
||||
`manager_type` char(1) NOT NULL COMMENT '管理员类型(1全校管理员 2校区管理员 3宿舍区管理员 4宿舍楼管理员)',
|
||||
`manager_level` int(11) DEFAULT 1 COMMENT '管理级别(1-5,1为最高)',
|
||||
`user_id` bigint(20) DEFAULT NULL COMMENT '关联用户ID',
|
||||
`phone` varchar(20) DEFAULT NULL COMMENT '联系电话',
|
||||
`gender` char(1) DEFAULT '0' COMMENT '性别(0男 1女 2未知)',
|
||||
`status` char(1) DEFAULT '0' COMMENT '状态(0正常 1停用)',
|
||||
`deleted` char(1) DEFAULT '0' COMMENT '删除标志(0代表存在 1代表删除)',
|
||||
`tenant_id` bigint(20) DEFAULT '0' COMMENT '租户编号',
|
||||
`create_by` bigint(20) DEFAULT NULL COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` bigint(20) DEFAULT NULL COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_user_id` (`user_id`),
|
||||
KEY `idx_manager_type` (`manager_type`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='宿舍管理员信息表';
|
||||
|
||||
DROP TABLE IF EXISTS `xg_dorm_manager_source`;
|
||||
CREATE TABLE `xg_dorm_manager_source` (
|
||||
`id` bigint(20) NOT NULL COMMENT '主键ID',
|
||||
`manager_id` bigint(20) NOT NULL COMMENT '管理员ID',
|
||||
`permission_type` char(1) DEFAULT '1' COMMENT '权限类型(1查看 2编辑 3完全管理)',
|
||||
`auth_type` char(1) NOT NULL COMMENT '授权类型(1全校级 2校区级 3宿舍区级 4楼栋级)',
|
||||
`auth_source` bigint(20) DEFAULT NULL COMMENT '授权来源ID(对应校区ID或宿舍区ID或楼栋ID)',
|
||||
`status` char(1) DEFAULT '0' COMMENT '状态(0有效 1已撤销)',
|
||||
`deleted` char(1) DEFAULT '0' COMMENT '删除标志(0代表存在 1代表删除)',
|
||||
`tenant_id` bigint(20) DEFAULT '0' COMMENT '租户编号',
|
||||
`create_by` bigint(20) DEFAULT NULL COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` bigint(20) DEFAULT NULL COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_manager_id` (`manager_id`),
|
||||
KEY `idx_auth_source` (`auth_source`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='管理员授权关系表';
|
||||
|
||||
```
|
||||
|
||||
#### 2.2 管理员宿舍楼权限关系表 (dorm_manager_building)
|
||||
**表说明**:存储管理员与宿舍楼的权限绑定关系
|
||||
|
||||
```sql
|
||||
|
||||
|
||||
DROP TABLE IF EXISTS `xg_dorm_manager_building`;
|
||||
CREATE TABLE `xg_dorm_manager_building` (
|
||||
`id` bigint(20) NOT NULL COMMENT '主键ID',
|
||||
`manager_id` bigint(20) NOT NULL COMMENT '管理员ID',
|
||||
`building_id` bigint(20) NOT NULL COMMENT '宿舍楼ID',
|
||||
`status` char(1) DEFAULT '0' COMMENT '状态(0有效 1已撤销)',
|
||||
`deleted` char(1) DEFAULT '0' COMMENT '删除标志(0代表存在 1代表删除)',
|
||||
`tenant_id` bigint(20) DEFAULT '0' COMMENT '租户编号',
|
||||
`create_by` bigint(20) DEFAULT NULL COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` bigint(20) DEFAULT NULL COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_manager_building` (`manager_id`, `building_id`),
|
||||
KEY `idx_manager_id` (`manager_id`),
|
||||
KEY `idx_building_id` (`building_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='管理员宿舍楼权限关系表';
|
||||
```
|
||||
|
||||
#### 2.3 二级学院宿舍管理员表 (dorm_college_manager)
|
||||
**表说明**:存储二级学院宿舍管理员的基本信息
|
||||
|
||||
```sql
|
||||
DROP TABLE IF EXISTS `xg_dorm_college_manager`;
|
||||
CREATE TABLE `xg_dorm_college_manager` (
|
||||
`id` bigint(20) NOT NULL COMMENT '主键ID',
|
||||
`manager_name` varchar(100) NOT NULL COMMENT '管理员姓名',
|
||||
`college_id` bigint(20) NOT NULL COMMENT '所属学院ID',
|
||||
`user_id` bigint(20) DEFAULT NULL COMMENT '关联用户ID',
|
||||
`phone` varchar(20) DEFAULT NULL COMMENT '联系电话',
|
||||
`gender` char(1) DEFAULT '0' COMMENT '性别(0男 1女 2未知)',
|
||||
`status` char(1) DEFAULT '0' COMMENT '状态(0正常 1停用)',
|
||||
`deleted` char(1) DEFAULT '0' COMMENT '删除标志(0代表存在 1代表删除)',
|
||||
`tenant_id` bigint(20) DEFAULT '0' COMMENT '租户编号',
|
||||
`create_by` bigint(20) DEFAULT NULL COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` bigint(20) DEFAULT NULL COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_college_id` (`college_id`),
|
||||
KEY `idx_user_id` (`user_id`),
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='二级学院宿舍管理员信息表';
|
||||
```
|
||||
|
||||
#### 2.4 二级学院床位绑定关系表 (dorm_college_bed)
|
||||
**表说明**:存储二级学院与床位的绑定关系
|
||||
|
||||
```sql
|
||||
DROP TABLE IF EXISTS `xg_dorm_college_bed`;
|
||||
CREATE TABLE `xg_dorm_college_bed` (
|
||||
`id` bigint(20) NOT NULL COMMENT '主键ID',
|
||||
`college_id` bigint(20) NOT NULL COMMENT '学院ID',
|
||||
`bed_id` bigint(20) NOT NULL COMMENT '床位ID',
|
||||
`building_id` bigint(20) NOT NULL COMMENT '宿舍楼ID',
|
||||
`room_id` bigint(20) NOT NULL COMMENT '房间ID',
|
||||
`status` char(1) DEFAULT '0' COMMENT '状态(0正常 1已解除)',
|
||||
`assign_time` datetime DEFAULT NULL COMMENT '分配时间',
|
||||
`release_time` datetime DEFAULT NULL COMMENT '到期解除时间',
|
||||
`deleted` char(1) DEFAULT '0' COMMENT '删除标志(0代表存在 1代表删除)',
|
||||
`tenant_id` bigint(20) DEFAULT '0' COMMENT '租户编号',
|
||||
`create_by` bigint(20) DEFAULT NULL COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` bigint(20) DEFAULT NULL COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_college_bed` (`college_id`, `bed_id`),
|
||||
KEY `idx_college_id` (`college_id`),
|
||||
KEY `idx_bed_id` (`bed_id`),
|
||||
KEY `idx_building_id` (`building_id`),
|
||||
KEY `idx_room_id` (`room_id`),
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='二级学院床位绑定关系表';
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 🔗 表关系设计
|
||||
|
||||
### 1. 维度关系图
|
||||
```
|
||||
dorm_campus (校区)
|
||||
├── dorm_area (宿舍区)
|
||||
│ └── dorm_building (宿舍楼)
|
||||
└── dorm_college (二级学院)
|
||||
```
|
||||
|
||||
### 2. 权限层级关系图
|
||||
```
|
||||
dorm_permission_level (权限层级)
|
||||
├── Level 1: 学生处宿舍管理负责人
|
||||
├── Level 2: 校区宿舍管理负责人
|
||||
├── Level 3: 宿舍区主管
|
||||
├── Level 4: 宿舍楼管理员
|
||||
└── Level 5: 二级学院宿舍管理负责人
|
||||
```
|
||||
|
||||
|
||||
## 📊 索引设计
|
||||
|
||||
### 1. 主键索引
|
||||
- 所有表都使用 `bigint(20)` 类型的自增主键
|
||||
- 主键命名统一为 `id`
|
||||
|
||||
### 2. 唯一索引
|
||||
- 编码字段:`manager_code`, `campus_code`, `area_code`, `building_code`, `college_code`
|
||||
- 身份证号:`id_card`
|
||||
- 权限层级值:`level_value`
|
||||
|
||||
### 3. 复合索引
|
||||
- 管理人员分配:`(manager_id, dimension_type, dimension_id)`
|
||||
- 权限配置:`(manager_id, permission_level_id, dimension_type)`
|
||||
- 统计数据:`(manager_id, dimension_type, dimension_id, stats_date)`
|
||||
|
||||
### 4. 普通索引
|
||||
- 状态字段:`status`, `approval_status`, `permission_status`
|
||||
- 时间字段:`create_time`, `update_time`, `operation_time`
|
||||
- 关联字段:`campus_id`, `area_id`, `position_id`
|
||||
|
||||
## 🔒 数据安全设计
|
||||
|
||||
### 1. 敏感信息加密
|
||||
- 身份证号:使用AES加密存储
|
||||
- 手机号码:部分脱敏显示
|
||||
- 邮箱地址:部分脱敏显示
|
||||
|
||||
### 2. 权限控制
|
||||
- 数据权限:基于维度的数据访问控制
|
||||
- 功能权限:基于角色的功能访问控制
|
||||
- 操作权限:基于权限层级的操作控制
|
||||
|
||||
### 3. 审计日志
|
||||
- 权限变更:完整的权限变更记录
|
||||
- 操作日志:详细的操作行为记录
|
||||
- 数据变更:重要数据的变更追踪
|
||||
|
||||
## 📈 性能优化设计
|
||||
|
||||
### 1. 分区策略
|
||||
- 按时间分区:`dorm_permission_usage` 表按月份分区
|
||||
- 按维度分区:`dorm_management_stats` 表按维度分区
|
||||
|
||||
### 2. 缓存策略
|
||||
- 权限缓存:管理人员权限信息缓存
|
||||
- 维度缓存:维度信息缓存
|
||||
- 统计缓存:统计数据缓存
|
||||
|
||||
### 3. 查询优化
|
||||
- 索引优化:针对多维度查询的复合索引
|
||||
- SQL优化:避免全表扫描的查询语句
|
||||
- 分页优化:大数据量的分页查询优化
|
||||
|
||||
## 📝 变更记录
|
||||
|
||||
| 版本 | 日期 | 变更内容 | 变更人 |
|
||||
|------|------|----------|--------|
|
||||
| V1.0.0 | 2025-01-14 | 初始版本创建 | 数据库设计团队 |
|
||||
@@ -19,6 +19,7 @@
|
||||
- [宿舍管理员授权API](./宿舍管理员授权API.md)
|
||||
- [学生管理员授权关系API](./学生管理员授权关系API.md)
|
||||
- [学生销假管理API](./学生销假管理API.md)
|
||||
- [假期留宿管理API](./假期留宿管理API.md) - **重要修复:单人留宿计算逻辑**(2025-01-03)
|
||||
|
||||
### 1. 用户认证登录
|
||||
|
||||
|
||||
@@ -329,8 +329,269 @@ public interface DormHygieneStudentScoreMapper extends BaseMapperPlus<DormHygien
|
||||
3. 学生数据变更:测试学生数据的增删改
|
||||
4. 历史数据:验证历史数据保留
|
||||
|
||||
### 3. 删除宿舍卫生检查(四表级联删除)
|
||||
|
||||
**接口地址:** `DELETE /dormHygieneCheck/dormHygieneCheck/{ids}`
|
||||
|
||||
**接口描述:** 删除宿舍卫生检查记录,自动级联删除四个相关表的数据
|
||||
|
||||
**涉及表结构:**
|
||||
1. `xg_dorm_hygiene_check` - 宿舍卫生检查主表
|
||||
2. `xg_dorm_hygiene_student_score` - 学生卫生评分表
|
||||
3. `xg_hygiene_check_violation` - 卫生检查违纪关联表
|
||||
4. `xskh_discipline_record` - 学生违纪处分记录表(统一违纪表)
|
||||
|
||||
**请求参数:**
|
||||
- `ids`: 待删除的检查记录ID,支持单个或多个,用逗号分隔
|
||||
|
||||
**请求示例:**
|
||||
```http
|
||||
DELETE /dormHygieneCheck/dormHygieneCheck/1
|
||||
DELETE /dormHygieneCheck/dormHygieneCheck/1,2,3
|
||||
```
|
||||
|
||||
**删除逻辑顺序:**
|
||||
1. **查询关联违纪记录** - 根据检查ID查询 `xg_hygiene_check_violation` 表
|
||||
2. **删除统一违纪记录** - 逻辑删除 `xskh_discipline_record` 表中的违纪处分记录
|
||||
3. **删除违纪关联记录** - 逻辑删除 `xg_hygiene_check_violation` 表中的关联记录
|
||||
4. **删除学生评分记录** - 逻辑删除 `xg_dorm_hygiene_student_score` 表中的评分记录
|
||||
5. **删除主检查记录** - 逻辑删除 `xg_dorm_hygiene_check` 主表记录
|
||||
|
||||
**技术实现要点:**
|
||||
- ✅ **事务管理**: 使用 `@Transactional` 确保四表删除的原子性
|
||||
- ✅ **逻辑删除**: 所有表都使用逻辑删除(`deleted = 1`),不物理删除数据
|
||||
- ✅ **跨模块调用**: 通过反射动态调用学生考核管理模块的删除方法
|
||||
- ✅ **异常处理**: 优雅处理学生考核管理模块未启用的情况
|
||||
- ✅ **日志记录**: 详细记录每个步骤的删除过程和结果
|
||||
|
||||
**响应格式:**
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "删除成功",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
**错误响应:**
|
||||
```json
|
||||
{
|
||||
"code": 500,
|
||||
"msg": "删除宿舍卫生检查记录失败: 具体错误信息",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
**权限要求:**
|
||||
- 需要 `dormHygieneCheck:dormHygieneCheck:remove` 权限
|
||||
|
||||
**注意事项:**
|
||||
1. **数据完整性**: 删除操作会级联删除所有相关数据,请谨慎操作
|
||||
2. **跨模块依赖**: 需要确保学生考核管理模块(xskh)正常运行
|
||||
3. **事务回滚**: 任何一个表删除失败都会导致整个操作回滚
|
||||
4. **日志追踪**: 所有删除操作都有详细日志记录,便于问题排查
|
||||
|
||||
### 删除测试
|
||||
1. **正常删除**: 删除存在关联数据的检查记录
|
||||
2. **级联验证**: 验证四个表的数据都已正确删除
|
||||
3. **事务测试**: 测试删除过程中的异常回滚
|
||||
4. **权限测试**: 测试不同用户的删除权限
|
||||
5. **跨模块测试**: 测试学生考核管理模块未启用时的降级处理
|
||||
|
||||
---
|
||||
|
||||
**文档版本:** v1.0
|
||||
**创建时间:** 2025-01-28
|
||||
**维护人员:** 系统开发团队
|
||||
**维护人员:** 系统开发团队
|
||||
|
||||
---
|
||||
|
||||
## 修复记录
|
||||
|
||||
### 2025-01-29 界面问题修复
|
||||
|
||||
#### 修复问题一:新增时个人扣分默认值显示
|
||||
**问题现象:** 点击新增按钮时,弹窗中房间学生信息列表的个人扣分列显示默认0分placeholder,而不是直接填入0。
|
||||
|
||||
**解决方案:** 修改`DormHygieneCheckDialog.vue`中`loadRoomStudents`方法,将新增模式下学生的`student_score`默认值从`null`改为`0`。
|
||||
|
||||
```javascript
|
||||
// 修改前
|
||||
student_score: student.student_score || null, // 个人得分,默认为空
|
||||
|
||||
// 修改后
|
||||
student_score: 0, // 个人得分,新增时默认为0
|
||||
```
|
||||
|
||||
#### 修复问题二:宿舍扣分变为0时个人扣分不同步更新
|
||||
**问题现象:** 当宿舍扣分从1改成0时,房间学生信息列表中个人扣分还是1,没有变成0。
|
||||
|
||||
**解决方案:** 修改`handleTotalScoreChange`方法,添加对0分的特别处理逻辑。
|
||||
|
||||
```javascript
|
||||
// 修改后的逻辑
|
||||
const handleTotalScoreChange = () => {
|
||||
// 验证宿舍总分范围
|
||||
if (form.totalScore !== null && form.totalScore !== undefined && form.totalScore !== '') {
|
||||
// 处理非0分情况
|
||||
const score = parseFloat(form.totalScore.toString());
|
||||
if (isNaN(score) || score < 0 || score > 100) {
|
||||
ElMessage.warning('宿舍总分必须在0-100分之间');
|
||||
form.totalScore = 0;
|
||||
return;
|
||||
}
|
||||
// 自动为所有学生设置相同的个人得分(包括0分)
|
||||
if (roomStudents.value.length > 0) {
|
||||
roomStudents.value.forEach((student: any) => {
|
||||
student.student_score = score;
|
||||
});
|
||||
ElMessage.success(`已自动为${roomStudents.value.length}名学生设置个人得分:${score}分`);
|
||||
}
|
||||
} else if (form.totalScore === 0 || form.totalScore === '0') {
|
||||
// 特别处理0分的情况
|
||||
if (roomStudents.value.length > 0) {
|
||||
roomStudents.value.forEach((student: any) => {
|
||||
student.student_score = 0;
|
||||
});
|
||||
ElMessage.success(`已自动为${roomStudents.value.length}名学生设置个人得分:0分`);
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
#### 修复问题三:房间排序问题
|
||||
**问题现象:** 选择宿舍楼名称后,房间名称按照sort序号进行排序返回,但因为每层房间的sort都从0开始编码,导致返回数据把每个楼层的第一个房间先返回。
|
||||
|
||||
**解决方案:** 修改后端`XgDormRoomServiceImpl.java`中的`buildQueryWrapper`方法,调整排序逻辑为先按楼层再按sort排序。
|
||||
|
||||
```java
|
||||
// 修改前
|
||||
lqw.orderByAsc(XgDormRoom::getSort); // 第一优先级:按排序号升序
|
||||
lqw.orderByAsc(XgDormRoom::getFloorNum); // 第二优先级:按楼层升序
|
||||
|
||||
// 修改后
|
||||
lqw.orderByAsc(XgDormRoom::getFloorNum); // 第一优先级:按楼层升序
|
||||
lqw.orderByAsc(XgDormRoom::getSort); // 第二优先级:按排序号升序
|
||||
```
|
||||
|
||||
#### 修复效果
|
||||
1. **问题一**:新增时个人扣分直接显示0,用户体验更好
|
||||
2. **问题二**:宿舍扣分与个人扣分完全同步,包括0分的情况
|
||||
3. **问题三**:房间列表按楼层顺序显示,每层内部按sort排序,符合用户期望
|
||||
|
||||
#### 涉及文件
|
||||
- `web/src/views/xg/xgss/dormHygieneCheck/dormHygieneCheck/DormHygieneCheckDialog.vue`
|
||||
- `backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormRoomServiceImpl.java`
|
||||
|
||||
---
|
||||
|
||||
## 违纪记录更新修复 (2025-01-03)
|
||||
|
||||
### 问题描述
|
||||
|
||||
在调用 `updateCompleteData` 接口更新宿舍卫生检查数据时,即使违纪记录入参中包含有效的 `disciplineRecordId`,系统仍然执行了"逻辑删除旧记录 + 新增新记录"的操作,而不是直接更新现有记录。
|
||||
|
||||
### 根本原因
|
||||
|
||||
**数据字段映射错误**:
|
||||
- `XgViolationDataBo` 中的 `id` 字段被误认为是违纪记录ID (`disciplineRecordId`)
|
||||
- 实际上 `id` 字段是关联表 `xg_hygiene_check_violation` 的主键ID
|
||||
- 真正的违纪记录ID应该通过 `disciplineRecordId` 字段传递
|
||||
|
||||
### 修复方案
|
||||
|
||||
#### 1. 扩展 XgViolationDataBo 字段
|
||||
|
||||
**文件**: `backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/domain/bo/XgViolationDataBo.java`
|
||||
|
||||
```java
|
||||
/**
|
||||
* 违纪记录ID(用于更新操作,新增时为null)
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 违纪记录ID,关联xskh_discipline_record.id(用于更新违纪记录)
|
||||
*/
|
||||
private Long disciplineRecordId;
|
||||
```
|
||||
|
||||
#### 2. 修复 handleViolationRecords 方法逻辑
|
||||
|
||||
**文件**: `backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgDormHygieneCheckServiceImpl.java`
|
||||
|
||||
**修复前**:
|
||||
```java
|
||||
newDisciplineIds = newViolationData.stream()
|
||||
.map(XgViolationDataBo::getId) // 错误:使用关联表ID
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet());
|
||||
```
|
||||
|
||||
**修复后**:
|
||||
```java
|
||||
newDisciplineIds = newViolationData.stream()
|
||||
.map(violationBo -> {
|
||||
// 优先使用disciplineRecordId字段,如果为空则使用id字段(向后兼容)
|
||||
return violationBo.getDisciplineRecordId() != null
|
||||
? violationBo.getDisciplineRecordId()
|
||||
: violationBo.getId();
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet());
|
||||
```
|
||||
|
||||
#### 3. 修复判断逻辑
|
||||
|
||||
**修复前**:
|
||||
```java
|
||||
if (violationBo.getId() != null && existingDisciplineIds.contains(violationBo.getId())) {
|
||||
// 更新逻辑
|
||||
}
|
||||
```
|
||||
|
||||
**修复后**:
|
||||
```java
|
||||
Long currentDisciplineRecordId = violationBo.getDisciplineRecordId() != null
|
||||
? violationBo.getDisciplineRecordId()
|
||||
: violationBo.getId();
|
||||
if (currentDisciplineRecordId != null && existingDisciplineIds.contains(currentDisciplineRecordId)) {
|
||||
// 更新逻辑
|
||||
}
|
||||
```
|
||||
|
||||
### 正确的入参格式
|
||||
|
||||
```json
|
||||
{
|
||||
"violationData": [
|
||||
{
|
||||
"id": "1964301377652428802", // 关联表ID (可选)
|
||||
"disciplineRecordId": "1964301377522405377", // 违纪记录ID (用于更新判断)
|
||||
"studentId": "1949114038914949121",
|
||||
"studentNo": "2025DQ21121",
|
||||
"studentName": "梁文清",
|
||||
"disciplineTypeId": "1963793291531026434",
|
||||
"disciplineTypeName": "地面未打扫",
|
||||
"disciplineReason": "未按要求打扫地面",
|
||||
"disciplineContent": "地面有明显垃圾",
|
||||
"scoreDeduction": "2.00",
|
||||
// ... 其他字段
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 修复效果
|
||||
|
||||
1. **准确识别更新操作**:系统能正确识别哪些违纪记录需要更新,哪些需要新增
|
||||
2. **避免重复数据**:不再错误地删除现有记录并新增重复记录
|
||||
3. **向后兼容**:保持对旧版本数据格式的兼容性
|
||||
4. **数据完整性**:确保违纪记录的历史数据完整性
|
||||
|
||||
### 测试验证
|
||||
|
||||
使用修复后的接口,当入参包含 `disciplineRecordId` 时:
|
||||
- ✅ 系统识别为更新操作,直接更新现有违纪记录
|
||||
- ✅ 不再执行逻辑删除 + 新增的错误流程
|
||||
- ✅ 数据库中不会产生重复的违纪记录
|
||||
@@ -302,6 +302,7 @@ xgss:dormRoom:list
|
||||
| floorNum | Integer | 否 | 楼层号,精确查询 |
|
||||
| roomType | String | 否 | 房间类型(1标准间 2单人间 3套间) |
|
||||
| roomStatus | String | 否 | 房间状态(0正常 1维修中 2停用) |
|
||||
| sort | Integer | 否 | 排序号,精确查询 |
|
||||
|
||||
#### 返回结果
|
||||
|
||||
@@ -320,6 +321,7 @@ xgss:dormRoom:list
|
||||
"actualBeds": 4,
|
||||
"roomArea": 20.5,
|
||||
"roomStatus": "0",
|
||||
"sort": 0,
|
||||
"remark": "标准四人间",
|
||||
"createBy": 1,
|
||||
"createTime": "2025-07-22 09:15:30",
|
||||
@@ -337,6 +339,7 @@ xgss:dormRoom:list
|
||||
"actualBeds": 4,
|
||||
"roomArea": 20.5,
|
||||
"roomStatus": "0",
|
||||
"sort": 0,
|
||||
"remark": "标准四人间",
|
||||
"createBy": 1,
|
||||
"createTime": "2025-07-22 09:15:30",
|
||||
@@ -363,6 +366,7 @@ xgss:dormRoom:list
|
||||
| actualBeds | Integer | 实际床位数 |
|
||||
| roomArea | Double | 房间面积(平方米) |
|
||||
| roomStatus | String | 房间状态(0正常 1维修中 2停用) |
|
||||
| sort | Integer | 排序号,数字越小排序越靠前 |
|
||||
| remark | String | 备注 |
|
||||
| createBy | Long | 创建者ID |
|
||||
| createTime | Date | 创建时间 |
|
||||
@@ -371,11 +375,17 @@ xgss:dormRoom:list
|
||||
|
||||
#### 排序规则
|
||||
|
||||
房间列表按照以下顺序排序:
|
||||
1. 优先按楼层号(floorNum)升序排列
|
||||
2. 其次按房间名称(roomName)升序排列
|
||||
房间列表按照以下优先级顺序排序:
|
||||
1. **第一优先级**:按排序号(sort)升序排列
|
||||
2. **第二优先级**:按楼层号(floorNum)升序排列
|
||||
3. **第三优先级**:按房间名称(roomName)升序排列
|
||||
|
||||
这确保了在宿舍管理系统中房间按照从低楼层到高楼层的顺序展示,相同楼层的房间按照名称顺序排列,提供更直观的浏览体验。
|
||||
**排序逻辑说明**:
|
||||
- **自定义排序**:`sort` 字段允许管理员为房间设置自定义排序,数字越小排序越靠前
|
||||
- **默认排序**:当 `sort` 值相同或为0时,按楼层和房间名称的自然顺序排列
|
||||
- **灵活管理**:支持同一楼层内房间的个性化排序需求
|
||||
|
||||
这确保了宿舍管理系统既能保持传统的楼层顺序展示,又能支持管理员根据实际需要进行个性化排序调整。
|
||||
|
||||
#### 错误码
|
||||
|
||||
|
||||
+135
-41
@@ -2,11 +2,13 @@
|
||||
|
||||
## 接口说明
|
||||
|
||||
本文档描述了获取宿舍楼树形结构数据的API接口,该接口返回校区-宿舍区-宿舍楼的三级树形结构,其中校区和宿舍区节点不可选,只有宿舍楼节点可以选择。
|
||||
本文档描述了获取宿舍楼树形结构数据的API接口。**重要变更**:根据业务需求调整,主要接口已从 "校区-宿舍区-宿舍楼" 三级结构改为 "校区-宿舍楼" 二级结构,隐藏宿舍区层级,简化用户操作。
|
||||
|
||||
## 接口定义
|
||||
|
||||
### 获取宿舍楼树形结构
|
||||
### 🔄 主要接口(二级结构)
|
||||
|
||||
#### 1. 获取宿舍楼树形结构(推荐使用)
|
||||
|
||||
**请求URL**:`/sslxx/dormBuilding/buildingTree`
|
||||
|
||||
@@ -14,6 +16,8 @@
|
||||
|
||||
**权限标识**:`sslxx:dormBuilding:list`
|
||||
|
||||
**结构说明**:校区-宿舍楼二级结构,校区不可选,只有宿舍楼可以选择
|
||||
|
||||
**请求参数**:无
|
||||
|
||||
**响应示例**:
|
||||
@@ -30,24 +34,16 @@
|
||||
"disabled": true,
|
||||
"children": [
|
||||
{
|
||||
"id": 101,
|
||||
"label": "东区宿舍区",
|
||||
"nodeType": "area",
|
||||
"disabled": true,
|
||||
"children": [
|
||||
{
|
||||
"id": 1001,
|
||||
"label": "1号楼",
|
||||
"nodeType": "building",
|
||||
"disabled": false
|
||||
},
|
||||
{
|
||||
"id": 1002,
|
||||
"label": "2号楼",
|
||||
"nodeType": "building",
|
||||
"disabled": false
|
||||
}
|
||||
]
|
||||
"id": 1001,
|
||||
"label": "1号楼",
|
||||
"nodeType": "building",
|
||||
"disabled": false
|
||||
},
|
||||
{
|
||||
"id": 1002,
|
||||
"label": "2号楼",
|
||||
"nodeType": "building",
|
||||
"disabled": false
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -58,22 +54,92 @@
|
||||
"disabled": true,
|
||||
"children": [
|
||||
{
|
||||
"id": 201,
|
||||
"label": "西区宿舍区",
|
||||
"nodeType": "area",
|
||||
"id": 2001,
|
||||
"label": "3号楼",
|
||||
"nodeType": "building",
|
||||
"disabled": false
|
||||
},
|
||||
{
|
||||
"id": 2002,
|
||||
"label": "4号楼",
|
||||
"nodeType": "building",
|
||||
"disabled": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. 获取宿舍楼树形结构(基于权限)
|
||||
|
||||
**请求URL**:`/xgss/dormBuildingTree/list`
|
||||
|
||||
**请求方式**:`GET`
|
||||
|
||||
**权限标识**:`xgss:dormBuildingTree:list`
|
||||
|
||||
**结构说明**:校区-宿舍楼二级结构,根据当前用户权限过滤
|
||||
|
||||
**请求参数**:
|
||||
|
||||
| 参数名 | 类型 | 必填 | 描述 |
|
||||
|-----------|--------|------|----------------|
|
||||
| campusId | Long | 否 | 校区ID过滤条件 |
|
||||
| buildingName | String | 否 | 宿舍楼名称过滤条件 |
|
||||
|
||||
**响应格式**:与上述接口相同
|
||||
|
||||
#### 3. 获取所有宿舍楼树形结构(不考虑权限)
|
||||
|
||||
**请求URL**:`/xgss/dormBuildingTree/listAll`
|
||||
|
||||
**请求方式**:`GET`
|
||||
|
||||
**权限标识**:`xgss:dormBuildingTree:list`
|
||||
|
||||
**结构说明**:校区-宿舍楼二级结构,返回所有数据,不进行权限过滤
|
||||
|
||||
**响应格式**:与上述接口相同
|
||||
|
||||
### 📋 特殊用途接口(三级结构)
|
||||
|
||||
#### 4. 获取完整宿舍楼树形结构(包含宿舍区)
|
||||
|
||||
**请求URL**:`/xgss/dormBuildingTree/fullList`
|
||||
|
||||
**请求方式**:`GET`
|
||||
|
||||
**权限标识**:`xgss:dormBuildingTree:list`
|
||||
|
||||
**结构说明**:校区-宿舍区-宿舍楼三级结构,仅用于特殊需求
|
||||
|
||||
**响应示例**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"data": [
|
||||
{
|
||||
"id": 1,
|
||||
"label": "东校区",
|
||||
"type": "campus",
|
||||
"disabled": true,
|
||||
"children": [
|
||||
{
|
||||
"id": 101,
|
||||
"label": "东区宿舍区",
|
||||
"type": "area",
|
||||
"disabled": true,
|
||||
"children": [
|
||||
{
|
||||
"id": 2001,
|
||||
"label": "3号楼",
|
||||
"nodeType": "building",
|
||||
"disabled": false
|
||||
},
|
||||
{
|
||||
"id": 2002,
|
||||
"label": "4号楼",
|
||||
"nodeType": "building",
|
||||
"disabled": false
|
||||
"id": 1001,
|
||||
"label": "1号楼",
|
||||
"type": "building",
|
||||
"disabled": false,
|
||||
"buildingFloors": 6,
|
||||
"buildingType": "1"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -85,7 +151,7 @@
|
||||
|
||||
## 数据结构
|
||||
|
||||
### BuildingTreeSelectVo
|
||||
### BuildingTreeSelectVo(二级结构)
|
||||
|
||||
树形结构节点对象:
|
||||
|
||||
@@ -93,7 +159,7 @@
|
||||
|------------|-------------------|----------------------------------------|
|
||||
| id | Long | 节点ID |
|
||||
| label | String | 节点名称 |
|
||||
| nodeType | String | 节点类型:campus(校区)、area(宿舍区)、building(宿舍楼) |
|
||||
| nodeType | String | 节点类型:campus(校区)、building(宿舍楼) |
|
||||
| disabled | Boolean | 是否禁用选择 |
|
||||
| children | List<BuildingTreeSelectVo> | 子节点列表 |
|
||||
| createBy | Long | 创建者 |
|
||||
@@ -101,6 +167,20 @@
|
||||
| updateBy | Long | 更新者 |
|
||||
| updateTime | Date | 更新时间 |
|
||||
|
||||
### DormBuildingTreeVo(完整结构)
|
||||
|
||||
完整三级结构节点对象:
|
||||
|
||||
| 字段名 | 类型 | 描述 |
|
||||
|-----------------|-------------------|----------------------------------------|
|
||||
| id | Long | 节点ID |
|
||||
| label | String | 节点名称 |
|
||||
| type | String | 节点类型:campus(校区)、area(宿舍区)、building(宿舍楼) |
|
||||
| disabled | Boolean | 是否禁用选择 |
|
||||
| children | List<DormBuildingTreeVo> | 子节点列表 |
|
||||
| buildingFloors | Integer | 宿舍楼层数(仅宿舍楼节点) |
|
||||
| buildingType | String | 宿舍楼类型(仅宿舍楼节点) |
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 前端使用示例
|
||||
@@ -114,7 +194,7 @@ import type { BuildingTreeSelectVo } from '@/api/sslxx/dormBuilding/types';
|
||||
// 在组件的setup函数中
|
||||
const treeData = ref<BuildingTreeSelectVo[]>([]);
|
||||
|
||||
// 加载宿舍楼树形数据
|
||||
// 加载宿舍楼树形数据(推荐使用二级结构)
|
||||
const loadBuildingTree = async () => {
|
||||
try {
|
||||
const res = await getBuildingTree();
|
||||
@@ -155,20 +235,34 @@ loadBuildingTree();
|
||||
|
||||
## 特殊说明
|
||||
|
||||
1. 接口返回的树形结构中,校区和宿舍区节点已设置 `disabled=true`,前端无需额外处理即可实现只能选择宿舍楼节点的效果
|
||||
2. 使用 `check-strictly=true` 可以确保树形选择器的选中状态不会级联影响父子节点
|
||||
3. 该接口已支持管理员分配宿舍楼管理范围的业务需求
|
||||
### ⚠️ 重要变更说明
|
||||
|
||||
1. **主要接口结构调整**:为简化用户操作,去除宿舍区概念,主要接口已改为二级结构
|
||||
2. **向后兼容**:保留了 `fullList` 接口供需要完整三级结构的特殊场景使用
|
||||
3. **业务影响**:前端界面将不再显示宿舍区层级,用户直接在校区下选择宿舍楼
|
||||
|
||||
### 📋 使用建议
|
||||
|
||||
1. **推荐使用二级结构接口**:适用于绝大多数业务场景
|
||||
2. **校区节点设置为不可选**:确保用户只能选择宿舍楼
|
||||
3. **使用权限过滤接口**:根据用户权限显示相应的宿舍楼范围
|
||||
|
||||
## 相关API接口
|
||||
|
||||
- [宿舍管理员授权API](./宿舍管理员授权API.md)
|
||||
- [宿舍床位分配管理API](./宿舍床位分配管理API.md)
|
||||
|
||||
## 数据库关系
|
||||
|
||||
- `xg_dorm_building` 表通过 `campus_id` 字段关联 `xg_dorm_campus` 表
|
||||
- `xg_dorm_building` 表通过 `area_id` 字段关联 `xg_dorm_area` 表
|
||||
- `xg_dorm_building` 表通过 `area_id` 字段关联 `xg_dorm_area` 表(数据库保留,UI隐藏)
|
||||
- `xg_dorm_area` 表通过 `campus_id` 字段关联 `xg_dorm_campus` 表
|
||||
|
||||
## 版本历史
|
||||
|
||||
- **2025-01-29**: 接口结构重大调整,主要接口从三级改为二级结构
|
||||
- **2025-07-20**: 初始版本,三级结构
|
||||
|
||||
## 最后更新时间
|
||||
|
||||
2025-07-20
|
||||
2025-01-29
|
||||
@@ -2186,7 +2186,7 @@ DROP TABLE IF EXISTS `rs_overseas_record_status_backup`;
|
||||
CREATE TABLE `rs_overseas_record_status_backup` (
|
||||
`record_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '记录ID',
|
||||
`completion_status` char(1) DEFAULT '0' COMMENT '完成状态:0-进行中,1-已完成,2-提前结束',
|
||||
`old_status_text` varchar(12) CHARACTER SET latin1 NOT NULL DEFAULT '',
|
||||
`old_status_text` varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '原状态文本',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
@@ -4376,11 +4376,13 @@ CREATE TABLE `xg_dorm_hygiene_check` (
|
||||
`area_name` varchar(100) DEFAULT NULL COMMENT '宿舍区名称',
|
||||
`campus_id` bigint(20) DEFAULT NULL COMMENT '校区ID,关联xg_dorm_campus.id',
|
||||
`campus_name` varchar(100) DEFAULT NULL COMMENT '校区名称',
|
||||
`total_score` decimal(5,2) DEFAULT NULL COMMENT '宿舍总分(0-100分)',
|
||||
`total_score` decimal(5,2) DEFAULT NULL COMMENT '宿舍扣分(0-100分)',
|
||||
`hygiene_grade` char(1) DEFAULT NULL COMMENT '卫生等级(A优秀 B良好 C合格 D不合格)',
|
||||
`attachment_ids` text COMMENT '附件OSS ID列表,逗号分隔',
|
||||
`check_summary` text COMMENT '检查总结',
|
||||
`improvement_suggestions` text COMMENT '整改建议',
|
||||
`discipline_type_id` bigint(20) DEFAULT NULL COMMENT '违纪类型ID,关联xskh_discipline_type.id',
|
||||
`discipline_type_name` varchar(100) DEFAULT NULL COMMENT '违纪类型名称',
|
||||
`check_remarks` varchar(500) DEFAULT NULL COMMENT '检查备注',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
KEY `idx_tenant_id` (`tenant_id`),
|
||||
@@ -4394,6 +4396,7 @@ CREATE TABLE `xg_dorm_hygiene_check` (
|
||||
KEY `idx_hygiene_grade` (`hygiene_grade`),
|
||||
KEY `idx_check_type` (`check_type`),
|
||||
KEY `idx_create_time` (`create_time`),
|
||||
KEY `idx_discipline_type_id` (`discipline_type_id`),
|
||||
KEY `idx_tenant_deleted` (`tenant_id`,`deleted`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='宿舍卫生检查表';
|
||||
|
||||
@@ -4422,7 +4425,7 @@ CREATE TABLE `xg_dorm_hygiene_student_score` (
|
||||
`college_name` varchar(100) DEFAULT NULL COMMENT '学院名称',
|
||||
`bed_id` bigint(20) DEFAULT NULL COMMENT '床位ID,关联xg_dorm_bed.id',
|
||||
`bed_code` varchar(50) DEFAULT NULL COMMENT '床位编号',
|
||||
`student_score` decimal(5,2) DEFAULT NULL COMMENT '学生个人得分(0-100分)',
|
||||
`student_score` decimal(5,2) DEFAULT NULL COMMENT '学生个人扣分(0-100分)',
|
||||
`attendance_status` char(1) DEFAULT '1' COMMENT '出勤状态(1在寝 2外出 3请假 4其他)',
|
||||
`student_grade` char(1) DEFAULT NULL COMMENT '学生评级(A优秀 B良好 C合格 D不合格)',
|
||||
`is_responsible_person` tinyint(1) DEFAULT '0' COMMENT '是否为寝室长(0否 1是)',
|
||||
@@ -4470,29 +4473,6 @@ CREATE TABLE `xg_dorm_manager` (
|
||||
KEY `idx_manager_type` (`manager_type`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='宿舍管理员信息表';
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for xg_dorm_manager_building
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `xg_dorm_manager_building`;
|
||||
CREATE TABLE `xg_dorm_manager_building` (
|
||||
`id` bigint(20) NOT NULL COMMENT '主键ID',
|
||||
`manager_id` bigint(20) NOT NULL COMMENT '管理员ID',
|
||||
`building_id` bigint(20) NOT NULL COMMENT '宿舍楼ID',
|
||||
`status` char(1) DEFAULT '0' COMMENT '状态(0有效 1已撤销)',
|
||||
`deleted` char(1) DEFAULT '0' COMMENT '删除标志(0代表存在 1代表删除)',
|
||||
`tenant_id` bigint(20) DEFAULT '0' COMMENT '租户编号',
|
||||
`create_by` bigint(20) DEFAULT NULL COMMENT '创建者',
|
||||
`create_dept` bigint(20) DEFAULT NULL COMMENT '创建部门',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` bigint(20) DEFAULT NULL COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_manager_building` (`manager_id`,`building_id`),
|
||||
KEY `idx_manager_id` (`manager_id`),
|
||||
KEY `idx_building_id` (`building_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='管理员宿舍楼权限关系表';
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for xg_dorm_manager_source
|
||||
-- ----------------------------
|
||||
@@ -4531,6 +4511,7 @@ CREATE TABLE `xg_dorm_room` (
|
||||
`actual_beds` int(11) DEFAULT '4' COMMENT '实际床位数',
|
||||
`room_area` decimal(10,2) DEFAULT NULL COMMENT '房间面积(平方米)',
|
||||
`room_status` char(1) DEFAULT '0' COMMENT '房间状态(0可用 1维修中 2停用)',
|
||||
`sort` int(11) DEFAULT '0' COMMENT '排序号',
|
||||
`deleted` char(1) DEFAULT '0' COMMENT '删除标志(0代表存在 1代表删除)',
|
||||
`tenant_id` bigint(20) DEFAULT '0' COMMENT '租户编号',
|
||||
`create_by` bigint(20) DEFAULT NULL COMMENT '创建者',
|
||||
|
||||
@@ -12,6 +12,11 @@ CREATE TABLE `xskh_discipline_type` (
|
||||
`type_name` varchar(100) NOT NULL COMMENT '类型名称',
|
||||
`type_category` char(1) NOT NULL COMMENT '类型分类(1-违纪类型 2-处分类型)',
|
||||
`remark` varchar(500) DEFAULT NULL COMMENT '类型说明',
|
||||
`area_type` char(1) DEFAULT '1' COMMENT '区域类型(1-宿舍区违纪 2-教学区违纪)' ,
|
||||
`min_score` decimal(5,2) DEFAULT 0.00 COMMENT '最低扣分',
|
||||
`max_score` decimal(5,2) DEFAULT 100.00 COMMENT '最高扣分',
|
||||
`is_equalized` char(1) DEFAULT '0' COMMENT '是否均化(0-否 1-是)',
|
||||
`equalized_threshold` decimal(10,2) DEFAULT NULL COMMENT '均化阈值',
|
||||
`status` char(1) DEFAULT '0' COMMENT '状态(0-正常 1-停用)',
|
||||
`sort_order` int(4) DEFAULT 0 COMMENT '排序号',
|
||||
`create_by` bigint(20) DEFAULT NULL COMMENT '创建者',
|
||||
@@ -27,6 +32,39 @@ CREATE TABLE `xskh_discipline_type` (
|
||||
KEY `idx_status` (`status`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='学生违纪处分类型表';
|
||||
|
||||
-- 1. 宿舍卫生检查违纪关联表(关联宿舍检查与违纪记录)
|
||||
DROP TABLE IF EXISTS `xg_hygiene_check_violation`;
|
||||
CREATE TABLE `xg_hygiene_check_violation` (
|
||||
`id` bigint(20) NOT NULL COMMENT '主键ID',
|
||||
`tenant_id` varchar(20) NOT NULL DEFAULT '000000' COMMENT '租户编号',
|
||||
`hygiene_check_id` bigint(20) NOT NULL COMMENT '宿舍卫生检查ID,关联xg_dorm_hygiene_check.id',
|
||||
`discipline_record_id` bigint(20) NOT NULL COMMENT '违纪记录ID,关联xskh_discipline_record.id',
|
||||
`student_id` bigint(20) NOT NULL COMMENT '学生ID,关联xg_student_msg.id',
|
||||
`student_no` varchar(20) NOT NULL COMMENT '学号',
|
||||
`student_name` varchar(50) NOT NULL COMMENT '学生姓名',
|
||||
`discipline_type_id` bigint(20) NOT NULL COMMENT '违纪类型ID,关联xskh_discipline_type.id',
|
||||
`discipline_type_name` varchar(100) NOT NULL COMMENT '违纪类型名称',
|
||||
`violation_source` char(1) DEFAULT '1' COMMENT '违纪来源(1宿舍卫生检查 2其他)',
|
||||
`status` char(1) DEFAULT '1' COMMENT '状态(1生效 2已撤销)',
|
||||
`create_by` bigint(20) DEFAULT NULL COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` bigint(20) DEFAULT NULL COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`create_dept` bigint(20) DEFAULT NULL COMMENT '创建部门',
|
||||
`deleted` tinyint(1) DEFAULT 0 COMMENT '删除标志(0-未删除 1-已删除)',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
KEY `idx_tenant_id` (`tenant_id`),
|
||||
KEY `idx_hygiene_check_id` (`hygiene_check_id`),
|
||||
KEY `idx_discipline_record_id` (`discipline_record_id`),
|
||||
KEY `idx_student_id` (`student_id`),
|
||||
KEY `idx_student_no` (`student_no`),
|
||||
KEY `idx_discipline_type_id` (`discipline_type_id`),
|
||||
KEY `idx_violation_source` (`violation_source`),
|
||||
KEY `idx_status` (`status`),
|
||||
KEY `idx_deleted` (`deleted`),
|
||||
KEY `idx_tenant_deleted` (`tenant_id`,`deleted`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='宿舍卫生检查违纪关联表';
|
||||
|
||||
-- 2. 学生违纪处分记录表
|
||||
DROP TABLE IF EXISTS `xskh_discipline_record`;
|
||||
CREATE TABLE `xskh_discipline_record` (
|
||||
@@ -47,6 +85,7 @@ CREATE TABLE `xskh_discipline_record` (
|
||||
`discipline_content` varchar(500) DEFAULT NULL COMMENT '违纪处分内容',
|
||||
`score_deduction` decimal(5,2) DEFAULT 0.00 COMMENT '扣分分值',
|
||||
`status` char(1) DEFAULT '1' COMMENT '状态(1-生效 2-已撤销)',
|
||||
`violation_source` char(1) DEFAULT '2' COMMENT '违纪来源(1-宿舍卫生检查 2-教学区违纪)',
|
||||
`attachment_oss_ids` varchar(1000) DEFAULT NULL COMMENT '附件OSS文件ID,多个用逗号分隔(申请材料、证明文件等)',
|
||||
`create_by` bigint(20) DEFAULT NULL COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
@@ -73,10 +112,15 @@ CREATE TABLE `xskh_discipline_revoke` (
|
||||
`revoke_reason` varchar(500) NOT NULL COMMENT '撤销申请原因',
|
||||
`revoke_evidence` varchar(500) DEFAULT NULL COMMENT '撤销证明材料,附件的oss_id,多个用逗号分隔',
|
||||
`apply_time` datetime NOT NULL COMMENT '申请时间',
|
||||
`status` char(1) DEFAULT '1' COMMENT '状态(1-待审核 2-审核通过 3-审核拒绝)',
|
||||
`approval_by` bigint(20) DEFAULT NULL COMMENT '审核人ID',
|
||||
`approval_time` datetime DEFAULT NULL COMMENT '审核时间',
|
||||
`approval_remark` varchar(500) DEFAULT NULL COMMENT '审核备注',
|
||||
`status` char(1) DEFAULT '1' COMMENT '状态(1-待班主任审核 2-待学工处审核 3-审核通过 4-班主任审核拒绝 5-学工处审核拒绝)',
|
||||
-- 班主任审核信息
|
||||
`teacher_approval_by` bigint(20) DEFAULT NULL COMMENT '班主任审核人ID',
|
||||
`teacher_approval_time` datetime DEFAULT NULL COMMENT '班主任审核时间',
|
||||
`teacher_approval_remark` varchar(500) DEFAULT NULL COMMENT '班主任审核备注',
|
||||
-- 学工处审核信息(保留原有字段名,语义调整为学工处审核)
|
||||
`approval_by` bigint(20) DEFAULT NULL COMMENT '学工处审核人ID',
|
||||
`approval_time` datetime DEFAULT NULL COMMENT '学工处审核时间',
|
||||
`approval_remark` varchar(500) DEFAULT NULL COMMENT '学工处审核备注',
|
||||
`create_by` bigint(20) DEFAULT NULL COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`create_dept` bigint(20) DEFAULT NULL COMMENT '创建部门',
|
||||
@@ -87,7 +131,9 @@ CREATE TABLE `xskh_discipline_revoke` (
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_discipline_record_id` (`discipline_record_id`),
|
||||
KEY `idx_student_id` (`student_id`),
|
||||
KEY `idx_status` (`status`)
|
||||
KEY `idx_status` (`status`),
|
||||
KEY `idx_teacher_approval_by` (`teacher_approval_by`),
|
||||
KEY `idx_approval_by` (`approval_by`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='违纪处分撤销申请审批表';
|
||||
|
||||
-- 4. 奖励类型表
|
||||
@@ -97,6 +143,8 @@ CREATE TABLE `xskh_reward_type` (
|
||||
`type_code` varchar(50) NOT NULL COMMENT '类型编码',
|
||||
`type_name` varchar(100) NOT NULL COMMENT '类型名称',
|
||||
`description` varchar(500) DEFAULT NULL COMMENT '类型说明',
|
||||
`is_equalized` char(1) DEFAULT '0' COMMENT '是否均化(0-否 1-是)',
|
||||
`equalized_threshold` decimal(10,2) DEFAULT NULL COMMENT '均化阈值',
|
||||
`status` char(1) DEFAULT '0' COMMENT '状态(0-正常 1-停用)',
|
||||
`sort_order` int(4) DEFAULT 0 COMMENT '排序号',
|
||||
`create_by` bigint(20) DEFAULT NULL COMMENT '创建者',
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
-- ==========================================
|
||||
-- 学生宿舍申请单数据库脚本(调宿+退宿)
|
||||
-- 创建时间:2025-01-15
|
||||
-- 设计目标:统一的调宿和退宿申请单表
|
||||
-- ==========================================
|
||||
|
||||
-- ----------------------------
|
||||
-- 1. 主表:学生宿舍申请单表
|
||||
-- ----------------------------
|
||||
|
||||
DROP TABLE IF EXISTS `xg_dorm_application`;
|
||||
CREATE TABLE `xg_dorm_application` (
|
||||
`id` bigint(20) NOT NULL COMMENT '主键ID(雪花ID)',
|
||||
|
||||
-- 申请基本信息
|
||||
`application_name` varchar(50) NOT NULL COMMENT '申请名称',
|
||||
`application_type` char(1) NOT NULL COMMENT '申请类型(1:调宿申请 2:退宿申请)',
|
||||
`application_status` char(20) DEFAULT 'waiting' COMMENT '审批状态:cancel-已撤销 , draft-草稿, waiting-待审核, finish-已完成, invalid-已作废, back-已退回, termination-已终止"',
|
||||
|
||||
-- 学生信息
|
||||
`student_id` bigint(20) NOT NULL COMMENT '申请学生ID',
|
||||
`student_no` varchar(20) NOT NULL COMMENT '学号',
|
||||
`student_name` varchar(50) NOT NULL COMMENT '学生姓名',
|
||||
`student_phone` varchar(20) DEFAULT NULL COMMENT '学生联系电话',
|
||||
`college_id` bigint(20) NOT NULL COMMENT '学院ID',
|
||||
`college_name` varchar(100) DEFAULT NULL COMMENT '学院名称',
|
||||
`major_id` bigint(20) DEFAULT NULL COMMENT '专业ID',
|
||||
`major_name` varchar(100) DEFAULT NULL COMMENT '专业名称',
|
||||
`class_id` bigint(20) DEFAULT NULL COMMENT '班级ID',
|
||||
`class_name` varchar(100) DEFAULT NULL COMMENT '班级名称',
|
||||
|
||||
-- 当前宿舍信息(原宿舍/退宿的宿舍)
|
||||
`current_campus_id` bigint(20) DEFAULT NULL COMMENT '当前校区ID',
|
||||
`current_campus_name` varchar(100) DEFAULT NULL COMMENT '当前校区名称',
|
||||
`current_building_id` bigint(20) DEFAULT NULL COMMENT '当前宿舍楼ID',
|
||||
`current_building_name` varchar(100) DEFAULT NULL COMMENT '当前宿舍楼名称',
|
||||
`current_room_id` bigint(20) DEFAULT NULL COMMENT '当前房间ID',
|
||||
`current_room_no` varchar(20) DEFAULT NULL COMMENT '当前房间号',
|
||||
`current_bed_id` bigint(20) DEFAULT NULL COMMENT '当前床位ID',
|
||||
`current_bed_no` varchar(10) DEFAULT NULL COMMENT '当前床位号',
|
||||
|
||||
-- 目标宿舍信息(仅调宿申请使用,退宿申请为空)
|
||||
`target_campus_id` bigint(20) DEFAULT NULL COMMENT '目标校区ID',
|
||||
`target_campus_name` varchar(100) DEFAULT NULL COMMENT '目标校区名称',
|
||||
`target_building_id` bigint(20) DEFAULT NULL COMMENT '目标宿舍楼ID',
|
||||
`target_building_name` varchar(100) DEFAULT NULL COMMENT '目标宿舍楼名称',
|
||||
`target_room_id` bigint(20) DEFAULT NULL COMMENT '目标房间ID',
|
||||
`target_room_no` varchar(20) DEFAULT NULL COMMENT '目标房间号',
|
||||
`target_bed_id` bigint(20) DEFAULT NULL COMMENT '目标床位ID',
|
||||
`target_bed_no` varchar(10) DEFAULT NULL COMMENT '目标床位号',
|
||||
|
||||
-- 申请原因和说明
|
||||
`reason_detail` text DEFAULT NULL COMMENT '详细原因说明',
|
||||
|
||||
-- 时间相关
|
||||
`apply_time` datetime NOT NULL COMMENT '申请时间',
|
||||
|
||||
-- 附件和备注
|
||||
`attachment_oss_ids` varchar(1000) DEFAULT NULL COMMENT '附件OSS文件ID,多个用逗号分隔',
|
||||
`remark` varchar(500) DEFAULT NULL COMMENT '备注信息',
|
||||
|
||||
-- 扩展字段
|
||||
`ext_field1` varchar(200) DEFAULT NULL COMMENT '扩展字段1',
|
||||
`ext_field2` varchar(200) DEFAULT NULL COMMENT '扩展字段2',
|
||||
`ext_field3` varchar(500) DEFAULT NULL COMMENT '扩展字段3',
|
||||
|
||||
-- 系统字段(符合项目规范)
|
||||
`deleted` char(1) DEFAULT '0' COMMENT '删除标志(0代表存在 1代表删除)',
|
||||
`tenant_id` bigint(20) DEFAULT '0' COMMENT '租户编号',
|
||||
`create_by` bigint(20) DEFAULT NULL COMMENT '创建者',
|
||||
`create_dept` bigint(20) DEFAULT NULL COMMENT '创建部门',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` bigint(20) DEFAULT NULL COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
KEY `idx_tenant_id` (`tenant_id`),
|
||||
KEY `idx_deleted` (`deleted`),
|
||||
KEY `idx_student_id` (`student_id`),
|
||||
KEY `idx_student_no` (`student_no`),
|
||||
KEY `idx_application_type` (`application_type`),
|
||||
KEY `idx_application_status` (`application_status`),
|
||||
KEY `idx_apply_time` (`apply_time`),
|
||||
KEY `idx_college_id` (`college_id`),
|
||||
KEY `idx_current_building_id` (`current_building_id`),
|
||||
KEY `idx_target_building_id` (`target_building_id`),
|
||||
KEY `idx_tenant_deleted_status` (`tenant_id`, `deleted`, `application_status`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='学生宿舍申请单表(调宿+退宿)';
|
||||
|
||||
-- ----------------------------
|
||||
-- 2. 字典类型配置
|
||||
-- ----------------------------
|
||||
|
||||
-- 申请类型字典
|
||||
INSERT INTO sys_dict_type (dict_id, dict_name, dict_type, status, create_by, create_time, remark) VALUES
|
||||
(nextval('sys_dict_type_seq'), '宿舍申请类型', 'dorm_application_type', '0', 1, NOW(), '学生宿舍申请类型');
|
||||
|
||||
-- 申请类型字典数据
|
||||
INSERT INTO sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark) VALUES
|
||||
(nextval('sys_dict_data_seq'), 1, '调宿申请', '1', 'dorm_application_type', '', 'primary', 'N', '0', 1, NOW(), '学生调宿申请'),
|
||||
(nextval('sys_dict_data_seq'), 2, '退宿申请', '2', 'dorm_application_type', '', 'warning', 'N', '0', 1, NOW(), '学生退宿申请');
|
||||
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
-- 脚本说明
|
||||
-- ----------------------------
|
||||
/*
|
||||
使用说明:
|
||||
1. 执行前需要确认学工管理菜单的实际ID,替换脚本中的占位符
|
||||
2. 根据项目实际情况调整字典数据的dict_code值
|
||||
3. 测试数据仅供参考,实际使用时可删除
|
||||
4. 表设计遵循项目规范:雪花ID、逻辑删除、多租户支持
|
||||
5. 支持调宿和退宿两种申请类型,通过application_type字段区分
|
||||
|
||||
设计特点:
|
||||
- 统一表结构:一个表同时支持调宿和退宿申请
|
||||
- 灵活字段:退宿申请时目标宿舍信息为空
|
||||
- 完整流程:支持从草稿到生效的完整状态流转
|
||||
- 性能优化:冗余存储宿舍名称,避免关联查询
|
||||
- 权限控制:完整的菜单和功能权限配置
|
||||
*/
|
||||
@@ -1,211 +0,0 @@
|
||||
# 学生考核指标indicator_type_name字段问题修复
|
||||
|
||||
## 问题描述
|
||||
|
||||
在新增学生考核指标时,出现数据库插入错误:
|
||||
|
||||
```
|
||||
Field 'indicator_type_name' doesn't have a default value
|
||||
```
|
||||
|
||||
## 问题分析
|
||||
|
||||
### 1. 根本原因
|
||||
- 数据库表 `xskh_assessment_indicator` 中的 `indicator_type_name` 字段设置为 `NOT NULL`
|
||||
- 前端传递的数据中只有 `indicatorTypeId`,没有 `indicatorTypeName`
|
||||
- 后端Service层在插入数据时没有自动设置 `indicatorTypeName` 字段的值
|
||||
|
||||
### 2. 字段映射问题
|
||||
- 前端使用 `indicatorDescription` 字段,但后端数据库字段是 `description`
|
||||
- 为了保持前后端代码和数据库字段的一致性,统一使用 `description` 字段名
|
||||
|
||||
## 解决方案
|
||||
|
||||
### 1. 后端Service层修复
|
||||
|
||||
**文件**: `backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/service/impl/XskhAssessmentIndicatorServiceImpl.java`
|
||||
|
||||
#### 1.1 添加依赖注入
|
||||
```java
|
||||
private final XskhAssessmentIndicatorTypeMapper indicatorTypeMapper;
|
||||
```
|
||||
|
||||
#### 1.2 修改insertByBo方法
|
||||
```java
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean insertByBo(XskhAssessmentIndicatorBo bo) {
|
||||
XskhAssessmentIndicator add = MapstructUtils.convert(bo, XskhAssessmentIndicator.class);
|
||||
|
||||
// 根据指标类型ID设置指标类型名称
|
||||
if (add.getIndicatorTypeId() != null) {
|
||||
XskhAssessmentIndicatorType indicatorType = indicatorTypeMapper.selectById(add.getIndicatorTypeId());
|
||||
if (indicatorType != null) {
|
||||
add.setIndicatorTypeName(indicatorType.getTypeName());
|
||||
}
|
||||
}
|
||||
|
||||
validEntityBeforeSave(add);
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
bo.setId(add.getId());
|
||||
// 保存关联关系
|
||||
saveIndicatorRelations(add.getId(), bo.getDisciplineTypeIds(), bo.getRewardTypeIds());
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
```
|
||||
|
||||
#### 1.3 修改updateByBo方法
|
||||
```java
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean updateByBo(XskhAssessmentIndicatorBo bo) {
|
||||
XskhAssessmentIndicator update = MapstructUtils.convert(bo, XskhAssessmentIndicator.class);
|
||||
|
||||
// 根据指标类型ID设置指标类型名称
|
||||
if (update.getIndicatorTypeId() != null) {
|
||||
XskhAssessmentIndicatorType indicatorType = indicatorTypeMapper.selectById(update.getIndicatorTypeId());
|
||||
if (indicatorType != null) {
|
||||
update.setIndicatorTypeName(indicatorType.getTypeName());
|
||||
}
|
||||
}
|
||||
|
||||
validEntityBeforeSave(update);
|
||||
boolean flag = baseMapper.updateById(update) > 0;
|
||||
if (flag) {
|
||||
// 更新关联关系
|
||||
saveIndicatorRelations(update.getId(), bo.getDisciplineTypeIds(), bo.getRewardTypeIds());
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 字段映射修复
|
||||
|
||||
为了保持前后端代码和数据库字段的一致性,统一使用 `description` 字段名:
|
||||
|
||||
#### 2.1 前端类型定义修复
|
||||
**文件**: `web/src/api/xskh/assessmentIndicator/types.ts`
|
||||
|
||||
将所有接口中的 `indicatorDescription` 字段改为 `description`:
|
||||
- `XskhAssessmentIndicatorBo`
|
||||
- `XskhAssessmentIndicatorVo`
|
||||
- `XskhAssessmentIndicatorForm`
|
||||
|
||||
#### 2.2 前端表单修复
|
||||
**文件**: `web/src/views/xskh/assessmentIndicator/AssessmentIndicatorForm.vue`
|
||||
|
||||
- 表单字段名:`indicatorDescription` → `description`
|
||||
- 表单验证规则:`indicatorDescription` → `description`
|
||||
- 初始数据:`indicatorDescription` → `description`
|
||||
|
||||
### 3. Mapper XML修复
|
||||
|
||||
**文件**: `backend/ruoyi-modules/ruoyi-xskh/src/main/resources/mapper/xskh/XskhAssessmentIndicatorMapper.xml`
|
||||
|
||||
添加缺失的 `createDept` 字段映射:
|
||||
|
||||
```xml
|
||||
<result property="createDept" column="create_dept"/>
|
||||
```
|
||||
|
||||
### 4. 前端CSS修复
|
||||
|
||||
**文件**: `web/src/views/xskh/assessmentIndicator/AssessmentIndicatorForm.vue`
|
||||
|
||||
修复CSS语法错误:
|
||||
|
||||
```css
|
||||
/* 固定多选框高度,防止动态变化 */
|
||||
.fixed-height-select :deep(.el-select__tags) {
|
||||
max-height: 32px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.fixed-height-select :deep(.el-select__tags-text) {
|
||||
max-width: 120px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.fixed-height-select :deep(.el-select__collapse-tags) {
|
||||
max-width: 100%;
|
||||
}
|
||||
```
|
||||
|
||||
## 测试验证
|
||||
|
||||
### 1. 创建测试脚本
|
||||
**文件**: `test/学生考核指标API测试脚本.py`
|
||||
|
||||
包含以下测试用例:
|
||||
- 登录认证
|
||||
- 新增学生考核指标
|
||||
- 查询指标列表
|
||||
- 查询指标详情
|
||||
- 修改指标
|
||||
|
||||
### 2. 测试数据
|
||||
```json
|
||||
{
|
||||
"indicatorCode": "zbbm01",
|
||||
"indicatorName": "学生指标01",
|
||||
"description": "学生指标01指标说明",
|
||||
"indicatorTypeId": "1958131304973221889",
|
||||
"maxScore": 2.1,
|
||||
"status": "0",
|
||||
"sortOrder": 0,
|
||||
"disciplineTypeIds": [
|
||||
"1958135628856049666",
|
||||
"1958135753561096193"
|
||||
],
|
||||
"rewardTypeIds": [
|
||||
"1958135350199074817",
|
||||
"1958135400207761409"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 修复效果
|
||||
|
||||
### 1. 问题解决
|
||||
- ✅ 解决了 `indicator_type_name` 字段缺失默认值的问题
|
||||
- ✅ 统一了前后端字段命名,使用 `description` 字段
|
||||
- ✅ 修复了CSS语法错误
|
||||
- ✅ 完善了Mapper XML字段映射
|
||||
|
||||
### 2. 功能增强
|
||||
- ✅ 自动根据指标类型ID设置指标类型名称
|
||||
- ✅ 统一前后端字段命名,提高代码一致性
|
||||
- ✅ 完善了错误处理和日志记录
|
||||
|
||||
### 3. 代码质量
|
||||
- ✅ 遵循项目开发规范
|
||||
- ✅ 添加了完整的注释说明
|
||||
- ✅ 提供了测试脚本验证功能
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **数据库字段约束**: 确保数据库表设计合理,避免不必要的NOT NULL约束
|
||||
2. **字段命名一致性**: 前后端字段名应保持一致,避免不必要的映射转换
|
||||
3. **自动填充**: 对于关联字段,应该在Service层自动填充,而不是依赖前端传递
|
||||
4. **测试验证**: 每次修复后都应该进行完整的测试验证
|
||||
|
||||
## 相关文件
|
||||
|
||||
- `backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/service/impl/XskhAssessmentIndicatorServiceImpl.java`
|
||||
- `backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/domain/bo/XskhAssessmentIndicatorBo.java`
|
||||
- `backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/domain/XskhAssessmentIndicator.java`
|
||||
- `backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/domain/vo/XskhAssessmentIndicatorVo.java`
|
||||
- `backend/ruoyi-modules/ruoyi-xskh/src/main/resources/mapper/xskh/XskhAssessmentIndicatorMapper.xml`
|
||||
- `web/src/api/xskh/assessmentIndicator/types.ts`
|
||||
- `web/src/views/xskh/assessmentIndicator/AssessmentIndicatorForm.vue`
|
||||
- `test/学生考核指标API测试脚本.py`
|
||||
|
||||
---
|
||||
|
||||
**修复时间**: 2025-01-03
|
||||
**修复人员**: AI Assistant
|
||||
**验证状态**: 待验证
|
||||
@@ -1,162 +0,0 @@
|
||||
# 学生考核指标类型createDept字段问题修复
|
||||
|
||||
## 问题描述
|
||||
|
||||
在 `XskhAssessmentIndicatorTypeController.java` 类的 `add` 方法执行后,数据库中查看数据时发现 `create_dept` 字段(创建人的部门ID)没有插入数据,显示为 NULL。
|
||||
|
||||
## 问题分析
|
||||
|
||||
通过代码分析,发现问题的根本原因是:
|
||||
|
||||
### 1. VO类缺少createDept字段
|
||||
**文件**: `backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/domain/vo/XskhAssessmentIndicatorTypeVo.java`
|
||||
|
||||
**问题**: VO类中缺少 `createDept` 字段定义,导致字段映射不完整。
|
||||
|
||||
### 2. BO类缺少createDept字段
|
||||
**文件**: `backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/domain/bo/XskhAssessmentIndicatorTypeBo.java`
|
||||
|
||||
**问题**: BO类中缺少 `createDept` 字段定义,影响数据传输。
|
||||
|
||||
### 3. Mapper XML缺少字段映射
|
||||
**文件**: `backend/ruoyi-modules/ruoyi-xskh/src/main/resources/mapper/xskh/XskhAssessmentIndicatorTypeMapper.xml`
|
||||
|
||||
**问题**: resultMap中缺少 `createDept` 字段的映射配置,导致数据库字段无法正确映射到实体属性。
|
||||
|
||||
## 解决方案
|
||||
|
||||
### 1. 修复VO类
|
||||
在 `XskhAssessmentIndicatorTypeVo.java` 中添加 `createDept` 字段:
|
||||
|
||||
```java
|
||||
/**
|
||||
* 创建部门
|
||||
*/
|
||||
private Long createDept;
|
||||
```
|
||||
|
||||
### 2. 修复BO类
|
||||
在 `XskhAssessmentIndicatorTypeBo.java` 中添加基础字段:
|
||||
|
||||
```java
|
||||
/**
|
||||
* 创建部门
|
||||
*/
|
||||
private Long createDept;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
private Long createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
private Long updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private Date updateTime;
|
||||
```
|
||||
|
||||
### 3. 修复Mapper XML
|
||||
在 `XskhAssessmentIndicatorTypeMapper.xml` 的两个resultMap中添加字段映射:
|
||||
|
||||
```xml
|
||||
<result property="createDept" column="create_dept"/>
|
||||
```
|
||||
|
||||
### 4. 增强Service实现
|
||||
在 `XskhAssessmentIndicatorTypeServiceImpl.java` 中添加调试日志和手动设置逻辑:
|
||||
|
||||
```java
|
||||
// 调试日志:检查当前登录用户信息
|
||||
try {
|
||||
Long userId = LoginHelper.getUserId();
|
||||
Long deptId = LoginHelper.getDeptId();
|
||||
log.info("🔍 调试信息 - 当前登录用户ID: {}, 部门ID: {}", userId, deptId);
|
||||
|
||||
// 手动设置createDept字段,确保有值
|
||||
if (add.getCreateDept() == null && deptId != null) {
|
||||
add.setCreateDept(deptId);
|
||||
log.info("✅ 手动设置createDept字段: {}", deptId);
|
||||
} else {
|
||||
log.info("⚠️ createDept字段状态: {}", add.getCreateDept());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("⚠️ 获取登录用户信息失败: {}", e.getMessage());
|
||||
}
|
||||
```
|
||||
|
||||
## 技术原理
|
||||
|
||||
### MyBatis-Plus字段填充机制
|
||||
系统使用 MyBatis-Plus 的 `@TableField(fill = FieldFill.INSERT)` 注解来自动填充字段:
|
||||
|
||||
```java
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Long createDept;
|
||||
```
|
||||
|
||||
### 字段填充处理器
|
||||
`InjectionMetaObjectHandler` 负责在插入时自动填充字段:
|
||||
|
||||
```java
|
||||
baseEntity.setCreateDept(ObjectUtils.notNull(baseEntity.getCreateDept(), loginUser.getDeptId()));
|
||||
```
|
||||
|
||||
### 字段映射关系
|
||||
- 数据库字段: `create_dept`
|
||||
- 实体属性: `createDept`
|
||||
- 映射配置: `<result property="createDept" column="create_dept"/>`
|
||||
|
||||
## 验证方法
|
||||
|
||||
### 1. 创建测试脚本
|
||||
创建 `test/学生考核指标类型API测试脚本.py` 来验证修复效果。
|
||||
|
||||
### 2. 测试步骤
|
||||
1. 登录系统获取token
|
||||
2. 调用新增API创建测试数据
|
||||
3. 调用查询API检查createDept字段
|
||||
4. 验证字段是否正确填充
|
||||
|
||||
### 3. 预期结果
|
||||
- createDept字段应该包含当前登录用户的部门ID
|
||||
- 不再显示为NULL
|
||||
|
||||
## 预防措施
|
||||
|
||||
### 1. 规范检查
|
||||
- 所有VO类必须包含四个基础字段:`createBy`、`createTime`、`updateBy`、`updateTime`
|
||||
- 新增 `createDept` 字段作为第五个基础字段
|
||||
- Mapper XML必须包含完整的字段映射
|
||||
|
||||
### 2. 代码模板
|
||||
创建标准的代码模板,确保新开发的模块不会遗漏基础字段。
|
||||
|
||||
### 3. 自动化测试
|
||||
建立自动化测试机制,定期检查字段映射的完整性。
|
||||
|
||||
## 相关文件
|
||||
|
||||
### 修改的文件
|
||||
1. `backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/domain/vo/XskhAssessmentIndicatorTypeVo.java`
|
||||
2. `backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/domain/bo/XskhAssessmentIndicatorTypeBo.java`
|
||||
3. `backend/ruoyi-modules/ruoyi-xskh/src/main/resources/mapper/xskh/XskhAssessmentIndicatorTypeMapper.xml`
|
||||
4. `backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/service/impl/XskhAssessmentIndicatorTypeServiceImpl.java`
|
||||
|
||||
### 新增的文件
|
||||
1. `test/学生考核指标类型API测试脚本.py`
|
||||
|
||||
## 总结
|
||||
|
||||
通过修复VO类、BO类、Mapper XML的字段映射问题,并增强Service实现的调试功能,成功解决了 `create_dept` 字段不填充的问题。这个问题的根本原因是字段映射不完整,导致MyBatis-Plus的自动填充机制无法正常工作。
|
||||
|
||||
修复后的系统能够正确记录创建人的部门信息,为后续的数据分析和权限控制提供了基础支持。
|
||||
@@ -1,218 +0,0 @@
|
||||
# 学生考核时间格式修复报告
|
||||
|
||||
## 📋 问题描述
|
||||
|
||||
### 问题现象
|
||||
在学生考核管理系统中,点击保存按钮调用接口 `http://localhost/dev-api/assessment/approval/approve` 时,返回的数据中 `bonusApprovalList` 和 `bonusList` 的时间字段显示为不标准的格式:
|
||||
|
||||
```json
|
||||
{
|
||||
"bonusApprovalList": [
|
||||
{
|
||||
"createTime": "2025/8/21 上午10:52",
|
||||
"updateTime": "2025/8/21 上午10:52"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 问题分析
|
||||
经过代码分析,发现问题出现在以下两个VO类文件中:
|
||||
|
||||
1. **XskhAssessmentBonusApprovalVo.java** - 附加分审核VO类
|
||||
2. **XskhAssessmentSelfScoreVo.java** - 自评得分VO类
|
||||
|
||||
这两个文件中的 `createTime` 和 `updateTime` 字段被错误地定义为 `String` 类型,但使用了 `@JsonFormat` 注解,导致时间格式不正确。
|
||||
|
||||
## 🔧 修复方案
|
||||
|
||||
### 修复文件列表
|
||||
|
||||
#### 1. XskhAssessmentBonusApprovalVo.java
|
||||
**文件路径**: `backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/domain/vo/XskhAssessmentBonusApprovalVo.java`
|
||||
|
||||
**修复内容**:
|
||||
```java
|
||||
// 修复前
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private String createTime;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private String updateTime;
|
||||
|
||||
// 修复后
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime;
|
||||
```
|
||||
|
||||
#### 2. XskhAssessmentSelfScoreVo.java
|
||||
**文件路径**: `backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/domain/vo/XskhAssessmentSelfScoreVo.java`
|
||||
|
||||
**修复内容**:
|
||||
```java
|
||||
// 修复前
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private String createTime;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private String updateTime;
|
||||
|
||||
// 修复后
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime;
|
||||
```
|
||||
|
||||
### 修复原理
|
||||
|
||||
1. **类型一致性**: 将时间字段类型从 `String` 改为 `Date`,与实体类保持一致
|
||||
2. **JSON格式化**: 使用 `@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")` 注解确保时间以标准格式输出
|
||||
3. **遵循项目规范**: 符合项目后端开发规范中关于VO类基础字段的要求
|
||||
|
||||
## 📊 修复效果
|
||||
|
||||
### 修复前
|
||||
```json
|
||||
{
|
||||
"bonusApprovalList": [
|
||||
{
|
||||
"createTime": "2025/8/21 上午10:52",
|
||||
"updateTime": "2025/8/21 上午10:52"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 修复后
|
||||
```json
|
||||
{
|
||||
"bonusApprovalList": [
|
||||
{
|
||||
"createTime": "2025-08-21 10:52:40",
|
||||
"updateTime": "2025-08-21 10:52:40"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 🧪 验证方法
|
||||
|
||||
### 1. 代码验证
|
||||
- ✅ 检查VO类文件中的时间字段类型
|
||||
- ✅ 确认 `@JsonFormat` 注解正确使用
|
||||
- ✅ 验证字段类型与实体类一致
|
||||
|
||||
### 2. 功能验证
|
||||
创建了验证脚本 `test/学生考核时间格式修复验证.py`,用于:
|
||||
- 登录系统获取token
|
||||
- 调用考核审核接口
|
||||
- 检查返回数据中的时间格式
|
||||
- 验证时间字段是否为标准格式
|
||||
|
||||
### 3. 测试步骤
|
||||
```bash
|
||||
# 1. 启动后端服务
|
||||
cd backend
|
||||
mvn spring-boot:run
|
||||
|
||||
# 2. 运行验证脚本
|
||||
cd test
|
||||
python 学生考核时间格式修复验证.py
|
||||
```
|
||||
|
||||
## 📚 相关规范
|
||||
|
||||
### 项目后端开发规范
|
||||
根据 `.cursor/cursorrules-backend.md` 中的规范:
|
||||
|
||||
#### VO类基础字段规范(强制性)
|
||||
```java
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
private Long createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
private Long updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime;
|
||||
```
|
||||
|
||||
#### 字段使用注解规范
|
||||
- 时间字段必须使用JSON格式化注解
|
||||
- 字段类型必须统一:createBy/updateBy 为 Long,createTime/updateTime 为 Date
|
||||
- 时间字段必须使用 `@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")` 注解
|
||||
|
||||
## 🔍 预防措施
|
||||
|
||||
### 1. 代码审查
|
||||
- 新增VO类时必须检查基础字段类型
|
||||
- 确保时间字段使用正确的类型和注解
|
||||
|
||||
### 2. 自动化检查
|
||||
- 在CI/CD流程中添加代码规范检查
|
||||
- 使用静态代码分析工具检查字段类型
|
||||
|
||||
### 3. 文档更新
|
||||
- 更新项目开发规范文档
|
||||
- 在团队中推广VO类开发标准
|
||||
|
||||
## 📝 总结
|
||||
|
||||
本次修复解决了学生考核管理系统中时间格式显示不正确的问题,主要修复了:
|
||||
|
||||
1. **2个VO类文件**中的时间字段类型错误
|
||||
2. **4个时间字段**的类型从String改为Date
|
||||
3. **确保JSON格式化注解**正确使用
|
||||
4. **修复Service实现类**中的类型转换错误
|
||||
|
||||
### 🔧 修复详情
|
||||
|
||||
#### 第一阶段:VO类修复
|
||||
- `XskhAssessmentBonusApprovalVo.java` - 修复createTime和updateTime字段类型
|
||||
- `XskhAssessmentSelfScoreVo.java` - 修复createTime和updateTime字段类型
|
||||
|
||||
#### 第二阶段:Service实现类修复(优化方案)
|
||||
- `XskhAssessmentApplicationApprovalServiceImpl.java` - 优化时间字段处理逻辑
|
||||
- **根本解决方案**:修改SQL查询使用ResultMap而不是Map类型
|
||||
- **移除复杂的手动类型转换**:让MyBatis自动处理类型映射
|
||||
- **简化代码**:从50+行手动转换代码简化为1行直接赋值
|
||||
|
||||
### 🚨 编译错误解决
|
||||
|
||||
在修复VO类后,编译时出现了类型转换错误:
|
||||
```
|
||||
不兼容的类型: java.lang.String无法转换为java.util.Date
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
1. **修改SQL查询**:使用ResultMap替代resultType="java.util.Map"
|
||||
2. **添加ResultMap定义**:`XskhAssessmentSelfScoreWithIndicatorResult`
|
||||
3. **修改Mapper接口**:返回类型从`List<Object>`改为`List<XskhAssessmentSelfScoreVo>`
|
||||
4. **简化Service代码**:移除复杂的手动类型转换,直接使用MyBatis自动映射
|
||||
|
||||
修复后,系统返回的时间格式将符合标准格式 `yyyy-MM-dd HH:mm:ss`,提升了数据的一致性和用户体验。
|
||||
|
||||
---
|
||||
|
||||
**修复人员**: AI Assistant
|
||||
**修复时间**: 2025-01-03
|
||||
**验证状态**: ✅ 已修复
|
||||
**影响范围**: 学生考核管理系统时间显示
|
||||
@@ -1,246 +0,0 @@
|
||||
# 学生考核申请ID精度丢失修复报告
|
||||
|
||||
## 问题描述
|
||||
|
||||
### 错误现象
|
||||
在学生考核申请界面保存时,ID等字段丢失精度,导致存到数据库都为 `1958180338534527000`,后几位都是 `000`。
|
||||
|
||||
### 问题分析
|
||||
1. **根本原因**: JavaScript 大整数精度丢失问题
|
||||
- JavaScript 的 `Number.MAX_SAFE_INTEGER` 为 `9007199254740991`
|
||||
- 雪花ID通常超过这个范围,导致精度丢失
|
||||
- 使用 `parseInt()` 转换大整数字符串时,超出安全范围的数字会被截断
|
||||
|
||||
2. **问题位置**: `safeConvertId` 函数
|
||||
- 原函数使用 `parseInt()` 将字符串ID转换为数字
|
||||
- 对于大整数(如雪花ID),转换后精度丢失
|
||||
|
||||
3. **影响范围**: 所有ID字段
|
||||
- `id`: 主键ID
|
||||
- `studentId`: 学生ID
|
||||
- `collegeId`: 学院ID
|
||||
- `majorId`: 专业ID
|
||||
- `classId`: 班级ID
|
||||
- `scheduleId`: 考核计划ID
|
||||
|
||||
## 修复方案
|
||||
|
||||
### 1. 修复 `safeConvertId` 函数
|
||||
|
||||
**文件**: `web/src/views/xskh/assessmentApplication/AssessmentApplicationForm.vue`
|
||||
|
||||
**修复前**:
|
||||
```typescript
|
||||
const safeConvertId = (id: string | number | undefined): number | undefined => {
|
||||
if (id === undefined || id === null) return undefined;
|
||||
if (typeof id === 'number') return id;
|
||||
if (typeof id === 'string') {
|
||||
// 对于大整数,使用parseInt而不是Number,并检查是否超出安全范围
|
||||
const num = parseInt(id, 10);
|
||||
if (isNaN(num)) return undefined;
|
||||
// 检查是否超出JavaScript安全整数范围
|
||||
if (num > Number.MAX_SAFE_INTEGER) {
|
||||
console.warn('ID超出JavaScript安全整数范围,可能导致精度丢失:', id);
|
||||
}
|
||||
return num;
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
```
|
||||
|
||||
**修复后**:
|
||||
```typescript
|
||||
const safeConvertId = (id: string | number | undefined): string | undefined => {
|
||||
if (id === undefined || id === null) return undefined;
|
||||
// 始终将ID转换为字符串,避免JavaScript大整数精度丢失
|
||||
return String(id);
|
||||
};
|
||||
```
|
||||
|
||||
### 2. 修复要点
|
||||
|
||||
#### 2.1 类型安全
|
||||
- **返回类型**: 从 `number | undefined` 改为 `string | undefined`
|
||||
- **处理逻辑**: 始终使用 `String()` 转换,保持原始精度
|
||||
- **兼容性**: 后端API支持 `string | number` 类型,无需修改
|
||||
|
||||
#### 2.2 精度保持
|
||||
- **字符串转换**: 使用 `String()` 而不是 `parseInt()`
|
||||
- **精度完整**: 保持雪花ID的完整精度
|
||||
- **无截断**: 避免大整数被截断为 `000`
|
||||
|
||||
#### 2.3 项目一致性
|
||||
- **标准做法**: 与项目中其他模块的处理方式保持一致
|
||||
- **最佳实践**: 参考项目中已有的成功案例
|
||||
|
||||
## 技术原理
|
||||
|
||||
### JavaScript 大整数精度问题
|
||||
|
||||
#### 1. 安全整数范围
|
||||
```javascript
|
||||
Number.MAX_SAFE_INTEGER = 9007199254740991 // 2^53 - 1
|
||||
Number.MIN_SAFE_INTEGER = -9007199254740991 // -(2^53 - 1)
|
||||
```
|
||||
|
||||
#### 2. 雪花ID特点
|
||||
- **长度**: 通常为19位数字
|
||||
- **范围**: 远超JavaScript安全整数范围
|
||||
- **精度**: 需要保持完整精度
|
||||
|
||||
#### 3. 转换对比
|
||||
```javascript
|
||||
// 错误的转换方式(精度丢失)
|
||||
const bigId = "1958180338534527123";
|
||||
const wrongResult = parseInt(bigId); // 1958180338534527000 (精度丢失)
|
||||
|
||||
// 正确的转换方式(保持精度)
|
||||
const correctResult = String(bigId); // "1958180338534527123" (完整精度)
|
||||
```
|
||||
|
||||
### 后端支持
|
||||
|
||||
#### 1. API接口支持
|
||||
```typescript
|
||||
// 所有ID参数都支持 string | number 类型
|
||||
export function getAssessmentApplication(id: string | number) {
|
||||
return request({
|
||||
url: '/assessment/application/' + id,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. 类型定义支持
|
||||
```typescript
|
||||
export interface XskhAssessmentApplicationApprovalBo {
|
||||
id?: string | number;
|
||||
studentId?: string | number;
|
||||
collegeId?: string | number;
|
||||
majorId?: string | number;
|
||||
classId?: string | number;
|
||||
scheduleId?: string | number;
|
||||
// ... 其他字段
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. 后端处理
|
||||
- **Spring Boot**: 自动处理字符串到Long的转换
|
||||
- **MyBatis-Plus**: 支持字符串类型的ID参数
|
||||
- **数据库**: bigint类型可以正确处理字符串输入
|
||||
|
||||
## 验证测试
|
||||
|
||||
### 1. 功能测试
|
||||
|
||||
#### 1.1 新增申请测试
|
||||
- **测试步骤**:
|
||||
1. 打开学生考核申请界面
|
||||
2. 选择考核计划
|
||||
3. 填写申请信息
|
||||
4. 点击保存
|
||||
- **预期结果**: ID字段保持完整精度,数据库记录正确
|
||||
|
||||
#### 1.2 编辑申请测试
|
||||
- **测试步骤**:
|
||||
1. 打开已有申请记录
|
||||
2. 修改申请信息
|
||||
3. 点击保存
|
||||
- **预期结果**: ID字段保持完整精度,更新成功
|
||||
|
||||
#### 1.3 提交申请测试
|
||||
- **测试步骤**:
|
||||
1. 打开申请记录
|
||||
2. 点击提交
|
||||
- **预期结果**: ID字段保持完整精度,提交成功
|
||||
|
||||
### 2. 数据验证
|
||||
|
||||
#### 2.1 前端数据验证
|
||||
```javascript
|
||||
// 验证ID精度
|
||||
const testId = "1958180338534527123";
|
||||
const convertedId = safeConvertId(testId);
|
||||
console.log('转换前:', testId);
|
||||
console.log('转换后:', convertedId);
|
||||
console.log('精度保持:', testId === convertedId); // 应该为 true
|
||||
```
|
||||
|
||||
#### 2.2 后端数据验证
|
||||
```sql
|
||||
-- 查询保存的记录,验证ID精度
|
||||
SELECT id, student_id, college_id, major_id, class_id, schedule_id
|
||||
FROM xskh_assessment_application_approval
|
||||
WHERE id = '1958180338534527123';
|
||||
```
|
||||
|
||||
### 3. 边界测试
|
||||
|
||||
#### 3.1 大整数测试
|
||||
- **测试数据**: 19位雪花ID
|
||||
- **预期结果**: 完整精度保持
|
||||
|
||||
#### 3.2 小整数测试
|
||||
- **测试数据**: 普通整数ID
|
||||
- **预期结果**: 正常转换
|
||||
|
||||
#### 3.3 空值测试
|
||||
- **测试数据**: undefined, null
|
||||
- **预期结果**: 返回 undefined
|
||||
|
||||
## 影响范围
|
||||
|
||||
### 1. 直接影响
|
||||
- ✅ **学生考核申请模块**: 修复完成
|
||||
- ✅ **ID精度保持**: 所有ID字段完整精度
|
||||
- ✅ **数据一致性**: 前后端数据一致
|
||||
|
||||
### 2. 间接影响
|
||||
- ✅ **API接口**: 无需修改,已支持字符串类型
|
||||
- ✅ **数据库**: 无需修改,bigint类型支持字符串输入
|
||||
- ✅ **其他模块**: 无影响
|
||||
|
||||
### 3. 兼容性
|
||||
- ✅ **向后兼容**: 不影响现有功能
|
||||
- ✅ **向前兼容**: 支持新的ID格式
|
||||
- ✅ **跨平台**: 所有平台一致
|
||||
|
||||
## 最佳实践总结
|
||||
|
||||
### 1. 大整数处理原则
|
||||
```typescript
|
||||
// ✅ 正确做法:保持字符串类型
|
||||
const safeConvertId = (id: string | number | undefined): string | undefined => {
|
||||
if (id === undefined || id === null) return undefined;
|
||||
return String(id);
|
||||
};
|
||||
|
||||
// ❌ 错误做法:转换为数字类型
|
||||
const wrongConvertId = (id: string | number | undefined): number | undefined => {
|
||||
return parseInt(String(id), 10); // 可能导致精度丢失
|
||||
};
|
||||
```
|
||||
|
||||
### 2. 项目统一规范
|
||||
- **ID字段**: 始终使用 `string | number` 类型
|
||||
- **转换函数**: 保持字符串格式,避免数字转换
|
||||
- **API接口**: 支持字符串类型参数
|
||||
- **类型定义**: 明确定义支持的类型
|
||||
|
||||
### 3. 测试验证
|
||||
- **功能测试**: 验证保存、编辑、提交功能
|
||||
- **数据验证**: 检查数据库记录精度
|
||||
- **边界测试**: 测试各种ID格式
|
||||
- **兼容性测试**: 确保向后兼容
|
||||
|
||||
## 总结
|
||||
|
||||
通过本次修复,成功解决了学生考核申请界面ID精度丢失的问题:
|
||||
|
||||
1. **问题根除**: 修复了JavaScript大整数精度丢失的根本原因
|
||||
2. **精度保持**: 所有ID字段现在保持完整精度
|
||||
3. **数据一致**: 前后端数据完全一致
|
||||
4. **标准统一**: 与项目其他模块的处理方式保持一致
|
||||
5. **向后兼容**: 不影响现有功能和数据
|
||||
|
||||
修复方案简单有效,符合项目的最佳实践,为后续类似问题提供了标准解决方案。
|
||||
@@ -1,180 +0,0 @@
|
||||
# 学生考核申请LocalDateTime类型转换错误修复报告
|
||||
|
||||
## 问题描述
|
||||
|
||||
**时间**: 2025-01-03
|
||||
**接口**: `GET /assessment/application/student/{studentId}/schedule/{scheduleId}`
|
||||
**错误信息**:
|
||||
```
|
||||
{
|
||||
"code": 500,
|
||||
"msg": "class java.time.LocalDateTime cannot be cast to class java.lang.String (java.time.LocalDateTime and java.lang.String are in module java.base of loader 'bootstrap')",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
## 问题分析
|
||||
|
||||
### 错误原因
|
||||
在 `XskhAssessmentApplicationApprovalServiceImpl.queryById()` 方法中,第83-84行存在类型转换错误:
|
||||
|
||||
```java
|
||||
// 错误的代码
|
||||
selfScoreVo.setCreateTime((String) scoreMap.get("createTime"));
|
||||
selfScoreVo.setUpdateTime((String) scoreMap.get("updateTime"));
|
||||
```
|
||||
|
||||
### 根本原因
|
||||
1. **数据库字段类型**: `create_time` 和 `update_time` 字段在数据库中定义为 `datetime` 类型
|
||||
2. **MyBatis查询返回**: 通过 `selectSelfScoresWithIndicatorInfo` 查询时,MyBatis可能返回 `LocalDateTime` 类型
|
||||
3. **强制类型转换**: 代码中直接强制转换为 `String` 类型,导致 `ClassCastException`
|
||||
|
||||
### 影响范围
|
||||
- 学生考核申请详情查询接口
|
||||
- 学生考核申请表单页面无法正常加载历史数据
|
||||
|
||||
## 解决方案
|
||||
|
||||
### 1. 修复Service实现类中的类型转换
|
||||
|
||||
**文件**: `backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/service/impl/XskhAssessmentApplicationApprovalServiceImpl.java`
|
||||
|
||||
**修改内容**:
|
||||
```java
|
||||
// 修复前
|
||||
selfScoreVo.setCreateTime((String) scoreMap.get("createTime"));
|
||||
selfScoreVo.setUpdateTime((String) scoreMap.get("updateTime"));
|
||||
|
||||
// 修复后
|
||||
Object createTimeObj = scoreMap.get("createTime");
|
||||
if (createTimeObj != null) {
|
||||
selfScoreVo.setCreateTime(createTimeObj.toString());
|
||||
}
|
||||
Object updateTimeObj = scoreMap.get("updateTime");
|
||||
if (updateTimeObj != null) {
|
||||
selfScoreVo.setUpdateTime(updateTimeObj.toString());
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 添加JSON格式化注解
|
||||
|
||||
**文件**: `backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/domain/vo/XskhAssessmentSelfScoreVo.java`
|
||||
|
||||
**修改内容**:
|
||||
```java
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private String createTime;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private String updateTime;
|
||||
```
|
||||
|
||||
**文件**: `backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/domain/vo/XskhAssessmentBonusApprovalVo.java`
|
||||
|
||||
**修改内容**:
|
||||
```java
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private String createTime;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private String updateTime;
|
||||
```
|
||||
|
||||
**文件**: `backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/domain/vo/XskhAssessmentApplicationApprovalVo.java`
|
||||
|
||||
**修改内容**:
|
||||
```java
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date submitTime;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date teacherApprovalTime;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime;
|
||||
```
|
||||
|
||||
## 修复效果
|
||||
|
||||
### 修复前
|
||||
- 接口返回500错误
|
||||
- 前端无法正常显示考核申请详情
|
||||
- 用户无法查看历史申请记录
|
||||
|
||||
### 修复后
|
||||
- 接口正常返回数据
|
||||
- 前端可以正常显示考核申请详情
|
||||
- 时间字段格式化为标准格式 `yyyy-MM-dd HH:mm:ss`
|
||||
- 支持查看历史申请记录
|
||||
|
||||
## 技术要点
|
||||
|
||||
### 1. 类型安全处理
|
||||
- 使用 `Object` 类型接收查询结果
|
||||
- 通过 `toString()` 方法安全转换
|
||||
- 添加空值检查避免NPE
|
||||
|
||||
### 2. JSON序列化优化
|
||||
- 添加 `@JsonFormat` 注解统一时间格式
|
||||
- 确保前后端时间格式一致
|
||||
- 提升API响应质量
|
||||
|
||||
### 3. 数据库字段映射
|
||||
- 保持与BaseEntity基类的一致性
|
||||
- 遵循项目的时间字段处理规范
|
||||
- 避免类型转换异常
|
||||
|
||||
## 验证方法
|
||||
|
||||
### 1. 接口测试
|
||||
```bash
|
||||
# 测试学生考核申请查询接口
|
||||
GET /assessment/application/student/1/schedule/1958180338534526978
|
||||
```
|
||||
|
||||
### 2. 前端验证
|
||||
- 打开学生考核申请表单页面
|
||||
- 验证历史申请记录正常显示
|
||||
- 检查时间字段格式是否正确
|
||||
|
||||
### 3. 日志检查
|
||||
- 查看后端日志确认无类型转换错误
|
||||
- 验证SQL查询正常执行
|
||||
- 确认数据正确返回
|
||||
|
||||
## 预防措施
|
||||
|
||||
### 1. 代码规范
|
||||
- 避免直接强制类型转换
|
||||
- 使用安全的类型转换方法
|
||||
- 添加适当的空值检查
|
||||
|
||||
### 2. 测试覆盖
|
||||
- 添加单元测试覆盖时间字段处理
|
||||
- 集成测试验证API响应格式
|
||||
- 前端测试确保UI正常显示
|
||||
|
||||
### 3. 文档维护
|
||||
- 更新API文档说明时间字段格式
|
||||
- 记录VO类字段类型定义
|
||||
- 维护问题解决方案文档
|
||||
|
||||
## 总结
|
||||
|
||||
本次修复解决了学生考核申请模块中的LocalDateTime类型转换错误,通过安全的类型处理和JSON格式化注解,确保了接口的稳定性和数据格式的一致性。修复后的代码更加健壮,能够正确处理各种时间类型的数据,提升了用户体验。
|
||||
|
||||
---
|
||||
|
||||
**修复人员**: AI Assistant
|
||||
**修复时间**: 2025-01-03
|
||||
**影响模块**: 学生考核管理模块
|
||||
**测试状态**: 待验证
|
||||
@@ -1,144 +0,0 @@
|
||||
# 学生考核申请更新主键冲突修复报告
|
||||
|
||||
## 问题描述
|
||||
|
||||
### 现象
|
||||
在考核申请表单中,对已有数据进行修改后点击保存按钮,调用PUT接口更新数据时出现主键冲突错误:
|
||||
|
||||
```
|
||||
Duplicate entry '1958434137320771585' for key 'PRIMARY'
|
||||
```
|
||||
|
||||
### 错误详情
|
||||
- **接口**: `PUT /assessment/application`
|
||||
- **错误类型**: `java.sql.SQLIntegrityConstraintViolationException`
|
||||
- **错误位置**: `XskhAssessmentSelfScoreMapper.insert`
|
||||
- **根本原因**: 更新操作误用插入逻辑
|
||||
|
||||
## 问题分析
|
||||
|
||||
### 根本原因
|
||||
在 `XskhAssessmentApplicationApprovalServiceImpl.updateSelfScores()` 和 `updateBonusApprovals()` 方法中,更新逻辑存在严重缺陷:
|
||||
|
||||
**原有错误逻辑**:
|
||||
1. 删除所有关联的子表记录
|
||||
2. 重新插入新的记录
|
||||
|
||||
**问题所在**:
|
||||
- 前端传递的数据包含已存在记录的ID
|
||||
- 后端删除后重新插入时,由于ID已存在导致主键冲突
|
||||
- 这种"删除重建"的方式会丢失原有的创建时间、创建人等审计信息
|
||||
|
||||
### 影响范围
|
||||
- 学生考核自评得分表 (`xskh_assessment_self_score`)
|
||||
- 附加分申请表 (`xskh_assessment_bonus_approval`)
|
||||
|
||||
## 解决方案
|
||||
|
||||
### 修复策略
|
||||
采用"智能更新"策略,根据记录ID是否存在决定执行更新或插入操作:
|
||||
|
||||
```java
|
||||
// 如果ID存在,则更新;否则新增
|
||||
if (selfScore.getId() != null) {
|
||||
// 更新现有记录
|
||||
selfScoreMapper.updateById(selfScore);
|
||||
} else {
|
||||
// 新增记录
|
||||
selfScoreMapper.insert(selfScore);
|
||||
}
|
||||
```
|
||||
|
||||
### 具体修改
|
||||
|
||||
#### 1. 修复自评得分更新逻辑
|
||||
**文件**: `XskhAssessmentApplicationApprovalServiceImpl.java`
|
||||
**方法**: `updateSelfScores()`
|
||||
|
||||
```java
|
||||
private void updateSelfScores(Long applicationId, List<XskhAssessmentSelfScoreBo> selfScoreList) {
|
||||
if (selfScoreList != null && !selfScoreList.isEmpty()) {
|
||||
for (XskhAssessmentSelfScoreBo selfScoreBo : selfScoreList) {
|
||||
XskhAssessmentSelfScore selfScore = MapstructUtils.convert(selfScoreBo, XskhAssessmentSelfScore.class);
|
||||
selfScore.setApplicationId(applicationId);
|
||||
|
||||
// 如果ID存在,则更新;否则新增
|
||||
if (selfScore.getId() != null) {
|
||||
// 更新现有记录
|
||||
selfScoreMapper.updateById(selfScore);
|
||||
} else {
|
||||
// 新增记录
|
||||
selfScoreMapper.insert(selfScore);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. 修复附加分申请更新逻辑
|
||||
**文件**: `XskhAssessmentApplicationApprovalServiceImpl.java`
|
||||
**方法**: `updateBonusApprovals()`
|
||||
|
||||
```java
|
||||
private void updateBonusApprovals(Long applicationId, List<XskhAssessmentBonusApprovalBo> bonusApprovalList) {
|
||||
if (bonusApprovalList != null && !bonusApprovalList.isEmpty()) {
|
||||
for (XskhAssessmentBonusApprovalBo bonusApprovalBo : bonusApprovalList) {
|
||||
XskhAssessmentBonusApproval bonusApproval = MapstructUtils.convert(bonusApprovalBo,
|
||||
XskhAssessmentBonusApproval.class);
|
||||
bonusApproval.setApplicationId(applicationId);
|
||||
|
||||
// 如果ID存在,则更新;否则新增
|
||||
if (bonusApproval.getId() != null) {
|
||||
// 更新现有记录
|
||||
bonusApprovalMapper.updateById(bonusApproval);
|
||||
} else {
|
||||
// 新增记录,设置默认状态
|
||||
bonusApproval.setStatus("1"); // 默认待审核状态
|
||||
bonusApprovalMapper.insert(bonusApproval);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 修复效果
|
||||
|
||||
### 优势
|
||||
1. **保留审计信息**: 不再删除重建,保留原有的创建时间、创建人等字段
|
||||
2. **避免主键冲突**: 根据ID存在性智能选择更新或插入操作
|
||||
3. **数据完整性**: 确保数据的连续性和完整性
|
||||
4. **性能优化**: 避免不必要的删除和插入操作
|
||||
|
||||
### 测试验证
|
||||
- ✅ 新增考核申请:正常插入新记录
|
||||
- ✅ 修改考核申请:正常更新现有记录
|
||||
- ✅ 混合操作:同时包含新增和修改的记录
|
||||
- ✅ 数据完整性:审计字段正确保留
|
||||
|
||||
## 经验总结
|
||||
|
||||
### 开发规范
|
||||
1. **更新操作原则**: 避免"删除重建"模式,优先使用"智能更新"
|
||||
2. **ID处理策略**: 根据ID存在性决定操作类型
|
||||
3. **审计字段保护**: 更新时注意保护创建时间、创建人等审计信息
|
||||
4. **事务完整性**: 确保关联数据的更新在同一个事务中
|
||||
|
||||
### 代码审查要点
|
||||
- 检查更新逻辑是否采用"删除重建"模式
|
||||
- 验证是否正确处理已存在记录的ID
|
||||
- 确认审计字段的保留策略
|
||||
- 测试混合操作场景(新增+修改)
|
||||
|
||||
## 相关文件
|
||||
|
||||
- **修复文件**: `backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/service/impl/XskhAssessmentApplicationApprovalServiceImpl.java`
|
||||
- **涉及表**:
|
||||
- `xskh_assessment_self_score` (学生考核自评得分表)
|
||||
- `xskh_assessment_bonus_approval` (附加分申请表)
|
||||
- **相关接口**: `PUT /assessment/application`
|
||||
|
||||
---
|
||||
|
||||
**修复时间**: 2025-08-21
|
||||
**修复人员**: AI Assistant
|
||||
**状态**: 已完成
|
||||
@@ -1,153 +0,0 @@
|
||||
# 学生考核自评得分查询字段错误修复报告
|
||||
|
||||
## 问题描述
|
||||
|
||||
**错误时间**: 2025-08-21 11:53:24
|
||||
**错误接口**: `/assessment/approval/1958361581653856257`
|
||||
**错误类型**: SQL语法错误 - 未知字段
|
||||
|
||||
### 错误详情
|
||||
```
|
||||
org.springframework.jdbc.BadSqlGrammarException:
|
||||
Unknown column 'i.indicator_description' in 'field list'
|
||||
```
|
||||
|
||||
### 错误SQL
|
||||
```sql
|
||||
SELECT s.id, s.application_id, s.indicator_id, s.indicator_name,
|
||||
i.indicator_code, i.indicator_description, s.indicator_type,
|
||||
s.max_score, s.self_score, s.self_remark, s.teacher_score,
|
||||
s.teacher_remark, s.create_by, s.create_time, s.update_by, s.update_time
|
||||
FROM xskh_assessment_self_score s
|
||||
LEFT JOIN xskh_assessment_indicator i ON s.indicator_id = i.id AND i.tenant_id = '000000'
|
||||
WHERE s.application_id = ? AND s.deleted = 0 AND s.tenant_id = '000000'
|
||||
ORDER BY s.create_time ASC
|
||||
```
|
||||
|
||||
## 问题分析
|
||||
|
||||
### 根本原因
|
||||
1. **字段名不匹配**: SQL查询中使用了 `i.indicator_description`,但数据库表中实际字段名为 `description`
|
||||
2. **数据库表结构**: `xskh_assessment_indicator` 表中的字段名是 `description`,不是 `indicator_description`
|
||||
|
||||
### 数据库表结构确认
|
||||
```sql
|
||||
-- xskh_assessment_indicator 表结构
|
||||
CREATE TABLE `xskh_assessment_indicator` (
|
||||
`id` bigint(20) NOT NULL COMMENT '主键ID',
|
||||
`indicator_code` varchar(50) NOT NULL COMMENT '指标编码',
|
||||
`indicator_name` varchar(100) NOT NULL COMMENT '指标名称',
|
||||
`indicator_type_id` bigint(20) NOT NULL COMMENT '指标类型ID',
|
||||
`indicator_type_name` varchar(100) NOT NULL COMMENT '指标类型名称',
|
||||
`description` varchar(500) DEFAULT NULL COMMENT '指标说明', -- 正确字段名
|
||||
`max_score` decimal(5,2) NOT NULL COMMENT '最高分值',
|
||||
-- ... 其他字段
|
||||
);
|
||||
```
|
||||
|
||||
## 修复方案
|
||||
|
||||
### 修复文件
|
||||
- **文件路径**: `backend/ruoyi-modules/ruoyi-xskh/src/main/resources/mapper/xskh/XskhAssessmentSelfScoreMapper.xml`
|
||||
- **修复方法**: 将SQL查询中的字段名从 `i.indicator_description` 改为 `i.description`
|
||||
|
||||
### 字段命名统一优化
|
||||
为了保持前后端字段命名的一致性,同时进行了以下优化:
|
||||
|
||||
1. **VO类字段统一**: 将 `indicatorDescription` 改为 `description`
|
||||
2. **Mapper映射统一**: 更新ResultMap中的字段映射
|
||||
3. **相关文件同步**: 修改了所有相关的Mapper文件和VO类
|
||||
|
||||
### 具体修复内容
|
||||
|
||||
#### 1. 修复ResultMap映射
|
||||
```xml
|
||||
<!-- 修复前 -->
|
||||
<result property="indicatorDescription" column="indicator_description"/>
|
||||
|
||||
<!-- 修复后 -->
|
||||
<result property="description" column="description"/>
|
||||
```
|
||||
|
||||
#### 2. 修复SQL查询语句
|
||||
```xml
|
||||
<!-- 修复前 -->
|
||||
SELECT
|
||||
s.id, s.application_id, s.indicator_id, s.indicator_name,
|
||||
i.indicator_code, i.indicator_description, s.indicator_type,
|
||||
-- ... 其他字段
|
||||
|
||||
<!-- 修复后 -->
|
||||
SELECT
|
||||
s.id, s.application_id, s.indicator_id, s.indicator_name,
|
||||
i.indicator_code, i.description, s.indicator_type,
|
||||
-- ... 其他字段
|
||||
```
|
||||
|
||||
### 修复后的完整SQL
|
||||
```sql
|
||||
SELECT
|
||||
s.id,
|
||||
s.application_id,
|
||||
s.indicator_id,
|
||||
s.indicator_name,
|
||||
i.indicator_code,
|
||||
i.description, -- 修复:使用正确的字段名
|
||||
s.indicator_type,
|
||||
s.max_score,
|
||||
s.self_score,
|
||||
s.self_remark,
|
||||
s.teacher_score,
|
||||
s.teacher_remark,
|
||||
s.create_by,
|
||||
s.create_time,
|
||||
s.update_by,
|
||||
s.update_time
|
||||
FROM xskh_assessment_self_score s
|
||||
LEFT JOIN xskh_assessment_indicator i ON s.indicator_id = i.id AND i.tenant_id = '000000'
|
||||
WHERE s.application_id = #{applicationId}
|
||||
AND s.deleted = 0
|
||||
AND s.tenant_id = '000000'
|
||||
ORDER BY s.create_time ASC
|
||||
```
|
||||
|
||||
## 验证结果
|
||||
|
||||
### 修复验证
|
||||
1. ✅ **字段映射正确**: ResultMap中的 `description` 字段正确映射到数据库的 `description` 字段
|
||||
2. ✅ **SQL语法正确**: 查询语句使用正确的字段名,符合数据库表结构
|
||||
3. ✅ **VO类兼容**: `XskhAssessmentSelfScoreVo` 类中已正确定义 `description` 字段
|
||||
4. ✅ **字段命名统一**: 前后端字段名保持一致,避免混淆
|
||||
|
||||
### 测试建议
|
||||
1. **接口测试**: 重新调用 `/assessment/approval/{id}` 接口,确认不再出现字段错误
|
||||
2. **数据验证**: 确认返回的指标说明数据正确显示
|
||||
3. **功能测试**: 测试学生考核审核功能,确认自评得分查询正常
|
||||
|
||||
## 经验总结
|
||||
|
||||
### 开发规范提醒
|
||||
1. **字段命名一致性**: SQL查询中的字段名必须与数据库表结构完全一致
|
||||
2. **数据库设计规范**: 遵循项目统一的字段命名规范,避免混淆
|
||||
3. **代码审查**: 在开发过程中注意检查SQL语句的字段名正确性
|
||||
|
||||
### 预防措施
|
||||
1. **数据库文档**: 及时更新数据库设计文档,确保字段名准确
|
||||
2. **代码规范**: 建立SQL编写规范,要求字段名与数据库表结构保持一致
|
||||
3. **测试覆盖**: 增加SQL语法检查的自动化测试
|
||||
|
||||
## 相关文件
|
||||
|
||||
- **数据库设计**: `docs/设计文档/database/学生考核管理/学生考核管理数据库模型.sql`
|
||||
- **Mapper文件**:
|
||||
- `backend/ruoyi-modules/ruoyi-xskh/src/main/resources/mapper/xskh/XskhAssessmentSelfScoreMapper.xml`
|
||||
- `backend/ruoyi-modules/ruoyi-xskh/src/main/resources/mapper/xskh/XskhAssessmentPlanMapper.xml`
|
||||
- **VO类**:
|
||||
- `backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/domain/vo/XskhAssessmentSelfScoreVo.java`
|
||||
- `backend/ruoyi-modules/ruoyi-xskh/src/main/java/org/dromara/xskh/domain/vo/XskhAssessmentPlanIndicatorVo.java`
|
||||
|
||||
---
|
||||
|
||||
**修复人员**: Cursor AI
|
||||
**修复时间**: 2025-08-21
|
||||
**修复状态**: ✅ 已完成
|
||||
Reference in new issue
Block a user