docs: 添加员工信息导入结果弹窗自适应优化设计文档
- 分析现有问题:弹窗内容过多时超出视口 - 设计固定高度+内容可滚动的Flexbox布局方案 - 提供完整的CSS样式和响应式设计 - 包含实施计划、验收标准和技术要点 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
BIN
doc/other/ScreenShot_2026-02-05_154534_027.png
Normal file
BIN
doc/other/ScreenShot_2026-02-05_154534_027.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 393 KiB |
347
doc/plans/2025-02-05-ccdi_staff_recruitment.md
Normal file
347
doc/plans/2025-02-05-ccdi_staff_recruitment.md
Normal file
@@ -0,0 +1,347 @@
|
||||
# 员工招聘信息管理功能设计文档
|
||||
|
||||
**文档版本:** 1.0
|
||||
**创建日期:** 2025-02-05
|
||||
**模块名称:** ccdi-staff-recruitment
|
||||
**作者:** Claude
|
||||
|
||||
---
|
||||
|
||||
## 1. 概述
|
||||
|
||||
### 1.1 功能简介
|
||||
员工招聘信息管理模块提供招聘信息的记录、查询、导入导出等基础维护功能,支持单条和批量操作。
|
||||
|
||||
### 1.2 业务场景
|
||||
- 简单的招聘信息记录,作为数据存档使用
|
||||
- 支持招聘信息的增删改查操作
|
||||
- 支持Excel批量导入和导出
|
||||
|
||||
### 1.3 技术选型
|
||||
- **后端框架:** Spring Boot 3.5.8 + MyBatis Plus 3.5.10
|
||||
- **数据库:** MySQL 8.2.0
|
||||
- **前端框架:** Vue 2.6.12 + Element UI 2.15.14
|
||||
- **数据校验:** javax.validation + 自定义校验注解
|
||||
|
||||
---
|
||||
|
||||
## 2. 数据库设计
|
||||
|
||||
### 2.1 表结构
|
||||
|
||||
**表名:** `ccdi_staff_recruitment`
|
||||
|
||||
```sql
|
||||
CREATE TABLE `ccdi_staff_recruitment` (
|
||||
`recruit_id` varchar(32) NOT NULL COMMENT '招聘项目编号',
|
||||
`recruit_name` varchar(100) NOT NULL COMMENT '招聘项目名称',
|
||||
`pos_name` varchar(100) NOT NULL COMMENT '职位名称',
|
||||
`pos_category` varchar(50) NOT NULL COMMENT '职位类别',
|
||||
`pos_desc` text NOT NULL COMMENT '职位描述',
|
||||
`cand_name` varchar(20) NOT NULL COMMENT '应聘人员姓名',
|
||||
`cand_edu` varchar(20) NOT NULL COMMENT '应聘人员学历',
|
||||
`cand_id` varchar(18) NOT NULL COMMENT '应聘人员证件号码',
|
||||
`cand_school` varchar(50) NOT NULL COMMENT '应聘人员毕业院校',
|
||||
`cand_major` varchar(30) NOT NULL COMMENT '应聘人员专业',
|
||||
`cand_grad` varchar(6) NOT NULL COMMENT '应聘人员毕业年月',
|
||||
`admit_status` varchar(10) NOT NULL COMMENT '录用情况:录用、未录用、放弃',
|
||||
`interviewer_name1` varchar(20) DEFAULT NULL COMMENT '面试官1姓名',
|
||||
`interviewer_id1` varchar(10) DEFAULT NULL COMMENT '面试官1工号',
|
||||
`interviewer_name2` varchar(20) DEFAULT NULL COMMENT '面试官2姓名',
|
||||
`interviewer_id2` varchar(10) DEFAULT NULL COMMENT '面试官2工号',
|
||||
`created_by` varchar(20) NOT NULL COMMENT '记录创建人',
|
||||
`updated_by` varchar(20) DEFAULT NULL COMMENT '记录更新人',
|
||||
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
PRIMARY KEY (`recruit_id`),
|
||||
KEY `idx_cand_id` (`cand_id`),
|
||||
KEY `idx_admit_status` (`admit_status`),
|
||||
KEY `idx_interviewer_id1` (`interviewer_id1`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='员工招聘信息表';
|
||||
```
|
||||
|
||||
### 2.2 索引设计
|
||||
- **主键索引:** `recruit_id`
|
||||
- **业务索引:** `cand_id`, `admit_status`, `interviewer_id1`
|
||||
|
||||
### 2.3 枚举值设计
|
||||
|
||||
**录用状态 (admit_status):**
|
||||
| 枚举值 | 说明 |
|
||||
|--------|------|
|
||||
| 录用 | 已录用该候选人 |
|
||||
| 未录用 | 未录用该候选人 |
|
||||
| 放弃 | 候选人放弃 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 后端设计
|
||||
|
||||
### 3.1 模块结构
|
||||
|
||||
```
|
||||
ruoyi-ccdi/
|
||||
├── domain/
|
||||
│ ├── CcdiStaffRecruitment.java # 实体类
|
||||
│ ├── dto/
|
||||
│ │ ├── CcdiStaffRecruitmentQueryDTO.java # 查询DTO
|
||||
│ │ ├── CcdiStaffRecruitmentAddDTO.java # 新增DTO
|
||||
│ │ └── CcdiStaffRecruitmentEditDTO.java # 修改DTO
|
||||
│ ├── vo/
|
||||
│ │ └── CcdiStaffRecruitmentVO.java # 返回VO
|
||||
│ └── excel/
|
||||
│ └── CcdiStaffRecruitmentExcel.java # Excel导入导出类
|
||||
├── mapper/
|
||||
│ ├── CcdiStaffRecruitmentMapper.java # MyBatis Mapper接口
|
||||
│ └── xml/
|
||||
│ └── CcdiStaffRecruitmentMapper.xml # MyBatis XML映射
|
||||
├── service/
|
||||
│ ├── ICcdiStaffRecruitmentService.java # 服务接口
|
||||
│ └── impl/
|
||||
│ └── CcdiStaffRecruitmentServiceImpl.java # 服务实现
|
||||
└── controller/
|
||||
└── CcdiStaffRecruitmentController.java # 控制器
|
||||
```
|
||||
|
||||
### 3.2 API接口设计
|
||||
|
||||
**基础路径:** `/ccdi/staffRecruitment`
|
||||
|
||||
| 接口功能 | HTTP方法 | 路径 | 权限标识 |
|
||||
|---------|---------|------|---------|
|
||||
| 分页查询 | GET | `/list` | ccdi:staffRecruitment:list |
|
||||
| 详情查询 | GET | `/{recruitId}` | ccdi:staffRecruitment:query |
|
||||
| 新增 | POST | `/` | ccdi:staffRecruitment:add |
|
||||
| 修改 | PUT | `/` | ccdi:staffRecruitment:edit |
|
||||
| 删除 | DELETE | `/{recruitIds}` | ccdi:staffRecruitment:remove |
|
||||
| 导入模板下载 | GET | `/importTemplate` | ccdi:staffRecruitment:import |
|
||||
| 批量导入 | POST | `/importData` | ccdi:staffRecruitment:import |
|
||||
| 导出 | POST | `/export` | ccdi:staffRecruitment:export |
|
||||
|
||||
### 3.3 查询参数设计
|
||||
|
||||
**CcdiStaffRecruitmentQueryDTO:**
|
||||
```java
|
||||
// 查询条件
|
||||
private String recruitName; // 招聘项目名称(模糊查询)
|
||||
private String posName; // 职位名称(模糊查询)
|
||||
private String candName; // 候选人姓名(模糊查询)
|
||||
private String candId; // 证件号码(精确查询)
|
||||
private String admitStatus; // 录用状态(精确查询)
|
||||
private String interviewerName; // 面试官姓名(模糊查询,查询面试官1或2)
|
||||
private String interviewerId; // 面试官工号(精确查询,查询面试官1或2)
|
||||
|
||||
// 分页参数
|
||||
private Integer pageNum = 1;
|
||||
private Integer pageSize = 10;
|
||||
```
|
||||
|
||||
### 3.4 数据校验规则
|
||||
|
||||
| 字段 | 校验规则 | 错误提示 |
|
||||
|-----|---------|---------|
|
||||
| recruitName | @NotBlank, @Size(max=100) | 招聘项目名称不能为空/长度不能超过100 |
|
||||
| posName | @NotBlank, @Size(max=100) | 职位名称不能为空/长度不能超过100 |
|
||||
| candName | @NotBlank, @Size(max=20) | 应聘人员姓名不能为空/长度不能超过20 |
|
||||
| candId | @NotBlank, @Pattern(身份证正则) | 证件号码不能为空/格式不正确 |
|
||||
| candGrad | @NotBlank, @Pattern(YYYYMM) | 毕业年月不能为空/格式不正确 |
|
||||
| admitStatus | @NotBlank, @EnumValid | 录用情况不能为空/状态值不合法 |
|
||||
|
||||
### 3.5 批量导入功能设计
|
||||
|
||||
**核心优化点:**
|
||||
1. **批量查询已存在记录:** 使用 `selectBatchIds` 一次性查询
|
||||
2. **批量插入:** 使用 `saveBatch()` 方法
|
||||
3. **批量更新:** 使用 `updateBatchById()` 方法
|
||||
4. **错误信息:** 只返回错误的数据行,成功数据不展示
|
||||
|
||||
**性能提升:**
|
||||
- 原方案: ~3000次数据库操作 (导入1000条)
|
||||
- 优化后: ~3次数据库操作 (导入1000条)
|
||||
- 性能提升: ~1000倍
|
||||
|
||||
**导入逻辑:**
|
||||
```
|
||||
1. 收集所有recruit_id
|
||||
2. 批量查询已存在的记录
|
||||
3. 遍历Excel数据:
|
||||
- 数据转换和校验
|
||||
- 分类为: 待新增列表、待更新列表
|
||||
- 记录校验失败的数据
|
||||
4. 批量插入待新增数据
|
||||
5. 批量更新待更新数据
|
||||
6. 只返回错误信息
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 前端设计
|
||||
|
||||
### 4.1 页面结构
|
||||
|
||||
```
|
||||
ruoyi-ui/src/views/ccdiStaffRecruitment/
|
||||
├── index.vue # 列表页面(主页面)
|
||||
└── components/
|
||||
├── RecruitmentForm.vue # 新增/修改表单组件
|
||||
└── ImportDialog.vue # 导入对话框组件
|
||||
```
|
||||
|
||||
### 4.2 功能列表
|
||||
|
||||
**列表页面 (index.vue):**
|
||||
- 顶部查询表单
|
||||
- 招聘项目名称(模糊查询)
|
||||
- 职位名称(模糊查询)
|
||||
- 候选人姓名(模糊查询)
|
||||
- 证件号码(精确查询)
|
||||
- 录用状态(下拉选择)
|
||||
- 面试官姓名(模糊查询)
|
||||
- 面试官工号(精确查询)
|
||||
- 数据表格
|
||||
- 展示所有字段信息
|
||||
- 支持排序
|
||||
- 操作按钮
|
||||
- 新增
|
||||
- 批量导入
|
||||
- 导出
|
||||
- 批量删除
|
||||
- 行操作
|
||||
- 修改
|
||||
- 删除
|
||||
|
||||
**表单组件 (RecruitmentForm.vue):**
|
||||
- 所有必填字段添加 `required: true`
|
||||
- 证件号码正则校验
|
||||
- 毕业年月格式校验(YYYYMM)
|
||||
- 录用状态下拉选择(枚举值)
|
||||
|
||||
---
|
||||
|
||||
## 5. 异常处理
|
||||
|
||||
### 5.1 异常分类
|
||||
|
||||
| 异常类型 | HTTP状态码 | 使用场景 |
|
||||
|---------|-----------|---------|
|
||||
| ServiceException | 500 | 业务逻辑异常 |
|
||||
| ValidationException | 400 | 参数校验失败 |
|
||||
| DuplicateKeyException | 409 | 主键冲突 |
|
||||
| FileNotFoundException | 404 | 文件不存在 |
|
||||
|
||||
### 5.2 统一异常处理
|
||||
|
||||
使用 `@RestControllerAdvice` 全局异常处理器捕获和处理异常。
|
||||
|
||||
---
|
||||
|
||||
## 6. 测试策略
|
||||
|
||||
### 6.1 单元测试
|
||||
|
||||
**测试范围:**
|
||||
- 实体类校验注解测试
|
||||
- 数据转换工具方法测试
|
||||
- 业务逻辑核心方法测试
|
||||
|
||||
**关键测试用例:**
|
||||
1. 正常数据导入测试
|
||||
2. 身份证格式校验测试
|
||||
3. 批量插入性能测试
|
||||
|
||||
### 6.2 集成测试
|
||||
|
||||
**测试流程:**
|
||||
1. 登录获取Token
|
||||
2. 分页查询测试
|
||||
3. 单条新增测试
|
||||
4. 单条修改测试
|
||||
5. 批量导入测试
|
||||
6. 导出测试
|
||||
7. 批量删除测试
|
||||
|
||||
### 6.3 性能指标
|
||||
|
||||
| 测试场景 | 预期性能 |
|
||||
|---------|---------|
|
||||
| 分页查询(1000条) | < 200ms |
|
||||
| 单条新增 | < 100ms |
|
||||
| 批量导入(1000条) | < 5s |
|
||||
| 批量删除(100条) | < 500ms |
|
||||
| 导出(1000条) | < 2s |
|
||||
|
||||
---
|
||||
|
||||
## 7. 实施步骤
|
||||
|
||||
### 第一步:数据库准备
|
||||
1. 执行建表SQL
|
||||
2. 在菜单表中添加菜单和权限配置
|
||||
|
||||
### 第二步:后端开发
|
||||
1. 创建枚举类
|
||||
2. 创建实体类、DTO、VO、Excel类
|
||||
3. 创建Mapper接口和XML
|
||||
4. 创建Service接口和实现
|
||||
5. 创建Controller
|
||||
6. 编写单元测试
|
||||
7. Swagger-UI测试
|
||||
|
||||
### 第三步:前端开发
|
||||
1. 创建API接口定义
|
||||
2. 开发表格查询页面
|
||||
3. 开发表单组件
|
||||
4. 开发导入对话框
|
||||
5. 配置路由
|
||||
6. 配置菜单
|
||||
|
||||
### 第四步:集成测试
|
||||
1. 准备测试数据
|
||||
2. 执行集成测试
|
||||
3. 验证功能
|
||||
4. 生成测试报告
|
||||
|
||||
### 第五步:文档编写
|
||||
1. 生成API文档
|
||||
2. 编写使用说明
|
||||
|
||||
---
|
||||
|
||||
## 8. 附录
|
||||
|
||||
### 8.1 Excel导入模板字段顺序
|
||||
|
||||
按CSV字段顺序设计:
|
||||
1. 招聘项目编号
|
||||
2. 招聘项目名称
|
||||
3. 职位名称
|
||||
4. 职位类别
|
||||
5. 职位描述
|
||||
6. 应聘人员姓名
|
||||
7. 应聘人员学历
|
||||
8. 应聘人员证件号码
|
||||
9. 应聘人员毕业院校
|
||||
10. 应聘人员专业
|
||||
11. 应聘人员毕业年月
|
||||
12. 录用情况
|
||||
13. 面试官1姓名
|
||||
14. 面试官1工号
|
||||
15. 面试官2姓名
|
||||
16. 面试官2工号
|
||||
|
||||
### 8.2 MyBatis Plus配置
|
||||
|
||||
确保项目中已配置MyBatis Plus分页插件:
|
||||
|
||||
```java
|
||||
@Bean
|
||||
public MybatisPlusInterceptor mybatisPlusInterceptor() {
|
||||
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
|
||||
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
|
||||
return interceptor;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**文档结束**
|
||||
@@ -0,0 +1,395 @@
|
||||
# 员工信息导入结果弹窗自适应优化设计
|
||||
|
||||
**日期**: 2025-02-05
|
||||
**模块**: 员工信息管理 (ccdiEmployee)
|
||||
**问题**: 导入结果弹窗在失败数据较多时,内容过长未自适应页面大小
|
||||
|
||||
---
|
||||
|
||||
## 1. 问题分析
|
||||
|
||||
### 1.1 问题描述
|
||||
|
||||
当前员工信息维护页面中的导入结果弹窗使用 Element UI 的 `$alert` 组件展示导入结果。当导入失败记录较多(如50+条)时,弹窗会出现以下问题:
|
||||
- 弹窗可能超出视口高度
|
||||
- 需要滚动整个页面才能看到确定按钮
|
||||
- 用户体验不佳
|
||||
|
||||
### 1.2 现状分析
|
||||
|
||||
**前端实现** (index.vue:500-507):
|
||||
```javascript
|
||||
handleFileSuccess(response, file, fileList) {
|
||||
this.upload.isUploading = false;
|
||||
this.upload.open = false;
|
||||
this.getList();
|
||||
this.$alert(response.msg, "导入结果", {
|
||||
dangerouslyUseHTMLString: true,
|
||||
customClass: 'import-result-dialog'
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
**后端返回格式** (CcdiEmployeeServiceImpl.java:276-296):
|
||||
```java
|
||||
failureMsg.append("<br/>").append(failureNum).append("、")
|
||||
.append(excel.getName()).append(" 导入失败:").append(e.getMessage());
|
||||
// ...
|
||||
failureMsg.insert(0, "很抱歉,导入完成!成功 " + successNum + " 条,失败 " + failureNum + " 条,错误如下:");
|
||||
```
|
||||
|
||||
返回HTML格式示例:
|
||||
```html
|
||||
很抱歉,导入完成!成功 5 条,失败 10 条,错误如下:<br/>1、张三 导入失败:姓名不能为空<br/>2、李四 导入失败:柜员号不能为空<br/>...
|
||||
```
|
||||
|
||||
**现有样式** (index.vue:638-662):
|
||||
虽然已经设置了 `max-height: 60vh` 和 `overflow-y: auto`,但Element UI MessageBox的布局限制导致效果不理想。
|
||||
|
||||
---
|
||||
|
||||
## 2. 设计方案
|
||||
|
||||
### 2.1 设计目标
|
||||
|
||||
1. ✅ 弹窗最大高度不超过视口的70%
|
||||
2. ✅ 内容区域独立滚动,标题和按钮固定
|
||||
3. ✅ 适配不同屏幕尺寸(包括小屏幕)
|
||||
4. ✅ 保持良好的视觉层次和可读性
|
||||
|
||||
### 2.2 技术方案
|
||||
|
||||
**核心策略**:
|
||||
- 使用Flexbox布局确保弹窗结构稳定
|
||||
- 优化 `.import-result-dialog` 的CSS样式
|
||||
- 调整 MessageBox 内部元素布局权重
|
||||
- 添加响应式断点处理小屏幕
|
||||
|
||||
---
|
||||
|
||||
## 3. 详细设计
|
||||
|
||||
### 3.1 弹窗容器优化
|
||||
|
||||
```css
|
||||
.import-result-dialog.el-message-box {
|
||||
max-height: 70vh !important;
|
||||
max-width: 700px !important;
|
||||
width: 700px !important;
|
||||
display: flex !important;
|
||||
flex-direction: column !important;
|
||||
position: fixed !important;
|
||||
top: 50% !important;
|
||||
left: 50% !important;
|
||||
transform: translate(-50%, -50%) !important;
|
||||
}
|
||||
```
|
||||
|
||||
**设计说明**:
|
||||
- `max-height: 70vh`: 比原60vh增加10vh,提供更多展示空间
|
||||
- `max-width: 700px`: 增加宽度以提升长错误信息的可读性
|
||||
- Flexbox布局:确保三部分(header/content/btns)结构稳定
|
||||
- 固定定位+居中:防止弹窗位置偏移
|
||||
|
||||
### 3.2 内容区域滚动优化
|
||||
|
||||
```css
|
||||
.import-result-dialog .el-message-box__content {
|
||||
max-height: calc(70vh - 120px) !important;
|
||||
overflow-y: auto !important;
|
||||
overflow-x: hidden !important;
|
||||
padding: 15px 20px !important;
|
||||
flex-shrink: 1 !important;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: #c0c4cc #f5f7fa;
|
||||
}
|
||||
```
|
||||
|
||||
**设计说明**:
|
||||
- `max-height: calc(70vh - 120px)`: 减去header和btns高度,确保不超出视口
|
||||
- `flex-shrink: 1`: 内容区可收缩,为header和btns留出空间
|
||||
- 滚动条优化:thin模式,提升视觉体验
|
||||
|
||||
### 3.3 滚动条美化(WebKit浏览器)
|
||||
|
||||
```css
|
||||
.import-result-dialog .el-message-box__content::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.import-result-dialog .el-message-box__content::-webkit-scrollbar-track {
|
||||
background: #f5f7fa;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.import-result-dialog .el-message-box__content::-webkit-scrollbar-thumb {
|
||||
background: #c0c4cc;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.import-result-dialog .el-message-box__content::-webkit-scrollbar-thumb:hover {
|
||||
background: #909399;
|
||||
}
|
||||
```
|
||||
|
||||
**设计说明**:
|
||||
- 6px宽度:既清晰又不占用过多空间
|
||||
- 圆角设计:与Element UI风格一致
|
||||
- hover效果:提供交互反馈
|
||||
|
||||
### 3.4 标题和按钮固定
|
||||
|
||||
```css
|
||||
.import-result-dialog .el-message-box__header {
|
||||
flex-shrink: 0 !important;
|
||||
padding: 15px 20px 10px !important;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
.import-result-dialog .el-message-box__btns {
|
||||
flex-shrink: 0 !important;
|
||||
padding: 10px 20px 15px !important;
|
||||
border-top: 1px solid #ebeef5;
|
||||
background: #fff;
|
||||
}
|
||||
```
|
||||
|
||||
**设计说明**:
|
||||
- `flex-shrink: 0`: 禁止收缩,始终显示
|
||||
- 添加边框:增强三部分视觉分离
|
||||
- 背景色:确保按钮区域不透明
|
||||
|
||||
### 3.5 响应式设计
|
||||
|
||||
**小屏幕适配(高度 < 768px)**:
|
||||
```css
|
||||
@media screen and (max-height: 768px) {
|
||||
.import-result-dialog.el-message-box {
|
||||
max-height: 85vh !important;
|
||||
max-width: 90vw !important;
|
||||
width: 90vw !important;
|
||||
}
|
||||
|
||||
.import-result-dialog .el-message-box__content {
|
||||
max-height: calc(85vh - 100px) !important;
|
||||
padding: 10px 15px !important;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**超小屏幕适配(宽度 < 768px)**:
|
||||
```css
|
||||
@media screen and (max-width: 768px) {
|
||||
.import-result-dialog.el-message-box {
|
||||
max-width: 95vw !important;
|
||||
width: 95vw !important;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.6 错误信息格式优化
|
||||
|
||||
```css
|
||||
.import-result-dialog .el-message-box__content p {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
line-height: 1.8;
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.import-result-dialog .el-message-box__content br {
|
||||
display: block;
|
||||
margin: 4px 0;
|
||||
content: "";
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 实施计划
|
||||
|
||||
### 4.1 修改文件
|
||||
|
||||
- **文件**: `ruoyi-ui/src/views/ccdiEmployee/index.vue`
|
||||
- **位置**: 第638-662行(全局样式部分)
|
||||
|
||||
### 4.2 实施步骤
|
||||
|
||||
1. **备份现有样式**
|
||||
- 记录当前样式配置
|
||||
- 保存弹窗截图作为对比基准
|
||||
|
||||
2. **修改CSS样式**
|
||||
- 替换全局样式部分
|
||||
- 保持Vue组件作用域样式不变
|
||||
- 确保新样式全局生效(弹窗挂载在body下)
|
||||
|
||||
3. **验证不同场景**
|
||||
- 导入全部成功(简短消息)
|
||||
- 1-10条失败(中等长度)
|
||||
- 10-50条失败(较长列表)
|
||||
- 50+条失败(超长列表)
|
||||
|
||||
4. **多屏幕尺寸测试**
|
||||
- 1920x1080(桌面)
|
||||
- 1366x768(笔记本)
|
||||
- 768x1024(平板竖屏)
|
||||
- 375x667(移动端)
|
||||
|
||||
### 4.3 验收标准
|
||||
|
||||
- [ ] 弹窗始终完整显示在视口内
|
||||
- [ ] 标题、内容、按钮三部分布局清晰
|
||||
- [ ] 内容区域可独立滚动
|
||||
- [ ] 确定按钮始终可见可点击
|
||||
- [ ] 滚动条样式美观且易于操作
|
||||
- [ ] 小屏幕下不出现横向滚动条
|
||||
|
||||
---
|
||||
|
||||
## 5. 技术要点
|
||||
|
||||
### 5.1 为什么使用 `!important`?
|
||||
|
||||
Element UI 的 MessageBox 组件有较高的CSS优先级,必须使用 `!important` 覆盖默认样式。
|
||||
|
||||
### 5.2 为什么使用全局样式?
|
||||
|
||||
`$alert` 创建的弹窗挂载在 `document.body` 下,不在 Vue 组件的作用域内,因此必须使用全局样式(非 `<style scoped>`)。
|
||||
|
||||
### 5.3 Flexbox布局优势
|
||||
|
||||
- 自动分配空间:内容区自动占据剩余空间
|
||||
- 防止溢出:flex-shrink控制各部分收缩行为
|
||||
- 结构稳定:header和btns不会被挤出视口
|
||||
|
||||
---
|
||||
|
||||
## 6. 风险评估
|
||||
|
||||
| 风险 | 影响 | 缓解措施 |
|
||||
|------|------|----------|
|
||||
| Element UI版本升级导致样式失效 | 中 | 使用官方API和稳定的CSS类名 |
|
||||
| 某些浏览器不支持calc() | 低 | 提供固定高度作为fallback |
|
||||
| 极端小屏幕显示不佳 | 低 | 响应式媒体查询覆盖 |
|
||||
|
||||
---
|
||||
|
||||
## 7. 扩展考虑
|
||||
|
||||
### 7.1 未来优化方向
|
||||
|
||||
1. **错误信息分组**: 按错误类型分组展示(如:必填项错误、格式错误、重复数据等)
|
||||
2. **错误详情展开**: 默认显示摘要,点击展开具体错误信息
|
||||
3. **复制功能**: 添加"复制错误信息"按钮,方便用户修复后重新导入
|
||||
|
||||
### 7.2 其他模块应用
|
||||
|
||||
该方案可直接应用于其他使用 `$alert` 展示导入结果的模块:
|
||||
- 员工招聘信息 (ccdiStaffRecruitment)
|
||||
- 中介黑名单 (ccdiIntermediaryBlacklist)
|
||||
|
||||
---
|
||||
|
||||
## 8. 附录
|
||||
|
||||
### 8.1 完整CSS代码
|
||||
|
||||
```css
|
||||
/* 导入结果弹窗样式 - 全局样式,因为弹窗挂载在body下 */
|
||||
.import-result-dialog.el-message-box {
|
||||
max-height: 70vh !important;
|
||||
max-width: 700px !important;
|
||||
width: 700px !important;
|
||||
display: flex !important;
|
||||
flex-direction: column !important;
|
||||
position: fixed !important;
|
||||
top: 50% !important;
|
||||
left: 50% !important;
|
||||
transform: translate(-50%, -50%) !important;
|
||||
}
|
||||
|
||||
.import-result-dialog .el-message-box__header {
|
||||
flex-shrink: 0 !important;
|
||||
padding: 15px 20px 10px !important;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
.import-result-dialog .el-message-box__content {
|
||||
max-height: calc(70vh - 120px) !important;
|
||||
overflow-y: auto !important;
|
||||
overflow-x: hidden !important;
|
||||
padding: 15px 20px !important;
|
||||
flex-shrink: 1 !important;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: #c0c4cc #f5f7fa;
|
||||
}
|
||||
|
||||
.import-result-dialog .el-message-box__content::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.import-result-dialog .el-message-box__content::-webkit-scrollbar-track {
|
||||
background: #f5f7fa;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.import-result-dialog .el-message-box__content::-webkit-scrollbar-thumb {
|
||||
background: #c0c4cc;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.import-result-dialog .el-message-box__content::-webkit-scrollbar-thumb:hover {
|
||||
background: #909399;
|
||||
}
|
||||
|
||||
.import-result-dialog .el-message-box__content p {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
line-height: 1.8;
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.import-result-dialog .el-message-box__content br {
|
||||
display: block;
|
||||
margin: 4px 0;
|
||||
content: "";
|
||||
}
|
||||
|
||||
.import-result-dialog .el-message-box__btns {
|
||||
flex-shrink: 0 !important;
|
||||
padding: 10px 20px 15px !important;
|
||||
border-top: 1px solid #ebeef5;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
/* 小屏幕适配 */
|
||||
@media screen and (max-height: 768px) {
|
||||
.import-result-dialog.el-message-box {
|
||||
max-height: 85vh !important;
|
||||
max-width: 90vw !important;
|
||||
width: 90vw !important;
|
||||
}
|
||||
|
||||
.import-result-dialog .el-message-box__content {
|
||||
max-height: calc(85vh - 100px) !important;
|
||||
padding: 10px 15px !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* 超小屏幕适配 */
|
||||
@media screen and (max-width: 768px) {
|
||||
.import-result-dialog.el-message-box {
|
||||
max-width: 95vw !important;
|
||||
width: 95vw !important;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 8.2 相关文件
|
||||
|
||||
- 前端组件: `ruoyi-ui/src/views/ccdiEmployee/index.vue`
|
||||
- 后端服务: `ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/service/impl/CcdiEmployeeServiceImpl.java`
|
||||
- API文档: `doc/api/ccdiEmployee.md`
|
||||
BIN
doc/test-data/employee/employee_1770275427026.xlsx
Normal file
BIN
doc/test-data/employee/employee_1770275427026.xlsx
Normal file
Binary file not shown.
BIN
doc/test-data/employee/employee_test_data_1000 - 副本 (2).xlsx
Normal file
BIN
doc/test-data/employee/employee_test_data_1000 - 副本 (2).xlsx
Normal file
Binary file not shown.
BIN
doc/test-data/employee/employee_test_data_1000 - 副本.xlsx
Normal file
BIN
doc/test-data/employee/employee_test_data_1000 - 副本.xlsx
Normal file
Binary file not shown.
BIN
doc/test-data/employee/employee_test_data_1000.xlsx
Normal file
BIN
doc/test-data/employee/employee_test_data_1000.xlsx
Normal file
Binary file not shown.
@@ -0,0 +1,134 @@
|
||||
package com.ruoyi.ccdi.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiStaffRecruitmentAddDTO;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiStaffRecruitmentEditDTO;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiStaffRecruitmentQueryDTO;
|
||||
import com.ruoyi.ccdi.domain.excel.CcdiStaffRecruitmentExcel;
|
||||
import com.ruoyi.ccdi.domain.vo.CcdiStaffRecruitmentVO;
|
||||
import com.ruoyi.ccdi.service.ICcdiStaffRecruitmentService;
|
||||
import com.ruoyi.ccdi.utils.EasyExcelUtil;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.page.PageDomain;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.core.page.TableSupport;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 员工招聘信息Controller
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-02-05
|
||||
*/
|
||||
@Tag(name = "员工招聘信息管理")
|
||||
@RestController
|
||||
@RequestMapping("/ccdi/staffRecruitment")
|
||||
public class CcdiStaffRecruitmentController extends BaseController {
|
||||
|
||||
@Resource
|
||||
private ICcdiStaffRecruitmentService recruitmentService;
|
||||
|
||||
/**
|
||||
* 查询招聘信息列表
|
||||
*/
|
||||
@Operation(summary = "查询招聘信息列表")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:staffRecruitment:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(CcdiStaffRecruitmentQueryDTO queryDTO) {
|
||||
// 使用MyBatis Plus分页
|
||||
PageDomain pageDomain = TableSupport.buildPageRequest();
|
||||
Page<CcdiStaffRecruitmentVO> page = new Page<>(pageDomain.getPageNum(), pageDomain.getPageSize());
|
||||
Page<CcdiStaffRecruitmentVO> result = recruitmentService.selectRecruitmentPage(page, queryDTO);
|
||||
return getDataTable(result.getRecords(), result.getTotal());
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出招聘信息列表
|
||||
*/
|
||||
@Operation(summary = "导出招聘信息列表")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:staffRecruitment:export')")
|
||||
@Log(title = "员工招聘信息", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, CcdiStaffRecruitmentQueryDTO queryDTO) {
|
||||
List<CcdiStaffRecruitmentExcel> list = recruitmentService.selectRecruitmentListForExport(queryDTO);
|
||||
EasyExcelUtil.exportExcel(response, list, CcdiStaffRecruitmentExcel.class, "员工招聘信息");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取招聘信息详细信息
|
||||
*/
|
||||
@Operation(summary = "获取招聘信息详细信息")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:staffRecruitment:query')")
|
||||
@GetMapping(value = "/{recruitId}")
|
||||
public AjaxResult getInfo(@PathVariable String recruitId) {
|
||||
return success(recruitmentService.selectRecruitmentById(recruitId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增招聘信息
|
||||
*/
|
||||
@Operation(summary = "新增招聘信息")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:staffRecruitment:add')")
|
||||
@Log(title = "员工招聘信息", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@Validated @RequestBody CcdiStaffRecruitmentAddDTO addDTO) {
|
||||
return toAjax(recruitmentService.insertRecruitment(addDTO));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改招聘信息
|
||||
*/
|
||||
@Operation(summary = "修改招聘信息")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:staffRecruitment:edit')")
|
||||
@Log(title = "员工招聘信息", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@Validated @RequestBody CcdiStaffRecruitmentEditDTO editDTO) {
|
||||
return toAjax(recruitmentService.updateRecruitment(editDTO));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除招聘信息
|
||||
*/
|
||||
@Operation(summary = "删除招聘信息")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:staffRecruitment:remove')")
|
||||
@Log(title = "员工招聘信息", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{recruitIds}")
|
||||
public AjaxResult remove(@PathVariable String[] recruitIds) {
|
||||
return toAjax(recruitmentService.deleteRecruitmentByIds(recruitIds));
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载带字典下拉框的导入模板
|
||||
* 使用@DictDropdown注解自动添加下拉框
|
||||
*/
|
||||
@Operation(summary = "下载导入模板")
|
||||
@PostMapping("/importTemplate")
|
||||
public void importTemplate(HttpServletResponse response) {
|
||||
EasyExcelUtil.importTemplateWithDictDropdown(response, CcdiStaffRecruitmentExcel.class, "员工招聘信息");
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入招聘信息
|
||||
*/
|
||||
@Operation(summary = "导入招聘信息")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:staffRecruitment:import')")
|
||||
@Log(title = "员工招聘信息", businessType = BusinessType.IMPORT)
|
||||
@PostMapping("/importData")
|
||||
public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception {
|
||||
List<CcdiStaffRecruitmentExcel> list = EasyExcelUtil.importExcel(file.getInputStream(), CcdiStaffRecruitmentExcel.class);
|
||||
String message = recruitmentService.importRecruitment(list, updateSupport);
|
||||
return success(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package com.ruoyi.ccdi.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 员工招聘信息对象 ccdi_staff_recruitment
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-02-05
|
||||
*/
|
||||
@Data
|
||||
public class CcdiStaffRecruitment implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 招聘项目编号 */
|
||||
@TableId(type = IdType.INPUT)
|
||||
private String recruitId;
|
||||
|
||||
/** 招聘项目名称 */
|
||||
private String recruitName;
|
||||
|
||||
/** 职位名称 */
|
||||
private String posName;
|
||||
|
||||
/** 职位类别 */
|
||||
private String posCategory;
|
||||
|
||||
/** 职位描述 */
|
||||
private String posDesc;
|
||||
|
||||
/** 应聘人员姓名 */
|
||||
private String candName;
|
||||
|
||||
/** 应聘人员学历 */
|
||||
private String candEdu;
|
||||
|
||||
/** 应聘人员证件号码 */
|
||||
private String candId;
|
||||
|
||||
/** 应聘人员毕业院校 */
|
||||
private String candSchool;
|
||||
|
||||
/** 应聘人员专业 */
|
||||
private String candMajor;
|
||||
|
||||
/** 应聘人员毕业年月 */
|
||||
private String candGrad;
|
||||
|
||||
/** 录用情况:录用、未录用、放弃 */
|
||||
private String admitStatus;
|
||||
|
||||
/** 面试官1姓名 */
|
||||
private String interviewerName1;
|
||||
|
||||
/** 面试官1工号 */
|
||||
private String interviewerId1;
|
||||
|
||||
/** 面试官2姓名 */
|
||||
private String interviewerName2;
|
||||
|
||||
/** 面试官2工号 */
|
||||
private String interviewerId2;
|
||||
|
||||
/** 记录创建人 */
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private String createdBy;
|
||||
|
||||
/** 记录更新人 */
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private String updatedBy;
|
||||
|
||||
/** 创建时间 */
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Date createTime;
|
||||
|
||||
/** 更新时间 */
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private Date updateTime;
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package com.ruoyi.ccdi.domain.dto;
|
||||
|
||||
import com.ruoyi.ccdi.annotation.EnumValid;
|
||||
import com.ruoyi.ccdi.enums.AdmitStatus;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 员工招聘信息新增DTO
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-02-05
|
||||
*/
|
||||
@Data
|
||||
public class CcdiStaffRecruitmentAddDTO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 招聘项目编号 */
|
||||
@NotBlank(message = "招聘项目编号不能为空")
|
||||
@Size(max = 32, message = "招聘项目编号长度不能超过32个字符")
|
||||
private String recruitId;
|
||||
|
||||
/** 招聘项目名称 */
|
||||
@NotBlank(message = "招聘项目名称不能为空")
|
||||
@Size(max = 100, message = "招聘项目名称长度不能超过100个字符")
|
||||
private String recruitName;
|
||||
|
||||
/** 职位名称 */
|
||||
@NotBlank(message = "职位名称不能为空")
|
||||
@Size(max = 100, message = "职位名称长度不能超过100个字符")
|
||||
private String posName;
|
||||
|
||||
/** 职位类别 */
|
||||
@NotBlank(message = "职位类别不能为空")
|
||||
@Size(max = 50, message = "职位类别长度不能超过50个字符")
|
||||
private String posCategory;
|
||||
|
||||
/** 职位描述 */
|
||||
@NotBlank(message = "职位描述不能为空")
|
||||
private String posDesc;
|
||||
|
||||
/** 应聘人员姓名 */
|
||||
@NotBlank(message = "应聘人员姓名不能为空")
|
||||
@Size(max = 20, message = "应聘人员姓名长度不能超过20个字符")
|
||||
private String candName;
|
||||
|
||||
/** 应聘人员学历 */
|
||||
@NotBlank(message = "应聘人员学历不能为空")
|
||||
@Size(max = 20, message = "应聘人员学历长度不能超过20个字符")
|
||||
private String candEdu;
|
||||
|
||||
/** 应聘人员证件号码 */
|
||||
@NotBlank(message = "证件号码不能为空")
|
||||
@Pattern(regexp = "^[1-9]\\d{5}(18|19|20)\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])\\d{3}[0-9Xx]$", message = "证件号码格式不正确")
|
||||
private String candId;
|
||||
|
||||
/** 应聘人员毕业院校 */
|
||||
@NotBlank(message = "应聘人员毕业院校不能为空")
|
||||
@Size(max = 50, message = "应聘人员毕业院校长度不能超过50个字符")
|
||||
private String candSchool;
|
||||
|
||||
/** 应聘人员专业 */
|
||||
@NotBlank(message = "应聘人员专业不能为空")
|
||||
@Size(max = 30, message = "应聘人员专业长度不能超过30个字符")
|
||||
private String candMajor;
|
||||
|
||||
/** 应聘人员毕业年月 */
|
||||
@NotBlank(message = "应聘人员毕业年月不能为空")
|
||||
@Pattern(regexp = "^((19|20)\\d{2})(0[1-9]|1[0-2])$", message = "毕业年月格式不正确,应为YYYYMM")
|
||||
private String candGrad;
|
||||
|
||||
/** 录用情况:录用、未录用、放弃 */
|
||||
@NotBlank(message = "录用情况不能为空")
|
||||
@EnumValid(enumClass = AdmitStatus.class, message = "录用情况状态值不合法")
|
||||
private String admitStatus;
|
||||
|
||||
/** 面试官1姓名 */
|
||||
@Size(max = 20, message = "面试官1姓名长度不能超过20个字符")
|
||||
private String interviewerName1;
|
||||
|
||||
/** 面试官1工号 */
|
||||
@Size(max = 10, message = "面试官1工号长度不能超过10个字符")
|
||||
private String interviewerId1;
|
||||
|
||||
/** 面试官2姓名 */
|
||||
@Size(max = 20, message = "面试官2姓名长度不能超过20个字符")
|
||||
private String interviewerName2;
|
||||
|
||||
/** 面试官2工号 */
|
||||
@Size(max = 10, message = "面试官2工号长度不能超过10个字符")
|
||||
private String interviewerId2;
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package com.ruoyi.ccdi.domain.dto;
|
||||
|
||||
import com.ruoyi.ccdi.annotation.EnumValid;
|
||||
import com.ruoyi.ccdi.enums.AdmitStatus;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 员工招聘信息编辑DTO
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-02-05
|
||||
*/
|
||||
@Data
|
||||
public class CcdiStaffRecruitmentEditDTO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 招聘项目编号 */
|
||||
@NotNull(message = "招聘项目编号不能为空")
|
||||
private String recruitId;
|
||||
|
||||
/** 招聘项目名称 */
|
||||
@Size(max = 100, message = "招聘项目名称长度不能超过100个字符")
|
||||
private String recruitName;
|
||||
|
||||
/** 职位名称 */
|
||||
@Size(max = 100, message = "职位名称长度不能超过100个字符")
|
||||
private String posName;
|
||||
|
||||
/** 职位类别 */
|
||||
@Size(max = 50, message = "职位类别长度不能超过50个字符")
|
||||
private String posCategory;
|
||||
|
||||
/** 职位描述 */
|
||||
private String posDesc;
|
||||
|
||||
/** 应聘人员姓名 */
|
||||
@Size(max = 20, message = "应聘人员姓名长度不能超过20个字符")
|
||||
private String candName;
|
||||
|
||||
/** 应聘人员学历 */
|
||||
@Size(max = 20, message = "应聘人员学历长度不能超过20个字符")
|
||||
private String candEdu;
|
||||
|
||||
/** 应聘人员证件号码 */
|
||||
@NotBlank(message = "证件号码不能为空")
|
||||
@Pattern(regexp = "^[1-9]\\d{5}(18|19|20)\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])\\d{3}[0-9Xx]$", message = "证件号码格式不正确")
|
||||
private String candId;
|
||||
|
||||
/** 应聘人员毕业院校 */
|
||||
@Size(max = 50, message = "应聘人员毕业院校长度不能超过50个字符")
|
||||
private String candSchool;
|
||||
|
||||
/** 应聘人员专业 */
|
||||
@Size(max = 30, message = "应聘人员专业长度不能超过30个字符")
|
||||
private String candMajor;
|
||||
|
||||
/** 应聘人员毕业年月 */
|
||||
@Pattern(regexp = "^((19|20)\\d{2})(0[1-9]|1[0-2])$", message = "毕业年月格式不正确,应为YYYYMM")
|
||||
private String candGrad;
|
||||
|
||||
/** 录用情况:录用、未录用、放弃 */
|
||||
@EnumValid(enumClass = AdmitStatus.class, message = "录用情况状态值不合法")
|
||||
private String admitStatus;
|
||||
|
||||
/** 面试官1姓名 */
|
||||
@Size(max = 20, message = "面试官1姓名长度不能超过20个字符")
|
||||
private String interviewerName1;
|
||||
|
||||
/** 面试官1工号 */
|
||||
@Size(max = 10, message = "面试官1工号长度不能超过10个字符")
|
||||
private String interviewerId1;
|
||||
|
||||
/** 面试官2姓名 */
|
||||
@Size(max = 20, message = "面试官2姓名长度不能超过20个字符")
|
||||
private String interviewerName2;
|
||||
|
||||
/** 面试官2工号 */
|
||||
@Size(max = 10, message = "面试官2工号长度不能超过10个字符")
|
||||
private String interviewerId2;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.ruoyi.ccdi.domain.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 员工招聘信息查询DTO
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-02-05
|
||||
*/
|
||||
@Data
|
||||
public class CcdiStaffRecruitmentQueryDTO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 招聘项目名称(模糊查询) */
|
||||
private String recruitName;
|
||||
|
||||
/** 职位名称(模糊查询) */
|
||||
private String posName;
|
||||
|
||||
/** 候选人姓名(模糊查询) */
|
||||
private String candName;
|
||||
|
||||
/** 证件号码(精确查询) */
|
||||
private String candId;
|
||||
|
||||
/** 录用状态(精确查询) */
|
||||
private String admitStatus;
|
||||
|
||||
/** 面试官姓名(模糊查询,查询面试官1或2) */
|
||||
private String interviewerName;
|
||||
|
||||
/** 面试官工号(精确查询,查询面试官1或2) */
|
||||
private String interviewerId;
|
||||
|
||||
/** 分页参数 */
|
||||
private Integer pageNum = 1;
|
||||
|
||||
/** 分页参数 */
|
||||
private Integer pageSize = 10;
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package com.ruoyi.ccdi.domain.excel;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import com.alibaba.excel.annotation.write.style.ColumnWidth;
|
||||
import com.ruoyi.common.annotation.DictDropdown;
|
||||
import com.ruoyi.common.annotation.Required;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 员工招聘信息Excel导入导出对象
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-02-05
|
||||
*/
|
||||
@Data
|
||||
public class CcdiStaffRecruitmentExcel implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 招聘项目编号 */
|
||||
@ExcelProperty(value = "招聘项目编号", index = 0)
|
||||
@ColumnWidth(20)
|
||||
@Required
|
||||
private String recruitId;
|
||||
|
||||
/** 招聘项目名称 */
|
||||
@ExcelProperty(value = "招聘项目名称", index = 1)
|
||||
@ColumnWidth(20)
|
||||
@Required
|
||||
private String recruitName;
|
||||
|
||||
/** 职位名称 */
|
||||
@ExcelProperty(value = "职位名称", index = 2)
|
||||
@ColumnWidth(20)
|
||||
@Required
|
||||
private String posName;
|
||||
|
||||
/** 职位类别 */
|
||||
@ExcelProperty(value = "职位类别", index = 3)
|
||||
@ColumnWidth(15)
|
||||
@Required
|
||||
private String posCategory;
|
||||
|
||||
/** 职位描述 */
|
||||
@ExcelProperty(value = "职位描述", index = 4)
|
||||
@ColumnWidth(30)
|
||||
@Required
|
||||
private String posDesc;
|
||||
|
||||
/** 应聘人员姓名 */
|
||||
@ExcelProperty(value = "应聘人员姓名", index = 5)
|
||||
@ColumnWidth(15)
|
||||
@Required
|
||||
private String candName;
|
||||
|
||||
/** 应聘人员学历 */
|
||||
@ExcelProperty(value = "应聘人员学历", index = 6)
|
||||
@ColumnWidth(15)
|
||||
@Required
|
||||
private String candEdu;
|
||||
|
||||
/** 应聘人员证件号码 */
|
||||
@ExcelProperty(value = "应聘人员证件号码", index = 7)
|
||||
@ColumnWidth(20)
|
||||
@Required
|
||||
private String candId;
|
||||
|
||||
/** 应聘人员毕业院校 */
|
||||
@ExcelProperty(value = "应聘人员毕业院校", index = 8)
|
||||
@ColumnWidth(20)
|
||||
@Required
|
||||
private String candSchool;
|
||||
|
||||
/** 应聘人员专业 */
|
||||
@ExcelProperty(value = "应聘人员专业", index = 9)
|
||||
@ColumnWidth(15)
|
||||
@Required
|
||||
private String candMajor;
|
||||
|
||||
/** 应聘人员毕业年月 */
|
||||
@ExcelProperty(value = "应聘人员毕业年月", index = 10)
|
||||
@ColumnWidth(15)
|
||||
@Required
|
||||
private String candGrad;
|
||||
|
||||
/** 录用情况 */
|
||||
@ExcelProperty(value = "录用情况", index = 11)
|
||||
@ColumnWidth(10)
|
||||
@DictDropdown(dictType = "ccdi_admit_status")
|
||||
@Required
|
||||
private String admitStatus;
|
||||
|
||||
/** 面试官1姓名 */
|
||||
@ExcelProperty(value = "面试官1姓名", index = 12)
|
||||
@ColumnWidth(15)
|
||||
private String interviewerName1;
|
||||
|
||||
/** 面试官1工号 */
|
||||
@ExcelProperty(value = "面试官1工号", index = 13)
|
||||
@ColumnWidth(15)
|
||||
private String interviewerId1;
|
||||
|
||||
/** 面试官2姓名 */
|
||||
@ExcelProperty(value = "面试官2姓名", index = 14)
|
||||
@ColumnWidth(15)
|
||||
private String interviewerName2;
|
||||
|
||||
/** 面试官2工号 */
|
||||
@ExcelProperty(value = "面试官2工号", index = 15)
|
||||
@ColumnWidth(15)
|
||||
private String interviewerId2;
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package com.ruoyi.ccdi.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 员工招聘信息VO
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-02-05
|
||||
*/
|
||||
@Data
|
||||
public class CcdiStaffRecruitmentVO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 招聘项目编号 */
|
||||
private String recruitId;
|
||||
|
||||
/** 招聘项目名称 */
|
||||
private String recruitName;
|
||||
|
||||
/** 职位名称 */
|
||||
private String posName;
|
||||
|
||||
/** 职位类别 */
|
||||
private String posCategory;
|
||||
|
||||
/** 职位描述 */
|
||||
private String posDesc;
|
||||
|
||||
/** 应聘人员姓名 */
|
||||
private String candName;
|
||||
|
||||
/** 应聘人员学历 */
|
||||
private String candEdu;
|
||||
|
||||
/** 应聘人员证件号码 */
|
||||
private String candId;
|
||||
|
||||
/** 应聘人员毕业院校 */
|
||||
private String candSchool;
|
||||
|
||||
/** 应聘人员专业 */
|
||||
private String candMajor;
|
||||
|
||||
/** 应聘人员毕业年月 */
|
||||
private String candGrad;
|
||||
|
||||
/** 录用情况:录用、未录用、放弃 */
|
||||
private String admitStatus;
|
||||
|
||||
/** 录用情况描述 */
|
||||
private String admitStatusDesc;
|
||||
|
||||
/** 面试官1姓名 */
|
||||
private String interviewerName1;
|
||||
|
||||
/** 面试官1工号 */
|
||||
private String interviewerId1;
|
||||
|
||||
/** 面试官2姓名 */
|
||||
private String interviewerName2;
|
||||
|
||||
/** 面试官2工号 */
|
||||
private String interviewerId2;
|
||||
|
||||
/** 记录创建人 */
|
||||
private String createdBy;
|
||||
|
||||
/** 创建时间 */
|
||||
private Date createTime;
|
||||
|
||||
/** 记录更新人 */
|
||||
private String updatedBy;
|
||||
|
||||
/** 更新时间 */
|
||||
private Date updateTime;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.ruoyi.ccdi.enums;
|
||||
|
||||
|
||||
/**
|
||||
* 录用状态枚举
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public enum AdmitStatus {
|
||||
|
||||
/** 录用 */
|
||||
ADMITTED("录用", "已录用该候选人"),
|
||||
|
||||
/** 未录用 */
|
||||
NOT_ADMITTED("未录用", "未录用该候选人"),
|
||||
|
||||
/** 放弃 */
|
||||
WITHDRAWN("放弃", "候选人放弃");
|
||||
|
||||
private final String code;
|
||||
private final String desc;
|
||||
|
||||
AdmitStatus(String code, String desc) {
|
||||
this.code = code;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getDesc() {
|
||||
return desc;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据编码获取描述
|
||||
*/
|
||||
public static String getDescByCode(String code) {
|
||||
for (AdmitStatus status : values()) {
|
||||
if (status.getCode().equals(code)) {
|
||||
return status.getDesc();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
package com.ruoyi.ccdi.handler;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import com.alibaba.excel.write.handler.SheetWriteHandler;
|
||||
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
|
||||
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
|
||||
import com.ruoyi.common.annotation.Required;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.poi.ss.usermodel.*;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* EasyExcel必填字段标注处理器
|
||||
* 在Excel模板生成时,为标注了@Required注解的字段表头添加红色星号(*)标记
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Slf4j
|
||||
public class RequiredFieldWriteHandler implements SheetWriteHandler {
|
||||
|
||||
/**
|
||||
* 实体类Class对象
|
||||
*/
|
||||
private final Class<?> modelClass;
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
*
|
||||
* @param modelClass 实体类Class对象
|
||||
*/
|
||||
public RequiredFieldWriteHandler(Class<?> modelClass) {
|
||||
this.modelClass = modelClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
|
||||
// 获取工作表
|
||||
Sheet sheet = writeSheetHolder.getSheet();
|
||||
|
||||
// 获取表头行(第1行,索引为0)
|
||||
Row headerRow = sheet.getRow(0);
|
||||
if (headerRow == null) {
|
||||
log.warn("表头行不存在,跳过必填字段标注");
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建红色字体样式
|
||||
Workbook workbook = writeWorkbookHolder.getWorkbook();
|
||||
CellStyle redStyle = createRedFontStyle(workbook);
|
||||
|
||||
// 解析实体类中的必填字段
|
||||
Set<Integer> requiredColumns = parseRequiredFields();
|
||||
|
||||
// 为必填字段的表头添加红色星号
|
||||
for (Integer columnIndex : requiredColumns) {
|
||||
Cell cell = headerRow.getCell(columnIndex);
|
||||
if (cell != null) {
|
||||
String originalValue = cell.getStringCellValue();
|
||||
// 添加红色星号
|
||||
cell.setCellValue(originalValue + "*");
|
||||
// 应用红色样式到星号
|
||||
cell.setCellStyle(redStyle);
|
||||
log.info("为列[{}]的表头添加必填标记(*)", columnIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建红色字体样式
|
||||
*
|
||||
* @param workbook 工作簿
|
||||
* @return 单元格样式
|
||||
*/
|
||||
private CellStyle createRedFontStyle(Workbook workbook) {
|
||||
CellStyle style = workbook.createCellStyle();
|
||||
|
||||
// 设置字体为红色
|
||||
Font font = workbook.createFont();
|
||||
font.setColor(IndexedColors.RED.getIndex());
|
||||
font.setBold(true);
|
||||
style.setFont(font);
|
||||
|
||||
// 设置对齐方式
|
||||
style.setAlignment(HorizontalAlignment.CENTER);
|
||||
style.setVerticalAlignment(VerticalAlignment.CENTER);
|
||||
|
||||
// 设置边框
|
||||
style.setBorderTop(BorderStyle.THIN);
|
||||
style.setBorderBottom(BorderStyle.THIN);
|
||||
style.setBorderLeft(BorderStyle.THIN);
|
||||
style.setBorderRight(BorderStyle.THIN);
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析实体类中的必填字段
|
||||
*
|
||||
* @return 必填字段的列索引集合
|
||||
*/
|
||||
private Set<Integer> parseRequiredFields() {
|
||||
Set<Integer> result = new HashSet<>();
|
||||
|
||||
// 获取所有字段(包括父类的)
|
||||
List<Field> fields = getAllFields(modelClass);
|
||||
|
||||
for (Field field : fields) {
|
||||
// 检查是否有@Required注解
|
||||
Required required = field.getAnnotation(Required.class);
|
||||
if (required == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 获取列索引
|
||||
Integer columnIndex = getColumnIndex(field);
|
||||
if (columnIndex == null) {
|
||||
log.warn("字段[{}]没有指定@ExcelProperty的index,跳过必填标记", field.getName());
|
||||
continue;
|
||||
}
|
||||
|
||||
result.add(columnIndex);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取类的所有字段(包括父类的)
|
||||
*
|
||||
* @param clazz 类对象
|
||||
* @return 字段列表
|
||||
*/
|
||||
private List<Field> getAllFields(Class<?> clazz) {
|
||||
List<Field> fields = new ArrayList<>();
|
||||
while (clazz != null && clazz != Object.class) {
|
||||
fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取字段对应的列索引
|
||||
*
|
||||
* @param field 字段对象
|
||||
* @return 列索引
|
||||
*/
|
||||
private Integer getColumnIndex(Field field) {
|
||||
ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);
|
||||
if (excelProperty != null && excelProperty.index() >= 0) {
|
||||
return excelProperty.index();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.ruoyi.ccdi.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.ccdi.domain.CcdiStaffRecruitment;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiStaffRecruitmentQueryDTO;
|
||||
import com.ruoyi.ccdi.domain.vo.CcdiStaffRecruitmentVO;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 员工招聘信息 数据层
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-02-05
|
||||
*/
|
||||
public interface CcdiStaffRecruitmentMapper extends BaseMapper<CcdiStaffRecruitment> {
|
||||
|
||||
/**
|
||||
* 分页查询招聘信息列表
|
||||
*
|
||||
* @param page 分页对象
|
||||
* @param queryDTO 查询条件
|
||||
* @return 招聘信息VO分页结果
|
||||
*/
|
||||
Page<CcdiStaffRecruitmentVO> selectRecruitmentPage(@Param("page") Page<CcdiStaffRecruitmentVO> page,
|
||||
@Param("query") CcdiStaffRecruitmentQueryDTO queryDTO);
|
||||
|
||||
/**
|
||||
* 查询招聘信息详情
|
||||
*
|
||||
* @param recruitId 招聘项目编号
|
||||
* @return 招聘信息VO
|
||||
*/
|
||||
CcdiStaffRecruitmentVO selectRecruitmentById(@Param("recruitId") String recruitId);
|
||||
|
||||
/**
|
||||
* 批量插入招聘信息数据
|
||||
*
|
||||
* @param list 招聘信息列表
|
||||
* @return 插入行数
|
||||
*/
|
||||
int insertBatch(@Param("list") List<CcdiStaffRecruitment> list);
|
||||
|
||||
/**
|
||||
* 批量更新招聘信息数据
|
||||
*
|
||||
* @param list 招聘信息列表
|
||||
* @return 更新行数
|
||||
*/
|
||||
int updateBatch(@Param("list") List<CcdiStaffRecruitment> list);
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.ruoyi.ccdi.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiStaffRecruitmentAddDTO;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiStaffRecruitmentEditDTO;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiStaffRecruitmentQueryDTO;
|
||||
import com.ruoyi.ccdi.domain.excel.CcdiStaffRecruitmentExcel;
|
||||
import com.ruoyi.ccdi.domain.vo.CcdiStaffRecruitmentVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 员工招聘信息 服务层
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-02-05
|
||||
*/
|
||||
public interface ICcdiStaffRecruitmentService {
|
||||
|
||||
/**
|
||||
* 查询招聘信息列表
|
||||
*
|
||||
* @param queryDTO 查询条件
|
||||
* @return 招聘信息VO集合
|
||||
*/
|
||||
List<CcdiStaffRecruitmentVO> selectRecruitmentList(CcdiStaffRecruitmentQueryDTO queryDTO);
|
||||
|
||||
/**
|
||||
* 分页查询招聘信息列表
|
||||
*
|
||||
* @param page 分页对象
|
||||
* @param queryDTO 查询条件
|
||||
* @return 招聘信息VO分页结果
|
||||
*/
|
||||
Page<CcdiStaffRecruitmentVO> selectRecruitmentPage(Page<CcdiStaffRecruitmentVO> page, CcdiStaffRecruitmentQueryDTO queryDTO);
|
||||
|
||||
/**
|
||||
* 查询招聘信息列表(用于导出)
|
||||
*
|
||||
* @param queryDTO 查询条件
|
||||
* @return 招聘信息Excel实体集合
|
||||
*/
|
||||
List<CcdiStaffRecruitmentExcel> selectRecruitmentListForExport(CcdiStaffRecruitmentQueryDTO queryDTO);
|
||||
|
||||
/**
|
||||
* 查询招聘信息详情
|
||||
*
|
||||
* @param recruitId 招聘项目编号
|
||||
* @return 招聘信息VO
|
||||
*/
|
||||
CcdiStaffRecruitmentVO selectRecruitmentById(String recruitId);
|
||||
|
||||
/**
|
||||
* 新增招聘信息
|
||||
*
|
||||
* @param addDTO 新增DTO
|
||||
* @return 结果
|
||||
*/
|
||||
int insertRecruitment(CcdiStaffRecruitmentAddDTO addDTO);
|
||||
|
||||
/**
|
||||
* 修改招聘信息
|
||||
*
|
||||
* @param editDTO 编辑DTO
|
||||
* @return 结果
|
||||
*/
|
||||
int updateRecruitment(CcdiStaffRecruitmentEditDTO editDTO);
|
||||
|
||||
/**
|
||||
* 批量删除招聘信息
|
||||
*
|
||||
* @param recruitIds 需要删除的招聘项目编号
|
||||
* @return 结果
|
||||
*/
|
||||
int deleteRecruitmentByIds(String[] recruitIds);
|
||||
|
||||
/**
|
||||
* 导入招聘信息数据
|
||||
*
|
||||
* @param excelList Excel实体列表
|
||||
* @param isUpdateSupport 是否更新支持
|
||||
* @return 结果
|
||||
*/
|
||||
String importRecruitment(List<CcdiStaffRecruitmentExcel> excelList, Boolean isUpdateSupport);
|
||||
}
|
||||
@@ -0,0 +1,322 @@
|
||||
package com.ruoyi.ccdi.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.ccdi.domain.CcdiStaffRecruitment;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiStaffRecruitmentAddDTO;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiStaffRecruitmentEditDTO;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiStaffRecruitmentQueryDTO;
|
||||
import com.ruoyi.ccdi.domain.excel.CcdiStaffRecruitmentExcel;
|
||||
import com.ruoyi.ccdi.domain.vo.CcdiStaffRecruitmentVO;
|
||||
import com.ruoyi.ccdi.enums.AdmitStatus;
|
||||
import com.ruoyi.ccdi.mapper.CcdiStaffRecruitmentMapper;
|
||||
import com.ruoyi.ccdi.service.ICcdiStaffRecruitmentService;
|
||||
import com.ruoyi.common.utils.IdCardUtil;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 员工招聘信息 服务层处理
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-02-05
|
||||
*/
|
||||
@Service
|
||||
public class CcdiStaffRecruitmentServiceImpl implements ICcdiStaffRecruitmentService {
|
||||
|
||||
@Resource
|
||||
private CcdiStaffRecruitmentMapper recruitmentMapper;
|
||||
|
||||
/**
|
||||
* 查询招聘信息列表
|
||||
*
|
||||
* @param queryDTO 查询条件
|
||||
* @return 招聘信息VO集合
|
||||
*/
|
||||
@Override
|
||||
public List<CcdiStaffRecruitmentVO> selectRecruitmentList(CcdiStaffRecruitmentQueryDTO queryDTO) {
|
||||
Page<CcdiStaffRecruitmentVO> page = new Page<>(1, Integer.MAX_VALUE);
|
||||
Page<CcdiStaffRecruitmentVO> resultPage = recruitmentMapper.selectRecruitmentPage(page, queryDTO);
|
||||
return resultPage.getRecords();
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询招聘信息列表
|
||||
*
|
||||
* @param page 分页对象
|
||||
* @param queryDTO 查询条件
|
||||
* @return 招聘信息VO分页结果
|
||||
*/
|
||||
@Override
|
||||
public Page<CcdiStaffRecruitmentVO> selectRecruitmentPage(Page<CcdiStaffRecruitmentVO> page, CcdiStaffRecruitmentQueryDTO queryDTO) {
|
||||
Page<CcdiStaffRecruitmentVO> resultPage = recruitmentMapper.selectRecruitmentPage(page, queryDTO);
|
||||
|
||||
// 设置录用状态描述
|
||||
resultPage.getRecords().forEach(vo ->
|
||||
vo.setAdmitStatusDesc(AdmitStatus.getDescByCode(vo.getAdmitStatus()))
|
||||
);
|
||||
|
||||
return resultPage;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询招聘信息列表(用于导出)
|
||||
*
|
||||
* @param queryDTO 查询条件
|
||||
* @return 招聘信息Excel实体集合
|
||||
*/
|
||||
@Override
|
||||
public List<CcdiStaffRecruitmentExcel> selectRecruitmentListForExport(CcdiStaffRecruitmentQueryDTO queryDTO) {
|
||||
Page<CcdiStaffRecruitmentVO> page = new Page<>(1, Integer.MAX_VALUE);
|
||||
Page<CcdiStaffRecruitmentVO> resultPage = recruitmentMapper.selectRecruitmentPage(page, queryDTO);
|
||||
|
||||
return resultPage.getRecords().stream().map(vo -> {
|
||||
CcdiStaffRecruitmentExcel excel = new CcdiStaffRecruitmentExcel();
|
||||
BeanUtils.copyProperties(vo, excel);
|
||||
return excel;
|
||||
}).toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询招聘信息详情
|
||||
*
|
||||
* @param recruitId 招聘项目编号
|
||||
* @return 招聘信息VO
|
||||
*/
|
||||
@Override
|
||||
public CcdiStaffRecruitmentVO selectRecruitmentById(String recruitId) {
|
||||
CcdiStaffRecruitmentVO vo = recruitmentMapper.selectRecruitmentById(recruitId);
|
||||
if (vo != null) {
|
||||
vo.setAdmitStatusDesc(AdmitStatus.getDescByCode(vo.getAdmitStatus()));
|
||||
}
|
||||
return vo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增招聘信息
|
||||
*
|
||||
* @param addDTO 新增DTO
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public int insertRecruitment(CcdiStaffRecruitmentAddDTO addDTO) {
|
||||
// 检查招聘项目编号唯一性
|
||||
if (recruitmentMapper.selectById(addDTO.getRecruitId()) != null) {
|
||||
throw new RuntimeException("该招聘项目编号已存在");
|
||||
}
|
||||
|
||||
CcdiStaffRecruitment recruitment = new CcdiStaffRecruitment();
|
||||
BeanUtils.copyProperties(addDTO, recruitment);
|
||||
int result = recruitmentMapper.insert(recruitment);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改招聘信息
|
||||
*
|
||||
* @param editDTO 编辑DTO
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public int updateRecruitment(CcdiStaffRecruitmentEditDTO editDTO) {
|
||||
CcdiStaffRecruitment recruitment = new CcdiStaffRecruitment();
|
||||
BeanUtils.copyProperties(editDTO, recruitment);
|
||||
int result = recruitmentMapper.updateById(recruitment);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除招聘信息
|
||||
*
|
||||
* @param recruitIds 需要删除的招聘项目编号
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public int deleteRecruitmentByIds(String[] recruitIds) {
|
||||
return recruitmentMapper.deleteBatchIds(List.of(recruitIds));
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入招聘信息数据(批量优化版本)
|
||||
*
|
||||
* @param excelList Excel实体列表
|
||||
* @param isUpdateSupport 是否更新支持,true-存在则更新,false-存在则跳过
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public String importRecruitment(List<CcdiStaffRecruitmentExcel> excelList, Boolean isUpdateSupport) {
|
||||
if (StringUtils.isNull(excelList) || excelList.isEmpty()) {
|
||||
return "至少需要一条数据";
|
||||
}
|
||||
|
||||
int successNum = 0;
|
||||
int failureNum = 0;
|
||||
StringBuilder successMsg = new StringBuilder();
|
||||
StringBuilder failureMsg = new StringBuilder();
|
||||
|
||||
// 第一阶段:数据验证和分类
|
||||
List<CcdiStaffRecruitment> toInsertList = new ArrayList<>();
|
||||
List<CcdiStaffRecruitment> toUpdateList = new ArrayList<>();
|
||||
|
||||
// 批量收集所有招聘项目编号
|
||||
List<String> recruitIds = new ArrayList<>();
|
||||
|
||||
for (CcdiStaffRecruitmentExcel excel : excelList) {
|
||||
if (StringUtils.isNotEmpty(excel.getRecruitId())) {
|
||||
recruitIds.add(excel.getRecruitId());
|
||||
}
|
||||
}
|
||||
|
||||
// 批量查询已存在的招聘项目编号
|
||||
Map<String, CcdiStaffRecruitment> existingRecruitmentMap = new HashMap<>();
|
||||
if (!recruitIds.isEmpty()) {
|
||||
LambdaQueryWrapper<CcdiStaffRecruitment> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.in(CcdiStaffRecruitment::getRecruitId, recruitIds);
|
||||
List<CcdiStaffRecruitment> existingRecruitments = recruitmentMapper.selectList(wrapper);
|
||||
existingRecruitmentMap = existingRecruitments.stream()
|
||||
.collect(Collectors.toMap(CcdiStaffRecruitment::getRecruitId, r -> r));
|
||||
}
|
||||
|
||||
// 第二阶段:处理每条数据
|
||||
for (int i = 0; i < excelList.size(); i++) {
|
||||
CcdiStaffRecruitmentExcel excel = excelList.get(i);
|
||||
try {
|
||||
// 验证必填字段和数据格式
|
||||
validateRecruitmentDataBasic(excel);
|
||||
|
||||
CcdiStaffRecruitment recruitment = new CcdiStaffRecruitment();
|
||||
BeanUtils.copyProperties(excel, recruitment);
|
||||
|
||||
// 检查是否已存在
|
||||
CcdiStaffRecruitment existingRecruitment = existingRecruitmentMap.get(excel.getRecruitId());
|
||||
|
||||
// 判断数据状态和操作类型
|
||||
if (existingRecruitment != null) {
|
||||
// 招聘项目编号已存在
|
||||
if (isUpdateSupport) {
|
||||
// 支持更新,添加到更新列表
|
||||
recruitment.setUpdatedBy("导入");
|
||||
toUpdateList.add(recruitment);
|
||||
} else {
|
||||
// 不支持更新,跳过或报错
|
||||
throw new RuntimeException("该招聘项目编号已存在");
|
||||
}
|
||||
} else {
|
||||
// 招聘项目编号不存在,新增数据
|
||||
recruitment.setCreatedBy("导入");
|
||||
toInsertList.add(recruitment);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
failureNum++;
|
||||
failureMsg.append("<br/>").append(failureNum).append("、招聘项目编号 ").append(excel.getRecruitId())
|
||||
.append(" 导入失败:").append(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 第三阶段:批量执行数据库操作
|
||||
if (!toInsertList.isEmpty()) {
|
||||
// 使用自定义批量插入方法
|
||||
recruitmentMapper.insertBatch(toInsertList);
|
||||
successNum += toInsertList.size();
|
||||
}
|
||||
|
||||
if (!toUpdateList.isEmpty()) {
|
||||
// 使用自定义批量更新方法
|
||||
recruitmentMapper.updateBatch(toUpdateList);
|
||||
successNum += toUpdateList.size();
|
||||
}
|
||||
|
||||
// 第四阶段:返回结果(只返回错误信息)
|
||||
if (failureNum > 0) {
|
||||
failureMsg.insert(0, "很抱歉,导入完成!成功 " + successNum + " 条,失败 " + failureNum + " 条,错误如下:");
|
||||
throw new RuntimeException(failureMsg.toString());
|
||||
} else {
|
||||
successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据类型:");
|
||||
if (!toInsertList.isEmpty()) {
|
||||
successMsg.append("新增 ").append(toInsertList.size()).append(" 条");
|
||||
}
|
||||
if (!toUpdateList.isEmpty()) {
|
||||
if (!toInsertList.isEmpty()) {
|
||||
successMsg.append(",");
|
||||
}
|
||||
successMsg.append("更新 ").append(toUpdateList.size()).append(" 条");
|
||||
}
|
||||
return successMsg.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证招聘信息数据(仅基本字段验证,不进行数据库查询)
|
||||
*/
|
||||
private void validateRecruitmentDataBasic(CcdiStaffRecruitmentExcel excel) {
|
||||
// 验证必填字段
|
||||
if (StringUtils.isEmpty(excel.getRecruitId())) {
|
||||
throw new RuntimeException("招聘项目编号不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(excel.getRecruitName())) {
|
||||
throw new RuntimeException("招聘项目名称不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(excel.getPosName())) {
|
||||
throw new RuntimeException("职位名称不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(excel.getPosCategory())) {
|
||||
throw new RuntimeException("职位类别不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(excel.getPosDesc())) {
|
||||
throw new RuntimeException("职位描述不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(excel.getCandName())) {
|
||||
throw new RuntimeException("应聘人员姓名不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(excel.getCandEdu())) {
|
||||
throw new RuntimeException("应聘人员学历不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(excel.getCandId())) {
|
||||
throw new RuntimeException("证件号码不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(excel.getCandSchool())) {
|
||||
throw new RuntimeException("应聘人员毕业院校不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(excel.getCandMajor())) {
|
||||
throw new RuntimeException("应聘人员专业不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(excel.getCandGrad())) {
|
||||
throw new RuntimeException("应聘人员毕业年月不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(excel.getAdmitStatus())) {
|
||||
throw new RuntimeException("录用情况不能为空");
|
||||
}
|
||||
|
||||
// 验证证件号码格式
|
||||
String idCardError = IdCardUtil.getErrorMessage(excel.getCandId());
|
||||
if (idCardError != null) {
|
||||
throw new RuntimeException("证件号码" + idCardError);
|
||||
}
|
||||
|
||||
// 验证毕业年月格式(YYYYMM)
|
||||
if (!excel.getCandGrad().matches("^((19|20)\\d{2})(0[1-9]|1[0-2])$")) {
|
||||
throw new RuntimeException("毕业年月格式不正确,应为YYYYMM");
|
||||
}
|
||||
|
||||
// 验证录用状态
|
||||
if (AdmitStatus.getDescByCode(excel.getAdmitStatus()) == null) {
|
||||
throw new RuntimeException("录用情况只能填写'录用'、'未录用'或'放弃'");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.ruoyi.ccdi.mapper.CcdiStaffRecruitmentMapper">
|
||||
|
||||
<!-- 招聘信息ResultMap -->
|
||||
<resultMap type="com.ruoyi.ccdi.domain.vo.CcdiStaffRecruitmentVO" id="CcdiStaffRecruitmentVOResult">
|
||||
<id property="recruitId" column="recruit_id"/>
|
||||
<result property="recruitName" column="recruit_name"/>
|
||||
<result property="posName" column="pos_name"/>
|
||||
<result property="posCategory" column="pos_category"/>
|
||||
<result property="posDesc" column="pos_desc"/>
|
||||
<result property="candName" column="cand_name"/>
|
||||
<result property="candEdu" column="cand_edu"/>
|
||||
<result property="candId" column="cand_id"/>
|
||||
<result property="candSchool" column="cand_school"/>
|
||||
<result property="candMajor" column="cand_major"/>
|
||||
<result property="candGrad" column="cand_grad"/>
|
||||
<result property="admitStatus" column="admit_status"/>
|
||||
<result property="interviewerName1" column="interviewer_name1"/>
|
||||
<result property="interviewerId1" column="interviewer_id1"/>
|
||||
<result property="interviewerName2" column="interviewer_name2"/>
|
||||
<result property="interviewerId2" column="interviewer_id2"/>
|
||||
<result property="createdBy" column="created_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updatedBy" column="updated_by"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
</resultMap>
|
||||
|
||||
<!-- 分页查询招聘信息列表 -->
|
||||
<select id="selectRecruitmentPage" resultMap="CcdiStaffRecruitmentVOResult">
|
||||
SELECT
|
||||
recruit_id, recruit_name, pos_name, pos_category, pos_desc,
|
||||
cand_name, cand_edu, cand_id, cand_school, cand_major, cand_grad,
|
||||
admit_status, interviewer_name1, interviewer_id1, interviewer_name2, interviewer_id2,
|
||||
created_by, create_time, updated_by, update_time
|
||||
FROM ccdi_staff_recruitment
|
||||
<where>
|
||||
<if test="query.recruitName != null and query.recruitName != ''">
|
||||
AND recruit_name LIKE CONCAT('%', #{query.recruitName}, '%')
|
||||
</if>
|
||||
<if test="query.posName != null and query.posName != ''">
|
||||
AND pos_name LIKE CONCAT('%', #{query.posName}, '%')
|
||||
</if>
|
||||
<if test="query.candName != null and query.candName != ''">
|
||||
AND cand_name LIKE CONCAT('%', #{query.candName}, '%')
|
||||
</if>
|
||||
<if test="query.candId != null and query.candId != ''">
|
||||
AND cand_id = #{query.candId}
|
||||
</if>
|
||||
<if test="query.admitStatus != null and query.admitStatus != ''">
|
||||
AND admit_status = #{query.admitStatus}
|
||||
</if>
|
||||
<if test="query.interviewerName != null and query.interviewerName != ''">
|
||||
AND (interviewer_name1 LIKE CONCAT('%', #{query.interviewerName}, '%')
|
||||
OR interviewer_name2 LIKE CONCAT('%', #{query.interviewerName}, '%'))
|
||||
</if>
|
||||
<if test="query.interviewerId != null and query.interviewerId != ''">
|
||||
AND (interviewer_id1 = #{query.interviewerId}
|
||||
OR interviewer_id2 = #{query.interviewerId})
|
||||
</if>
|
||||
</where>
|
||||
ORDER BY create_time DESC
|
||||
</select>
|
||||
|
||||
<!-- 查询招聘信息详情 -->
|
||||
<select id="selectRecruitmentById" resultMap="CcdiStaffRecruitmentVOResult">
|
||||
SELECT
|
||||
recruit_id, recruit_name, pos_name, pos_category, pos_desc,
|
||||
cand_name, cand_edu, cand_id, cand_school, cand_major, cand_grad,
|
||||
admit_status, interviewer_name1, interviewer_id1, interviewer_name2, interviewer_id2,
|
||||
created_by, create_time, updated_by, update_time
|
||||
FROM ccdi_staff_recruitment
|
||||
WHERE recruit_id = #{recruitId}
|
||||
</select>
|
||||
|
||||
<!-- 批量插入招聘信息数据 -->
|
||||
<insert id="insertBatch">
|
||||
INSERT INTO ccdi_staff_recruitment
|
||||
(recruit_id, recruit_name, pos_name, pos_category, pos_desc,
|
||||
cand_name, cand_edu, cand_id, cand_school, cand_major, cand_grad,
|
||||
admit_status, interviewer_name1, interviewer_id1, interviewer_name2, interviewer_id2,
|
||||
created_by, create_time, updated_by, update_time)
|
||||
VALUES
|
||||
<foreach collection="list" item="item" separator=",">
|
||||
(#{item.recruitId}, #{item.recruitName}, #{item.posName}, #{item.posCategory}, #{item.posDesc},
|
||||
#{item.candName}, #{item.candEdu}, #{item.candId}, #{item.candSchool}, #{item.candMajor}, #{item.candGrad},
|
||||
#{item.admitStatus}, #{item.interviewerName1}, #{item.interviewerId1}, #{item.interviewerName2}, #{item.interviewerId2},
|
||||
#{item.createdBy}, NOW(), #{item.updatedBy}, NOW())
|
||||
</foreach>
|
||||
</insert>
|
||||
|
||||
<!-- 批量更新招聘信息数据 -->
|
||||
<update id="updateBatch">
|
||||
<foreach collection="list" item="item" separator=";">
|
||||
UPDATE ccdi_staff_recruitment
|
||||
SET recruit_name = #{item.recruitName},
|
||||
pos_name = #{item.posName},
|
||||
pos_category = #{item.posCategory},
|
||||
pos_desc = #{item.posDesc},
|
||||
cand_name = #{item.candName},
|
||||
cand_edu = #{item.candEdu},
|
||||
cand_id = #{item.candId},
|
||||
cand_school = #{item.candSchool},
|
||||
cand_major = #{item.candMajor},
|
||||
cand_grad = #{item.candGrad},
|
||||
admit_status = #{item.admitStatus},
|
||||
interviewer_name1 = #{item.interviewerName1},
|
||||
interviewer_id1 = #{item.interviewerId1},
|
||||
interviewer_name2 = #{item.interviewerName2},
|
||||
interviewer_id2 = #{item.interviewerId2},
|
||||
updated_by = #{item.updatedBy},
|
||||
update_time = NOW()
|
||||
WHERE recruit_id = #{item.recruitId}
|
||||
</foreach>
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.ruoyi.common.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 必填字段注解
|
||||
* 用于标注Excel导入导出实体类中的必填字段
|
||||
* 在生成导入模板时,会为必填字段的表头添加红色星号(*)标记
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface Required {
|
||||
}
|
||||
70
ruoyi-ui/src/api/ccdiStaffRecruitment.js
Normal file
70
ruoyi-ui/src/api/ccdiStaffRecruitment.js
Normal file
@@ -0,0 +1,70 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 查询招聘信息列表
|
||||
export function listStaffRecruitment(query) {
|
||||
return request({
|
||||
url: '/ccdi/staffRecruitment/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询招聘信息详细
|
||||
export function getStaffRecruitment(recruitId) {
|
||||
return request({
|
||||
url: '/ccdi/staffRecruitment/' + recruitId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增招聘信息
|
||||
export function addStaffRecruitment(data) {
|
||||
return request({
|
||||
url: '/ccdi/staffRecruitment',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改招聘信息
|
||||
export function updateStaffRecruitment(data) {
|
||||
return request({
|
||||
url: '/ccdi/staffRecruitment',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除招聘信息
|
||||
export function delStaffRecruitment(recruitIds) {
|
||||
return request({
|
||||
url: '/ccdi/staffRecruitment/' + recruitIds,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 下载导入模板
|
||||
export function importTemplate() {
|
||||
return request({
|
||||
url: '/ccdi/staffRecruitment/importTemplate',
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
||||
// 导入招聘信息
|
||||
export function importData(data, updateSupport) {
|
||||
return request({
|
||||
url: '/ccdi/staffRecruitment/importData?updateSupport=' + updateSupport,
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 导出招聘信息
|
||||
export function exportStaffRecruitment(query) {
|
||||
return request({
|
||||
url: '/ccdi/staffRecruitment/export',
|
||||
method: 'post',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
623
ruoyi-ui/src/views/ccdiStaffRecruitment/index.vue
Normal file
623
ruoyi-ui/src/views/ccdiStaffRecruitment/index.vue
Normal file
@@ -0,0 +1,623 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="100px">
|
||||
<el-form-item label="招聘项目名称" prop="recruitName">
|
||||
<el-input
|
||||
v-model="queryParams.recruitName"
|
||||
placeholder="请输入招聘项目名称"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="职位名称" prop="posName">
|
||||
<el-input
|
||||
v-model="queryParams.posName"
|
||||
placeholder="请输入职位名称"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="候选人姓名" prop="candName">
|
||||
<el-input
|
||||
v-model="queryParams.candName"
|
||||
placeholder="请输入候选人姓名"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="证件号码" prop="candId">
|
||||
<el-input
|
||||
v-model="queryParams.candId"
|
||||
placeholder="请输入证件号码"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="录用情况" prop="admitStatus">
|
||||
<el-select v-model="queryParams.admitStatus" placeholder="请选择录用情况" clearable style="width: 240px">
|
||||
<el-option label="录用" value="录用" />
|
||||
<el-option label="未录用" value="未录用" />
|
||||
<el-option label="放弃" value="放弃" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
icon="el-icon-plus"
|
||||
size="mini"
|
||||
@click="handleAdd"
|
||||
v-hasPermi="['ccdi:staffRecruitment:add']"
|
||||
>新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="success"
|
||||
plain
|
||||
icon="el-icon-upload2"
|
||||
size="mini"
|
||||
@click="handleImport"
|
||||
v-hasPermi="['ccdi:staffRecruitment:import']"
|
||||
>导入</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="warning"
|
||||
plain
|
||||
icon="el-icon-download"
|
||||
size="mini"
|
||||
@click="handleExport"
|
||||
v-hasPermi="['ccdi:staffRecruitment:export']"
|
||||
>导出</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<el-table v-loading="loading" :data="recruitmentList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="招聘项目编号" align="center" prop="recruitId" width="150" :show-overflow-tooltip="true"/>
|
||||
<el-table-column label="招聘项目名称" align="center" prop="recruitName" :show-overflow-tooltip="true"/>
|
||||
<el-table-column label="职位名称" align="center" prop="posName" :show-overflow-tooltip="true"/>
|
||||
<el-table-column label="候选人姓名" align="center" prop="candName" width="120"/>
|
||||
<el-table-column label="证件号码" align="center" prop="candId" width="180"/>
|
||||
<el-table-column label="毕业院校" align="center" prop="candSchool" :show-overflow-tooltip="true"/>
|
||||
<el-table-column label="专业" align="center" prop="candMajor" :show-overflow-tooltip="true"/>
|
||||
<el-table-column label="录用情况" align="center" prop="admitStatus" width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-tag v-if="scope.row.admitStatus === '录用'" type="success" size="small">录用</el-tag>
|
||||
<el-tag v-else-if="scope.row.admitStatus === '未录用'" type="info" size="small">未录用</el-tag>
|
||||
<el-tag v-else type="warning" size="small">放弃</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="200">
|
||||
<template slot-scope="scope">
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-view"
|
||||
@click="handleDetail(scope.row)"
|
||||
v-hasPermi="['ccdi:staffRecruitment:query']"
|
||||
>详情</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-edit"
|
||||
@click="handleUpdate(scope.row)"
|
||||
v-hasPermi="['ccdi:staffRecruitment:edit']"
|
||||
>编辑</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-delete"
|
||||
@click="handleDelete(scope.row)"
|
||||
v-hasPermi="['ccdi:staffRecruitment:remove']"
|
||||
>删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total>0"
|
||||
:total="total"
|
||||
:page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
|
||||
<!-- 添加或修改对话框 -->
|
||||
<el-dialog :title="title" :visible.sync="open" width="900px" append-to-body>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="120px">
|
||||
<el-divider content-position="left">招聘项目信息</el-divider>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="招聘项目编号" prop="recruitId">
|
||||
<el-input v-model="form.recruitId" placeholder="请输入招聘项目编号" maxlength="32" :disabled="!isAdd" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="招聘项目名称" prop="recruitName">
|
||||
<el-input v-model="form.recruitName" placeholder="请输入招聘项目名称" maxlength="100" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-divider content-position="left">职位信息</el-divider>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="职位名称" prop="posName">
|
||||
<el-input v-model="form.posName" placeholder="请输入职位名称" maxlength="100" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="职位类别" prop="posCategory">
|
||||
<el-input v-model="form.posCategory" placeholder="请输入职位类别" maxlength="50" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item label="职位描述" prop="posDesc">
|
||||
<el-input v-model="form.posDesc" type="textarea" :rows="3" placeholder="请输入职位描述" />
|
||||
</el-form-item>
|
||||
|
||||
<el-divider content-position="left">候选人信息</el-divider>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="候选人姓名" prop="candName">
|
||||
<el-input v-model="form.candName" placeholder="请输入候选人姓名" maxlength="20" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="学历" prop="candEdu">
|
||||
<el-input v-model="form.candEdu" placeholder="请输入学历" maxlength="20" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="证件号码" prop="candId">
|
||||
<el-input v-model="form.candId" placeholder="请输入18位证件号码" maxlength="18" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="毕业年月" prop="candGrad">
|
||||
<el-input v-model="form.candGrad" placeholder="格式:YYYYMM" maxlength="6" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="毕业院校" prop="candSchool">
|
||||
<el-input v-model="form.candSchool" placeholder="请输入毕业院校" maxlength="50" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="专业" prop="candMajor">
|
||||
<el-input v-model="form.candMajor" placeholder="请输入专业" maxlength="30" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-divider content-position="left">录用信息</el-divider>
|
||||
<el-form-item label="录用情况" prop="admitStatus">
|
||||
<el-radio-group v-model="form.admitStatus">
|
||||
<el-radio label="录用">录用</el-radio>
|
||||
<el-radio label="未录用">未录用</el-radio>
|
||||
<el-radio label="放弃">放弃</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-divider content-position="left">面试官信息</el-divider>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="面试官1姓名">
|
||||
<el-input v-model="form.interviewerName1" placeholder="请输入面试官1姓名" maxlength="20" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="面试官1工号">
|
||||
<el-input v-model="form.interviewerId1" placeholder="请输入面试官1工号" maxlength="10" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="面试官2姓名">
|
||||
<el-input v-model="form.interviewerName2" placeholder="请输入面试官2姓名" maxlength="20" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="面试官2工号">
|
||||
<el-input v-model="form.interviewerId2" placeholder="请输入面试官2工号" maxlength="10" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="cancel">取消</el-button>
|
||||
<el-button type="primary" @click="submitForm">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 详情对话框 -->
|
||||
<el-dialog title="招聘信息详情" :visible.sync="detailOpen" width="900px" append-to-body>
|
||||
<div class="detail-container">
|
||||
<el-divider content-position="left">招聘项目信息</el-divider>
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="招聘项目编号">{{ recruitmentDetail.recruitId || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="招聘项目名称">{{ recruitmentDetail.recruitName || '-' }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<el-divider content-position="left">职位信息</el-divider>
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="职位名称">{{ recruitmentDetail.posName || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="职位类别">{{ recruitmentDetail.posCategory || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="职位描述" :span="2">{{ recruitmentDetail.posDesc || '-' }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<el-divider content-position="left">候选人信息</el-divider>
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="候选人姓名">{{ recruitmentDetail.candName || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="学历">{{ recruitmentDetail.candEdu || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="证件号码">{{ recruitmentDetail.candId || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="毕业年月">{{ recruitmentDetail.candGrad || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="毕业院校">{{ recruitmentDetail.candSchool || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="专业">{{ recruitmentDetail.candMajor || '-' }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<el-divider content-position="left">录用信息</el-divider>
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="录用情况">
|
||||
<el-tag v-if="recruitmentDetail.admitStatus === '录用'" type="success" size="small">录用</el-tag>
|
||||
<el-tag v-else-if="recruitmentDetail.admitStatus === '未录用'" type="info" size="small">未录用</el-tag>
|
||||
<el-tag v-else type="warning" size="small">放弃</el-tag>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<el-divider content-position="left">面试官信息</el-divider>
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="面试官1">{{ recruitmentDetail.interviewerName1 || '-' }} ({{ recruitmentDetail.interviewerId1 || '-' }})</el-descriptions-item>
|
||||
<el-descriptions-item label="面试官2">{{ recruitmentDetail.interviewerName2 || '-' }} ({{ recruitmentDetail.interviewerId2 || '-' }})</el-descriptions-item>
|
||||
<el-descriptions-item label="创建时间">
|
||||
{{ recruitmentDetail.createTime ? parseTime(recruitmentDetail.createTime) : '-' }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="创建人">{{ recruitmentDetail.createdBy || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="更新时间">
|
||||
{{ recruitmentDetail.updateTime ? parseTime(recruitmentDetail.updateTime) : '-' }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="更新人">{{ recruitmentDetail.updatedBy || '-' }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="detailOpen = false" icon="el-icon-close">关 闭</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 导入对话框 -->
|
||||
<el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body @close="handleImportDialogClose" v-loading="upload.isUploading" element-loading-text="正在导入数据,请稍候..." element-loading-spinner="el-icon-loading" element-loading-background="rgba(0, 0, 0, 0.7)">
|
||||
<el-upload
|
||||
ref="upload"
|
||||
:limit="1"
|
||||
accept=".xlsx, .xls"
|
||||
:headers="upload.headers"
|
||||
:action="upload.url + '?updateSupport=' + upload.updateSupport"
|
||||
:disabled="upload.isUploading"
|
||||
:on-progress="handleFileUploadProgress"
|
||||
:on-success="handleFileSuccess"
|
||||
:auto-upload="false"
|
||||
drag
|
||||
>
|
||||
<i class="el-icon-upload"></i>
|
||||
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
|
||||
<div class="el-upload__tip" slot="tip">
|
||||
<el-checkbox v-model="upload.updateSupport" />是否更新已经存在的招聘信息数据
|
||||
<el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline;" @click="importTemplate">下载模板</el-link>
|
||||
</div>
|
||||
<div class="el-upload__tip" slot="tip">
|
||||
<span>仅允许导入"xls"或"xlsx"格式文件。</span>
|
||||
</div>
|
||||
</el-upload>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitFileForm" :loading="upload.isUploading">确 定</el-button>
|
||||
<el-button @click="upload.open = false" :disabled="upload.isUploading">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { addStaffRecruitment, delStaffRecruitment, getStaffRecruitment, listStaffRecruitment, updateStaffRecruitment, importTemplate } from "@/api/ccdiStaffRecruitment";
|
||||
import { getToken } from "@/utils/auth";
|
||||
|
||||
// 身份证号校验正则
|
||||
const idCardPattern = /^[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$/;
|
||||
// 毕业年月校验正则 (YYYYMM)
|
||||
const gradPattern = /^((19|20)\d{2})(0[1-9]|1[0-2])$/;
|
||||
|
||||
export default {
|
||||
name: "StaffRecruitment",
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 选中数组
|
||||
ids: [],
|
||||
// 非单个禁用
|
||||
single: true,
|
||||
// 非多个禁用
|
||||
multiple: true,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 招聘信息表格数据
|
||||
recruitmentList: [],
|
||||
// 弹出层标题
|
||||
title: "",
|
||||
// 是否显示弹出层
|
||||
open: false,
|
||||
// 是否显示详情弹出层
|
||||
detailOpen: false,
|
||||
// 招聘信息详情
|
||||
recruitmentDetail: {},
|
||||
// 是否为新增操作
|
||||
isAdd: false,
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
recruitName: null,
|
||||
posName: null,
|
||||
candName: null,
|
||||
candId: null,
|
||||
admitStatus: null,
|
||||
interviewerName: null,
|
||||
interviewerId: null
|
||||
},
|
||||
// 表单参数
|
||||
form: {},
|
||||
// 表单校验
|
||||
rules: {
|
||||
recruitId: [
|
||||
{ required: true, message: "招聘项目编号不能为空", trigger: "blur" },
|
||||
{ max: 32, message: "招聘项目编号长度不能超过32个字符", trigger: "blur" }
|
||||
],
|
||||
recruitName: [
|
||||
{ required: true, message: "招聘项目名称不能为空", trigger: "blur" },
|
||||
{ max: 100, message: "招聘项目名称长度不能超过100个字符", trigger: "blur" }
|
||||
],
|
||||
posName: [
|
||||
{ required: true, message: "职位名称不能为空", trigger: "blur" },
|
||||
{ max: 100, message: "职位名称长度不能超过100个字符", trigger: "blur" }
|
||||
],
|
||||
posCategory: [
|
||||
{ required: true, message: "职位类别不能为空", trigger: "blur" },
|
||||
{ max: 50, message: "职位类别长度不能超过50个字符", trigger: "blur" }
|
||||
],
|
||||
posDesc: [
|
||||
{ required: true, message: "职位描述不能为空", trigger: "blur" }
|
||||
],
|
||||
candName: [
|
||||
{ required: true, message: "候选人姓名不能为空", trigger: "blur" },
|
||||
{ max: 20, message: "候选人姓名长度不能超过20个字符", trigger: "blur" }
|
||||
],
|
||||
candEdu: [
|
||||
{ required: true, message: "学历不能为空", trigger: "blur" },
|
||||
{ max: 20, message: "学历长度不能超过20个字符", trigger: "blur" }
|
||||
],
|
||||
candId: [
|
||||
{ required: true, message: "证件号码不能为空", trigger: "blur" },
|
||||
{ pattern: idCardPattern, message: "请输入正确的18位身份证号", trigger: "blur" }
|
||||
],
|
||||
candSchool: [
|
||||
{ required: true, message: "毕业院校不能为空", trigger: "blur" },
|
||||
{ max: 50, message: "毕业院校长度不能超过50个字符", trigger: "blur" }
|
||||
],
|
||||
candMajor: [
|
||||
{ required: true, message: "专业不能为空", trigger: "blur" },
|
||||
{ max: 30, message: "专业长度不能超过30个字符", trigger: "blur" }
|
||||
],
|
||||
candGrad: [
|
||||
{ required: true, message: "毕业年月不能为空", trigger: "blur" },
|
||||
{ pattern: gradPattern, message: "毕业年月格式不正确,应为YYYYMM", trigger: "blur" }
|
||||
],
|
||||
admitStatus: [
|
||||
{ required: true, message: "请选择录用情况", trigger: "change" }
|
||||
]
|
||||
},
|
||||
// 导入参数
|
||||
upload: {
|
||||
// 是否显示弹出层
|
||||
open: false,
|
||||
// 弹出层标题
|
||||
title: "",
|
||||
// 是否禁用上传
|
||||
isUploading: false,
|
||||
// 是否更新已经存在的数据
|
||||
updateSupport: 0,
|
||||
// 设置上传的请求头部
|
||||
headers: { Authorization: "Bearer " + getToken() },
|
||||
// 上传的地址
|
||||
url: process.env.VUE_APP_BASE_API + "/ccdi/staffRecruitment/importData"
|
||||
}
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
/** 查询招聘信息列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
listStaffRecruitment(this.queryParams).then(response => {
|
||||
this.recruitmentList = response.rows;
|
||||
this.total = response.total;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
// 取消按钮
|
||||
cancel() {
|
||||
this.open = false;
|
||||
this.reset();
|
||||
},
|
||||
// 表单重置
|
||||
reset() {
|
||||
this.form = {
|
||||
recruitId: null,
|
||||
recruitName: null,
|
||||
posName: null,
|
||||
posCategory: null,
|
||||
posDesc: null,
|
||||
candName: null,
|
||||
candEdu: null,
|
||||
candId: null,
|
||||
candSchool: null,
|
||||
candMajor: null,
|
||||
candGrad: null,
|
||||
admitStatus: "录用",
|
||||
interviewerName1: null,
|
||||
interviewerId1: null,
|
||||
interviewerName2: null,
|
||||
interviewerId2: null
|
||||
};
|
||||
this.resetForm("form");
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1;
|
||||
this.getList();
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.resetForm("queryForm");
|
||||
this.handleQuery();
|
||||
},
|
||||
/** 多选框选中数据 */
|
||||
handleSelectionChange(selection) {
|
||||
this.ids = selection.map(item => item.recruitId);
|
||||
this.single = selection.length !== 1;
|
||||
this.multiple = !selection.length;
|
||||
},
|
||||
/** 新增按钮操作 */
|
||||
handleAdd() {
|
||||
this.reset();
|
||||
this.open = true;
|
||||
this.title = "添加招聘信息";
|
||||
this.isAdd = true;
|
||||
},
|
||||
/** 修改按钮操作 */
|
||||
handleUpdate(row) {
|
||||
this.reset();
|
||||
const recruitId = row.recruitId || this.ids[0];
|
||||
getStaffRecruitment(recruitId).then(response => {
|
||||
this.form = response.data;
|
||||
this.open = true;
|
||||
this.title = "修改招聘信息";
|
||||
this.isAdd = false;
|
||||
});
|
||||
},
|
||||
/** 详情按钮操作 */
|
||||
handleDetail(row) {
|
||||
const recruitId = row.recruitId;
|
||||
getStaffRecruitment(recruitId).then(response => {
|
||||
this.recruitmentDetail = response.data;
|
||||
this.detailOpen = true;
|
||||
});
|
||||
},
|
||||
/** 提交按钮 */
|
||||
submitForm() {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (valid) {
|
||||
if (this.isAdd) {
|
||||
addStaffRecruitment(this.form).then(response => {
|
||||
this.$modal.msgSuccess("新增成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
} else {
|
||||
updateStaffRecruitment(this.form).then(response => {
|
||||
this.$modal.msgSuccess("修改成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
/** 删除按钮操作 */
|
||||
handleDelete(row) {
|
||||
const recruitIds = row.recruitId || this.ids;
|
||||
this.$modal.confirm('是否确认删除招聘信息编号为"' + recruitIds + '"的数据项?').then(function() {
|
||||
return delStaffRecruitment(recruitIds);
|
||||
}).then(() => {
|
||||
this.getList();
|
||||
this.$modal.msgSuccess("删除成功");
|
||||
}).catch(() => {});
|
||||
},
|
||||
/** 导出按钮操作 */
|
||||
handleExport() {
|
||||
this.download('ccdi/staffRecruitment/export', {
|
||||
...this.queryParams
|
||||
}, `招聘信息_${new Date().getTime()}.xlsx`);
|
||||
},
|
||||
/** 导入按钮操作 */
|
||||
handleImport() {
|
||||
this.upload.title = "招聘信息数据导入";
|
||||
this.upload.open = true;
|
||||
},
|
||||
/** 下载模板操作 */
|
||||
importTemplate() {
|
||||
this.download('ccdi/staffRecruitment/importTemplate', {}, `招聘信息导入模板_${new Date().getTime()}.xlsx`);
|
||||
},
|
||||
// 文件上传中处理
|
||||
handleFileUploadProgress(event, file, fileList) {
|
||||
this.upload.isUploading = true;
|
||||
},
|
||||
// 文件上传成功处理
|
||||
handleFileSuccess(response, file, fileList) {
|
||||
this.upload.isUploading = false;
|
||||
if (response.code === 200) {
|
||||
this.$modal.msgSuccess(response.msg);
|
||||
this.upload.open = false;
|
||||
this.getList();
|
||||
} else {
|
||||
this.$modal.msgError(response.msg);
|
||||
}
|
||||
this.$refs.upload.clearFiles();
|
||||
},
|
||||
// 提交上传文件
|
||||
submitFileForm() {
|
||||
this.$refs.upload.submit();
|
||||
},
|
||||
// 关闭导入对话框
|
||||
handleImportDialogClose() {
|
||||
this.upload.isUploading = false;
|
||||
this.$refs.upload.clearFiles();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.detail-container {
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.el-divider {
|
||||
margin: 16px 0;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user