2026-02-11 10:42:38 +08:00
|
|
|
|
# 员工调动记录唯一性校验功能实施总结
|
|
|
|
|
|
|
|
|
|
|
|
## 实施日期
|
|
|
|
|
|
2026-02-11
|
|
|
|
|
|
|
|
|
|
|
|
## 功能概述
|
|
|
|
|
|
实现了员工调动记录的唯一性校验功能,根据 **员工ID + 调动前部门ID + 调动后部门ID + 调动日期** 形成唯一键进行校验。
|
|
|
|
|
|
|
|
|
|
|
|
## 实施内容
|
|
|
|
|
|
|
|
|
|
|
|
### 1. 数据库层面 ✓
|
|
|
|
|
|
|
|
|
|
|
|
#### 创建的文件
|
|
|
|
|
|
- `doc/数据库文档/员工调动记录/04_add_unique_index.sql`
|
|
|
|
|
|
|
|
|
|
|
|
#### 执行结果
|
|
|
|
|
|
- ✓ 清理重复数据:删除1999条重复记录(保留每组中ID最小的)
|
|
|
|
|
|
- ✓ 创建唯一索引:`uk_staff_transfer_date (staff_id, dept_id_before, dept_id_after, transfer_date)`
|
|
|
|
|
|
- ✓ 数据库强制约束生效
|
|
|
|
|
|
|
|
|
|
|
|
### 2. 代码层面
|
|
|
|
|
|
|
|
|
|
|
|
#### 2.1 DTO类 ✓
|
|
|
|
|
|
**文件**: `com.ruoyi.ccdi.domain.dto.TransferUniqueKey`
|
|
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
|
// 主要功能:
|
|
|
|
|
|
- 包含唯一键字段(staffId, deptIdBefore, deptIdAfter, transferDate)
|
|
|
|
|
|
- toUniqueString() 方法生成唯一标识
|
|
|
|
|
|
- 静态方法 from() 从 AddDTO/EditDTO 构建唯一键
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 2.2 Mapper层 ✓
|
|
|
|
|
|
**修改文件**:
|
|
|
|
|
|
- `CcdiStaffTransferMapper.java`
|
|
|
|
|
|
- `CcdiStaffTransferMapper.xml`
|
|
|
|
|
|
|
|
|
|
|
|
**新增方法**:
|
|
|
|
|
|
```java
|
|
|
|
|
|
// 批量查询已存在记录
|
|
|
|
|
|
List<CcdiStaffTransfer> batchCheckExists(List<TransferUniqueKey> keys)
|
|
|
|
|
|
|
|
|
|
|
|
// 查询单条记录是否存在
|
|
|
|
|
|
CcdiStaffTransfer checkExists(TransferUniqueKey key)
|
|
|
|
|
|
|
|
|
|
|
|
// 查询单条记录是否存在(排除指定ID)
|
|
|
|
|
|
CcdiStaffTransfer checkExistsExcludeId(TransferUniqueKey key, Long excludeId)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 2.3 Service层 ✓
|
|
|
|
|
|
**修改文件**:
|
|
|
|
|
|
- `ICcdiStaffTransferService.java` - 新增接口定义
|
|
|
|
|
|
- `CcdiStaffTransferServiceImpl.java` - 实现校验逻辑
|
|
|
|
|
|
|
|
|
|
|
|
**新增方法**:
|
|
|
|
|
|
```java
|
|
|
|
|
|
// 新增时校验唯一性
|
|
|
|
|
|
void checkUniqueForAdd(CcdiStaffTransferAddDTO addDTO)
|
|
|
|
|
|
|
|
|
|
|
|
// 编辑时校验唯一性
|
|
|
|
|
|
void checkUniqueForEdit(CcdiStaffTransferEditDTO editDTO)
|
|
|
|
|
|
|
|
|
|
|
|
// 批量校验唯一性(用于导入)
|
|
|
|
|
|
List<StaffTransferImportFailureVO> batchCheckUnique(List<CcdiStaffTransferExcel> excelList)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**修改方法**:
|
|
|
|
|
|
```java
|
|
|
|
|
|
// insertTransfer() - 添加唯一性校验
|
|
|
|
|
|
// updateTransfer() - 添加唯一性校验(排除自身)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 2.4 导入服务 ✓
|
|
|
|
|
|
**修改文件**: `CcdiStaffTransferImportServiceImpl.java`
|
|
|
|
|
|
|
|
|
|
|
|
**修改内容**:
|
|
|
|
|
|
- 导入前先调用 `batchCheckUnique()` 进行批量唯一性校验
|
|
|
|
|
|
- 过滤掉Excel内部重复和数据库已存在的记录
|
|
|
|
|
|
- 只对有效记录进行数据验证和插入
|
|
|
|
|
|
- 失败记录包含详细的重复原因
|
|
|
|
|
|
|
|
|
|
|
|
#### 2.5 全局异常处理 ✓
|
|
|
|
|
|
**修改文件**: `GlobalExceptionHandler.java`
|
|
|
|
|
|
|
|
|
|
|
|
**新增处理**:
|
|
|
|
|
|
```java
|
|
|
|
|
|
@ExceptionHandler(RuntimeException.class)
|
|
|
|
|
|
public AjaxResult handleRuntimeException(...)
|
|
|
|
|
|
// 处理数据库唯一键冲突,提供友好错误提示
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 3. 测试 ✓
|
|
|
|
|
|
|
|
|
|
|
|
#### 测试文件
|
|
|
|
|
|
- `doc/测试数据/员工调动记录/test_unique_constraint.py`
|
|
|
|
|
|
- `doc/测试数据/员工调动记录/test_unique_constraint_report.md`
|
|
|
|
|
|
|
|
|
|
|
|
#### 测试结果
|
|
|
|
|
|
| 测试用例 | 状态 | 说明 |
|
|
|
|
|
|
|---------|------|------|
|
|
|
|
|
|
| 新增正常记录 | ✓ PASS | 成功创建调动记录 |
|
|
|
|
|
|
| 新增重复记录 | ✓ PASS | 数据库唯一索引成功拦截 |
|
|
|
|
|
|
| 编辑非关键字段 | ✓ PASS | 修改职级、岗位等非唯一键字段成功 |
|
|
|
|
|
|
| 编辑为重复记录 | ✓ PASS | 成功拦截重复记录 |
|
|
|
|
|
|
|
|
|
|
|
|
## 技术亮点
|
|
|
|
|
|
|
|
|
|
|
|
### 1. 多层防护机制
|
|
|
|
|
|
- **业务层校验**: 在Service层提供友好的业务提示
|
|
|
|
|
|
- **数据库约束**: 通过唯一索引保证数据完整性
|
|
|
|
|
|
|
|
|
|
|
|
### 2. 批量校验优化
|
|
|
|
|
|
导入时使用批量查询,避免N+1查询问题:
|
|
|
|
|
|
- Excel内部去重:使用Set记录唯一键
|
|
|
|
|
|
- 批量查询数据库:一次查询所有可能的重复
|
|
|
|
|
|
- 复杂度优化:O(n) 而非 O(n²)
|
|
|
|
|
|
|
|
|
|
|
|
### 3. 友好的错误提示
|
|
|
|
|
|
- 新增/编辑时:具体说明哪个员工在哪天的调动记录重复
|
|
|
|
|
|
- 导入时:区分Excel内部重复和数据库已存在两种情况
|
|
|
|
|
|
- 全局异常:提供用户友好的错误信息
|
|
|
|
|
|
|
|
|
|
|
|
## 文件清单
|
|
|
|
|
|
|
|
|
|
|
|
### 数据库
|
|
|
|
|
|
```
|
|
|
|
|
|
doc/数据库文档/员工调动记录/04_add_unique_index.sql
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Java源码
|
|
|
|
|
|
```
|
2026-02-24 17:12:11 +08:00
|
|
|
|
ruoyi-info-collection/src/main/java/com/ruoyi/ccdi/
|
2026-02-11 10:42:38 +08:00
|
|
|
|
├── domain/dto/
|
|
|
|
|
|
│ └── TransferUniqueKey.java [新增]
|
|
|
|
|
|
├── mapper/
|
|
|
|
|
|
│ ├── CcdiStaffTransferMapper.java [修改]
|
|
|
|
|
|
│ └── CcdiStaffTransferMapper.xml [修改]
|
|
|
|
|
|
├── service/
|
|
|
|
|
|
│ ├── ICcdiStaffTransferService.java [修改]
|
|
|
|
|
|
│ └── impl/
|
|
|
|
|
|
│ ├── CcdiStaffTransferServiceImpl.java [修改]
|
|
|
|
|
|
│ └── CcdiStaffTransferImportServiceImpl.java [修改]
|
|
|
|
|
|
|
|
|
|
|
|
ruoyi-framework/src/main/java/com/ruoyi/framework/web/exception/
|
|
|
|
|
|
└── GlobalExceptionHandler.java [修改]
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 测试
|
|
|
|
|
|
```
|
|
|
|
|
|
doc/测试数据/员工调动记录/
|
|
|
|
|
|
├── test_unique_constraint.py [新增]
|
|
|
|
|
|
└── test_unique_constraint_report.md [新增]
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 部署说明
|
|
|
|
|
|
|
|
|
|
|
|
### 1. 数据库升级
|
|
|
|
|
|
执行以下SQL脚本:
|
|
|
|
|
|
```bash
|
|
|
|
|
|
mysql -u root -p ccdi < doc/数据库文档/员工调动记录/04_add_unique_index.sql
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 2. 代码部署
|
|
|
|
|
|
- 更新上述Java文件到对应目录
|
|
|
|
|
|
- 重新编译打包:`mvn clean package`
|
|
|
|
|
|
- 重启应用
|
|
|
|
|
|
|
|
|
|
|
|
### 3. 验证
|
|
|
|
|
|
- 访问 `/swagger-ui/index.html` 查看API文档
|
|
|
|
|
|
- 尝试新增重复记录,验证唯一性约束
|
|
|
|
|
|
- 导入包含重复数据的Excel,验证批量校验
|
|
|
|
|
|
|
|
|
|
|
|
## 注意事项
|
|
|
|
|
|
|
|
|
|
|
|
1. **数据清理**: 首次执行时会清理重复数据,请确保已备份重要数据
|
|
|
|
|
|
2. **性能影响**: 唯一索引会影响插入性能,但对查询性能有提升
|
|
|
|
|
|
3. **兼容性**: 导入功能会跳过重复记录,不影响正常数据的导入
|
|
|
|
|
|
|
|
|
|
|
|
## 后续优化建议
|
|
|
|
|
|
|
|
|
|
|
|
1. **异步处理**: 对于大批量导入,可以考虑使用异步任务处理
|
|
|
|
|
|
2. **前端提示**: 前端可以提前进行表单内的重复检查
|
|
|
|
|
|
3. **历史数据**: 对于历史数据,可以提供数据清洗工具
|
|
|
|
|
|
|
|
|
|
|
|
## 实施状态
|
|
|
|
|
|
✅ 全部完成
|