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.
Reference in New Issue
Block a user