- 移除tellerNo字段,将employeeId设置为柜员号 - 柜员号为7位数字,手动输入,唯一性校验 - 包含数据库、后端、前端、测试等完整设计方案 - 生成测试脚本和API文档更新计划
12 KiB
12 KiB
员工柜员号优化设计文档
文档版本: v1.0 创建日期: 2026-02-05 设计目标: 统一标识符,移除tellerNo字段,将employeeId设置为柜员号
一、需求概述
1.1 需求背景
当前员工信息表中存在两个字段用于标识员工:
employee_id: 数据库主键,自增IDteller_no: 柜员号,业务标识符
这种双标识符设计造成了字段冗余和业务混淆。
1.2 需求目标
- 移除
teller_no字段,简化数据结构 - 将
employee_id改为手动输入的柜员号(7位数字) - 统一标识符,避免业务混淆
- 保持数据完整性和业务连续性
1.3 约束条件
- 系统处于开发阶段,无正式生产数据
- 柜员号必须为7位数字
- 柜员号必须唯一,不允许重复
- 柜员号为必填字段
二、数据库层设计
2.1 表结构修改
删除字段
ALTER TABLE ccdi_employee DROP COLUMN teller_no;
修改主键字段
-- 移除自增属性
ALTER TABLE ccdi_employee MODIFY employee_id BIGINT(20) NOT NULL;
-- 更新字段注释
ALTER TABLE ccdi_employee MODIFY COLUMN employee_id BIGINT(20) NOT NULL COMMENT '员工ID(柜员号,7位数字)';
重建表方案(推荐,清空数据场景)
DROP TABLE IF EXISTS ccdi_employee;
CREATE TABLE ccdi_employee (
employee_id BIGINT(20) NOT NULL COMMENT '员工ID(柜员号,7位数字)',
name VARCHAR(100) NOT NULL COMMENT '姓名',
dept_id BIGINT(20) DEFAULT NULL COMMENT '所属部门ID',
id_card VARCHAR(18) NOT NULL COMMENT '身份证号',
phone VARCHAR(11) DEFAULT NULL COMMENT '电话',
hire_date DATE DEFAULT NULL COMMENT '入职时间',
status CHAR(1) NOT NULL DEFAULT '0' COMMENT '状态(0在职 1离职)',
create_by VARCHAR(64) DEFAULT '' COMMENT '创建者',
create_time DATETIME DEFAULT NULL COMMENT '创建时间',
update_by VARCHAR(64) DEFAULT '' COMMENT '更新者',
update_time DATETIME DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (employee_id),
KEY idx_dept_id (dept_id),
KEY idx_status (status),
UNIQUE KEY uk_id_card (id_card)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='员工信息表';
2.2 索引调整
- 移除:
UNIQUE KEY teller_no - 保留:
PRIMARY KEY (employee_id)天然保证唯一性
三、后端代码层设计
3.1 Entity 实体类 (CcdiEmployee.java)
修改前:
@TableId(type = IdType.AUTO)
private Long employeeId;
private String tellerNo;
修改后:
@TableId(type = IdType.INPUT) // 改为手动输入
private Long employeeId;
// 删除 tellerNo 字段
3.2 DTO 类修改
CcdiEmployeeAddDTO.java
/** 员工ID(柜员号) */
@NotNull(message = "柜员号不能为空")
@Min(value = 1000000L, message = "柜员号必须为7位数字")
@Max(value = 9999999L, message = "柜员号必须为7位数字")
private Long employeeId;
// 删除 tellerNo 字段
CcdiEmployeeEditDTO.java
// employeeId 作为主键标识,通过路径参数传递,不在请求体中
// 删除 tellerNo 字段
CcdiEmployeeQueryDTO.java
/** 柜员号(精确查询) */
@Min(value = 1000000L, message = "柜员号必须为7位数字")
@Max(value = 9999999L, message = "柜员号必须为7位数字")
private Long employeeId;
// 删除 tellerNo 字段
3.3 VO 类修改 (CcdiEmployeeVO.java)
/** 员工ID(柜员号) */
private Long employeeId;
// 删除 tellerNo 字段
3.4 Service 层修改
新增柜员号唯一性校验
@Override
public void checkEmployeeIdUnique(Long employeeId) {
CcdiEmployee existing = baseMapper.selectById(employeeId);
if (existing != null) {
throw new ServiceException("柜员号已存在,请使用其他柜员号");
}
}
新增员工方法调整
@Override
public void addEmployee(CcdiEmployeeAddDTO dto) {
// 1. 校验柜员号唯一性
checkEmployeeIdUnique(dto.getEmployeeId());
// 2. 校验身份证号唯一性
checkIdCardUnique(dto.getIdCard());
// 3. 转换并保存
CcdiEmployee employee = BeanUtil.copyProperties(dto, CcdiEmployee.class);
baseMapper.insert(employee);
}
3.5 Mapper XML 修改
ResultMap 调整
<resultMap type="com.ruoyi.ccdi.domain.vo.CcdiEmployeeVO" id="CcdiEmployeeVOResult">
<id property="employeeId" column="employee_id"/>
<result property="name" column="name"/>
<!-- 删除 tellerNo 映射 -->
<result property="deptId" column="dept_id"/>
<result property="deptName" column="dept_name"/>
<result property="idCard" column="id_card"/>
<result property="phone" column="phone"/>
<result property="hireDate" column="hire_date"/>
<result property="status" column="status"/>
<result property="createTime" column="create_time"/>
</resultMap>
查询 SQL 调整
<select id="selectEmployeePageWithDept" resultMap="CcdiEmployeeVOResult">
SELECT
e.employee_id, e.name, e.dept_id, e.id_card, e.phone,
e.hire_date, e.status, e.create_time,
d.dept_name
FROM ccdi_employee e
LEFT JOIN sys_dept d ON e.dept_id = d.dept_id
<where>
<if test="query.name != null and query.name != ''">
AND e.name LIKE CONCAT('%', #{query.name}, '%')
</if>
<if test="query.employeeId != null">
AND e.employee_id = #{query.employeeId}
</if>
<!-- 删除 teller_no 查询条件 -->
<if test="query.deptId != null">
AND e.dept_id = #{query.deptId}
</if>
<if test="query.idCard != null and query.idCard != ''">
AND e.id_card LIKE CONCAT('%', #{query.idCard}, '%')
</if>
<if test="query.status != null and query.status != ''">
AND e.status = #{query.status}
</if>
</where>
ORDER BY e.create_time DESC
</select>
3.6 Controller 层修改
接口参数调整
- POST /ccdi/employee: 新增接口,接收
employeeId作为必填字段 - PUT /ccdi/employee/{employeeId}: 编辑接口,
employeeId作为路径参数不可修改 - GET /ccdi/employee/list: 列表查询,移除
tellerNo查询参数,保留employeeId精确查询
Swagger 注释更新
@Operation(summary = "新增员工信息", description = "employeeId为柜员号,7位数字")
四、前端代码层设计
4.1 查询表单调整
<!-- 删除原来的 tellerNo 查询条件 -->
<!-- 新增:员工ID(柜员号)查询 -->
<el-form-item label="柜员号" prop="employeeId">
<el-input
v-model="queryParams.employeeId"
placeholder="请输入7位柜员号"
clearable
maxlength="7"
oninput="value=value.replace(/[^\d]/g,'')"
style="width: 240px"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
4.2 表格列调整
<!-- 删除 -->
<!-- <el-table-column label="柜员号" prop="tellerNo" /> -->
<!-- 新增 -->
<el-table-column label="柜员号" align="center" prop="employeeId" :show-overflow-tooltip="true"/>
4.3 新增/编辑对话框调整
<!-- 新增模式:可输入 -->
<el-form-item label="柜员号" prop="employeeId" v-if="!isEdit">
<el-input
v-model="form.employeeId"
placeholder="请输入7位柜员号"
clearable
maxlength="7"
oninput="value=value.replace(/[^\d]/g,'')"
style="width: 240px"
/>
</el-form-item>
<!-- 编辑模式:只读 -->
<el-form-item label="柜员号" prop="employeeId" v-if="isEdit">
<el-input v-model="form.employeeId" disabled style="width: 240px"/>
</el-form-item>
4.4 JavaScript 数据结构
data() {
return {
queryParams: {
name: null,
employeeId: null, // 替代 tellerNo
deptId: null,
idCard: null,
status: null
},
form: {
employeeId: null, // 替代 tellerNo
name: null,
deptId: null,
// ...
}
}
}
4.5 表单校验规则
rules: {
employeeId: [
{ required: true, message: "柜员号不能为空", trigger: "blur" },
{ pattern: /^\d{7}$/, message: "柜员号必须为7位数字", trigger: "blur" }
],
// 其他规则...
}
五、测试方案
5.1 新增员工测试
| 测试场景 | 输入数据 | 预期结果 |
|---|---|---|
| 正常场景 | 柜员号: 1000000 | 新增成功 |
| 格式错误-少于7位 | 柜员号: 123456 | 提示"柜员号必须为7位数字" |
| 格式错误-多于7位 | 柜员号: 12345678 | 提示"柜员号必须为7位数字" |
| 格式错误-非数字 | 柜员号: 123456a | 提示"柜员号必须为7位数字" |
| 唯一性冲突 | 重复的柜员号 | 提示"柜员号已存在" |
| 必填校验 | 柜员号为空 | 提示"柜员号不能为空" |
5.2 编辑员工测试
| 测试场景 | 操作 | 预期结果 |
|---|---|---|
| 正常编辑 | 修改其他字段,柜员号不可变 | 编辑成功,柜员号不变 |
| 只读验证 | 尝试修改柜员号 | 柜员号输入框禁用 |
5.3 查询测试
| 测试场景 | 输入 | 预期结果 |
|---|---|---|
| 精确查询 | 输入7位柜员号 | 返回匹配的员工记录 |
| 列表显示 | 查看列表 | 显示employeeId作为柜员号 |
六、文档更新清单
6.1 API 文档更新
- 文件路径:
doc/api/员工信息管理API文档.md - 更新内容:
- 新增接口:移除
tellerNo,新增employeeId参数说明 - 编辑接口:更新路径参数为
employeeId - 查询接口:移除
tellerNo查询参数,新增employeeId - 返回数据:移除
tellerNo字段 - 字段说明表:更新
employeeId为"员工ID(柜员号,7位数字)"
- 新增接口:移除
6.2 测试脚本
- 文件路径:
doc/test/2026-02-05-employee-modify-test.sh - 测试账号: username: admin, password: admin123
- 测试接口:
/login/test获取 token
6.3 数据库脚本
- 文件路径:
sql/modify_employee_id_to_teller_no.sql - 执行顺序:
- 删除
teller_no字段 - 修改
employee_id为非自增 - 更新字段注释
- 删除
七、实施步骤
7.1 数据库修改
- 备份现有数据库(如有数据)
- 执行 SQL 脚本修改表结构
- 验证表结构修改成功
7.2 后端代码修改
- 修改 Entity 实体类
- 修改 DTO 类(Add/Edit/Query)
- 修改 VO 类
- 修改 Service 层,添加唯一性校验
- 修改 Mapper XML
- 修改 Controller 层
- 编译后端项目,确保无错误
7.3 前端代码修改
- 修改查询表单
- 修改表格列
- 修改新增/编辑对话框
- 修改 JavaScript 数据结构和方法
- 添加表单校验规则
- 编译前端项目,确保无错误
7.4 测试验证
- 执行测试脚本
- 验证新增功能
- 验证编辑功能
- 验证查询功能
- 验证唯一性校验
- 验证格式校验
- 生成测试报告
7.5 文档更新
- 更新 API 文档
- 更新测试报告
- 提交代码到版本控制
八、风险评估与应对
8.1 风险点
-
数据迁移风险: 如果有正式数据,需要迁移方案
- 应对: 当前为开发阶段,无正式数据,直接修改
-
接口兼容性: 前端调用可能受影响
- 应对: 同步修改前端代码和接口调用
-
业务逻辑依赖: 其他模块可能引用
tellerNo- 应对: 全局搜索
tellerNo引用,同步修改
- 应对: 全局搜索
8.2 回滚方案
如果修改后出现问题,可以:
- 恢复数据库表结构(添加回
teller_no字段) - 恢复代码到修改前的版本
- 恢复前端代码到修改前的版本
九、验收标准
9.1 功能验收
- ✅ 数据库
teller_no字段已删除 - ✅
employee_id改为非自增,手动输入 - ✅ 后端代码所有
tellerNo引用已移除 - ✅ 前端页面显示
employeeId作为柜员号 - ✅ 新增员工时必须输入7位数字柜员号
- ✅ 柜员号唯一性校验生效
- ✅ 柜员号格式校验生效
- ✅ 编辑时柜员号不可修改
9.2 性能验收
- ✅ 接口响应时间无明显变化
- ✅ 数据库查询效率正常
9.3 文档验收
- ✅ API 文档已更新
- ✅ 测试脚本已生成
- ✅ 测试报告已生成
文档结束