feat 员工亲属关系

This commit is contained in:
wkc
2026-02-10 10:41:19 +08:00
parent bf19a9daa8
commit 78a9300644
12 changed files with 234 additions and 1170 deletions

View File

@@ -102,7 +102,8 @@
"Bash(git -C \"D:\\\\ccdi\\\\ccdi\" log --oneline -5)",
"Bash([:*)",
"Bash([ -d modules ])",
"Bash([ -d test-data ])"
"Bash([ -d test-data ])",
"Skill(generate-test-data)"
]
},
"enabledMcpjsonServers": [

View File

@@ -8,6 +8,7 @@ import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 员工亲属关系Excel导入导出对象
@@ -46,68 +47,68 @@ public class CcdiStaffFmyRelationExcel implements Serializable {
@DictDropdown(dictType = "ccdi_indiv_gender")
private String gender;
/** 出生日期 */
@ExcelProperty(value = "出生日期", index = 4)
@ColumnWidth(15)
private Date birthDate;
/** 关系人证件类型 */
@ExcelProperty(value = "关系人证件类型*", index = 4)
@ExcelProperty(value = "关系人证件类型*", index = 5)
@ColumnWidth(15)
@DictDropdown(dictType = "ccdi_certificate_type")
@Required
private String relationCertType;
/** 关系人证件号码 */
@ExcelProperty(value = "关系人证件号码*", index = 5)
@ExcelProperty(value = "关系人证件号码*", index = 6)
@ColumnWidth(20)
@Required
private String relationCertNo;
/** 手机号码1 */
@ExcelProperty(value = "手机号码1", index = 6)
@ExcelProperty(value = "手机号码1", index = 7)
@ColumnWidth(15)
private String mobilePhone1;
/** 手机号码2 */
@ExcelProperty(value = "手机号码2", index = 7)
@ExcelProperty(value = "手机号码2", index = 8)
@ColumnWidth(15)
private String mobilePhone2;
/** 微信名称1 */
@ExcelProperty(value = "微信名称1", index = 8)
@ExcelProperty(value = "微信名称1", index = 9)
@ColumnWidth(15)
private String wechatNo1;
/** 微信名称2 */
@ExcelProperty(value = "微信名称2", index = 9)
@ExcelProperty(value = "微信名称2", index = 10)
@ColumnWidth(15)
private String wechatNo2;
/** 微信名称3 */
@ExcelProperty(value = "微信名称3", index = 10)
@ExcelProperty(value = "微信名称3", index = 11)
@ColumnWidth(15)
private String wechatNo3;
/** 详细联系地址 */
@ExcelProperty(value = "详细联系地址", index = 11)
@ExcelProperty(value = "详细联系地址", index = 12)
@ColumnWidth(30)
private String contactAddress;
/** 关系详细描述 */
@ExcelProperty(value = "关系详细描述", index = 12)
@ExcelProperty(value = "关系详细描述", index = 13)
@ColumnWidth(30)
private String relationDesc;
/** 生效日期 */
@ExcelProperty(value = "生效日期", index = 13)
@ExcelProperty(value = "生效日期", index = 14)
@ColumnWidth(15)
private String effectiveDate;
private Date effectiveDate;
/** 失效日期 */
@ExcelProperty(value = "失效日期", index = 14)
@ExcelProperty(value = "失效日期", index = 15)
@ColumnWidth(15)
private String invalidDate;
/** 状态 */
@ExcelProperty(value = "状态", index = 15)
@ColumnWidth(10)
private Integer status;
private Date invalidDate;
/** 备注 */
@ExcelProperty(value = "备注", index = 16)

View File

@@ -0,0 +1,138 @@
package com.ruoyi.ccdi.enums;
import org.apache.commons.lang3.StringUtils;
/**
* 性别枚举
* 用于性别中文标签与英文代码之间的转换
*
* @author ruoyi
* @date 2026-02-10
*/
public enum GenderEnum {
/**
* 男
*/
MALE("", "M"),
/**
* 女
*/
FEMALE("", "F"),
/**
* 其他
*/
OTHER("其他", "O");
private final String chineseLabel;
private final String englishCode;
GenderEnum(String chineseLabel, String englishCode) {
this.chineseLabel = chineseLabel;
this.englishCode = englishCode;
}
public String getChineseLabel() {
return chineseLabel;
}
public String getEnglishCode() {
return englishCode;
}
/**
* 根据中文标签获取枚举
*
* @param chineseLabel 中文标签(男、女、其他)
* @return 对应的枚举值
* @throws IllegalArgumentException 如果标签无效
*/
public static GenderEnum fromChinese(String chineseLabel) {
if (StringUtils.isEmpty(chineseLabel)) {
throw new IllegalArgumentException("性别标签不能为空");
}
for (GenderEnum gender : values()) {
if (gender.chineseLabel.equals(chineseLabel)) {
return gender;
}
}
throw new IllegalArgumentException("无效的性别标签: " + chineseLabel);
}
/**
* 根据英文代码获取枚举
*
* @param englishCode 英文代码M、F、O
* @return 对应的枚举值
* @throws IllegalArgumentException 如果代码无效
*/
public static GenderEnum fromEnglish(String englishCode) {
if (StringUtils.isEmpty(englishCode)) {
throw new IllegalArgumentException("性别代码不能为空");
}
for (GenderEnum gender : values()) {
if (gender.englishCode.equals(englishCode)) {
return gender;
}
}
throw new IllegalArgumentException("无效的性别代码: " + englishCode);
}
/**
* 验证性别值是否有效
* 支持中文标签男、女、其他或英文代码M、F、O
*
* @param value 待验证的值
* @return true-有效false-无效
*/
public static boolean isValid(String value) {
if (StringUtils.isEmpty(value)) {
return false;
}
for (GenderEnum gender : values()) {
if (gender.chineseLabel.equals(value) || gender.englishCode.equals(value)) {
return true;
}
}
return false;
}
/**
* 标准化性别值
* 输入中文标签或英文代码,统一返回英文代码
*
* @param input 输入值(中文或英文)
* @return 英文代码M、F、O
* @throws IllegalArgumentException 如果输入值无效
*/
public static String normalize(String input) {
if (StringUtils.isEmpty(input)) {
throw new IllegalArgumentException("性别值不能为空");
}
// 先尝试按中文匹配
for (GenderEnum gender : values()) {
if (gender.chineseLabel.equals(input)) {
return gender.englishCode;
}
}
// 再尝试按英文匹配(大写)
String upperInput = input.toUpperCase().trim();
for (GenderEnum gender : values()) {
if (gender.englishCode.equals(upperInput)) {
return gender.englishCode;
}
}
throw new IllegalArgumentException("无效的性别值: " + input + ",有效值为:男、女、其他 或 M、F、O");
}
}

View File

@@ -50,4 +50,14 @@ public interface CcdiStaffFmyRelationMapper extends BaseMapper<CcdiStaffFmyRelat
* @return 插入行数
*/
int insertBatch(@Param("list") List<CcdiStaffFmyRelation> list);
/**
* 批量查询已存在的员工亲属关系(用于导入唯一性校验)
*
* @param personIds 员工身份证号列表
* @param relationCertNos 关系人证件号码列表
* @return 已存在的记录列表
*/
List<CcdiStaffFmyRelation> selectExistingRelations(@Param("personIds") List<String> personIds,
@Param("relationCertNos") List<String> relationCertNos);
}

View File

@@ -7,6 +7,7 @@ import com.ruoyi.ccdi.domain.excel.CcdiStaffFmyRelationExcel;
import com.ruoyi.ccdi.domain.vo.ImportResult;
import com.ruoyi.ccdi.domain.vo.ImportStatusVO;
import com.ruoyi.ccdi.domain.vo.StaffFmyRelationImportFailureVO;
import com.ruoyi.ccdi.enums.GenderEnum;
import com.ruoyi.ccdi.mapper.CcdiStaffFmyRelationMapper;
import com.ruoyi.ccdi.service.ICcdiStaffFmyRelationImportService;
import com.ruoyi.common.utils.StringUtils;
@@ -44,10 +45,38 @@ public class CcdiStaffFmyRelationImportServiceImpl implements ICcdiStaffFmyRelat
List<CcdiStaffFmyRelation> newRecords = new ArrayList<>();
List<StaffFmyRelationImportFailureVO> failures = new ArrayList<>();
// 用于跟踪Excel文件内已处理的唯一键personId + relationCertNo
// ========== 第一步:批量唯一性校验 ==========
// 1. 提取Excel中所有的personId和relationCertNo
Set<String> excelPersonIds = new HashSet<>();
Set<String> excelRelationCertNos = new HashSet<>();
for (CcdiStaffFmyRelationExcel excel : excelList) {
if (StringUtils.isNotEmpty(excel.getPersonId())) {
excelPersonIds.add(excel.getPersonId());
}
if (StringUtils.isNotEmpty(excel.getRelationCertNo())) {
excelRelationCertNos.add(excel.getRelationCertNo());
}
}
// 2. 批量查询数据库中已存在的记录
Set<String> existingKeys = new HashSet<>();
if (!excelPersonIds.isEmpty() && !excelRelationCertNos.isEmpty()) {
List<CcdiStaffFmyRelation> existingRecords = relationMapper.selectExistingRelations(
new ArrayList<>(excelPersonIds),
new ArrayList<>(excelRelationCertNos)
);
// 3. 构建已存在记录的唯一键集合personId + relationCertNo
for (CcdiStaffFmyRelation existing : existingRecords) {
String key = existing.getPersonId() + "|" + existing.getRelationCertNo();
existingKeys.add(key);
}
}
// ========== 第二步:处理数据 ==========
// 用于跟踪Excel文件内已处理的唯一键
Set<String> processedKeys = new HashSet<>();
// 分类数据
for (int i = 0; i < excelList.size(); i++) {
CcdiStaffFmyRelationExcel excel = excelList.get(i);
@@ -67,17 +96,22 @@ public class CcdiStaffFmyRelationImportServiceImpl implements ICcdiStaffFmyRelat
throw new RuntimeException(String.format("员工[%s]的关系人[%s]在导入文件中重复", excel.getPersonId(), excel.getRelationCertNo()));
}
// 检查是否在数据库中已存在(批量校验的结果)
if (existingKeys.contains(uniqueKey)) {
throw new RuntimeException(String.format("员工[%s]的关系人[%s]已存在", excel.getPersonId(), excel.getRelationCertNo()));
}
// 从已验证和转换过的addDTO创建relation对象
CcdiStaffFmyRelation relation = new CcdiStaffFmyRelation();
BeanUtils.copyProperties(excel, relation);
BeanUtils.copyProperties(addDTO, relation);
relation.setCreatedBy(userName);
relation.setUpdatedBy(userName);
relation.setIsEmpFamily(true);
relation.setIsCustFamily(false);
relation.setDataSource("IMPORT");
if (relation.getStatus() == null) {
// 显式设置状态为有效status=1
relation.setStatus(1);
}
newRecords.add(relation);
processedKeys.add(uniqueKey);
@@ -230,8 +264,14 @@ public class CcdiStaffFmyRelationImportServiceImpl implements ICcdiStaffFmyRelat
}
// 验证性别值(如果提供)
if (StringUtils.isNotEmpty(addDTO.getGender()) && !addDTO.getGender().matches("^[MFO]$")) {
throw new RuntimeException("性别只能是M、F或O");
if (StringUtils.isNotEmpty(addDTO.getGender())) {
try {
// 使用GenderEnum进行标准化支持中文男、女、其他和英文M、F、O
String normalizedGender = GenderEnum.normalize(addDTO.getGender());
addDTO.setGender(normalizedGender);
} catch (IllegalArgumentException e) {
throw new RuntimeException("性别只能是:男、女、其他 或 M、F、O");
}
}
}
}

View File

@@ -148,4 +148,21 @@
</foreach>
</insert>
<!-- 批量查询已存在的员工亲属关系(用于导入唯一性校验) -->
<select id="selectExistingRelations" resultType="com.ruoyi.ccdi.domain.CcdiStaffFmyRelation">
SELECT
id, person_id, relation_type, relation_name, gender, birth_date,
relation_cert_type, relation_cert_no
FROM ccdi_staff_fmy_relation
WHERE is_emp_family = 1
AND person_id IN
<foreach collection="personIds" item="personId" open="(" separator="," close=")">
#{personId}
</foreach>
AND relation_cert_no IN
<foreach collection="relationCertNos" item="relationCertNo" open="(" separator="," close=")">
#{relationCertNo}
</foreach>
</select>
</mapper>

View File

@@ -1,273 +0,0 @@
#!/bin/bash
# 员工信息表重命名数据库验证脚本
# 验证 ccdi_base_staff 表及相关配置
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# 测试结果统计
TOTAL_TESTS=0
PASSED_TESTS=0
FAILED_TESTS=0
# 数据库连接配置
DB_HOST="localhost"
DB_USER="root"
DB_PASS="root"
DB_NAME="discipline_prelim_check"
# 日志函数
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
# 测试函数
test_case() {
TOTAL_TESTS=$((TOTAL_TESTS + 1))
local test_name=$1
local test_function=$2
echo -e "\n========================================"
echo "测试 ${TOTAL_TESTS}: $test_name"
echo "========================================"
$test_function
local result=$?
if [ $result -eq 0 ]; then
PASSED_TESTS=$((PASSED_TESTS + 1))
log_info "✓ 测试通过"
else
FAILED_TESTS=$((FAILED_TESTS + 1))
log_error "✗ 测试失败"
fi
}
# 测试 1: 验证表存在
test_table_exists() {
log_info "验证 ccdi_base_staff 表是否存在..."
local result=$(mysql -h $DB_HOST -u $DB_USER -p$DB_PASS -D $DB_NAME -e "
SELECT COUNT(*) as cnt
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = '$DB_NAME'
AND TABLE_NAME = 'ccdi_base_staff';" 2>/dev/null | tail -1)
if [ "$result" = "1" ]; then
log_info "表 ccdi_base_staff 存在"
return 0
else
log_error "表 ccdi_base_staff 不存在"
return 1
fi
}
# 测试 2: 验证 staff_id 主键字段
test_staff_id_field() {
log_info "验证 staff_id 字段存在且为主键..."
local result=$(mysql -h $DB_HOST -u $DB_USER -p$DB_PASS -D $DB_NAME -e "
SELECT COUNT(*) as cnt
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = '$DB_NAME'
AND TABLE_NAME = 'ccdi_base_staff'
AND COLUMN_NAME = 'staff_id';" 2>/dev/null | tail -1)
if [ "$result" = "1" ]; then
log_info "staff_id 字段存在"
# 验证是否为主键
local pk_result=$(mysql -h $DB_HOST -u $DB_USER -p$DB_PASS -D $DB_NAME -e "
SELECT COUNT(*) as cnt
FROM information_schema.KEY_COLUMN_USAGE
WHERE TABLE_SCHEMA = '$DB_NAME'
AND TABLE_NAME = 'ccdi_base_staff'
AND COLUMN_NAME = 'staff_id'
AND CONSTRAINT_NAME = 'PRIMARY';" 2>/dev/null | tail -1)
if [ "$pk_result" = "1" ]; then
log_info "staff_id 是主键"
return 0
else
log_error "staff_id 不是主键"
return 1
fi
else
log_error "staff_id 字段不存在"
return 1
fi
}
# 测试 3: 验证 teller_no 字段已删除
test_teller_no_removed() {
log_info "验证 teller_no 字段已删除..."
local result=$(mysql -h $DB_HOST -u $DB_USER -p$DB_PASS -D $DB_NAME -e "
SELECT COUNT(*) as cnt
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = '$DB_NAME'
AND TABLE_NAME = 'ccdi_base_staff'
AND COLUMN_NAME = 'teller_no';" 2>/dev/null | tail -1)
if [ "$result" = "0" ]; then
log_info "teller_no 字段已删除"
return 0
else
log_error "teller_no 字段仍然存在"
return 1
fi
}
# 测试 4: 验证其他必需字段存在
test_required_fields() {
log_info "验证必需字段存在..."
local fields=("name" "dept_id" "id_card" "phone" "hire_date" "status")
local all_exist=1
for field in "${fields[@]}"; do
local result=$(mysql -h $DB_HOST -u $DB_USER -p$DB_PASS -D $DB_NAME -e "
SELECT COUNT(*) as cnt
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = '$DB_NAME'
AND TABLE_NAME = 'ccdi_base_staff'
AND COLUMN_NAME = '$field';" 2>/dev/null | tail -1)
if [ "$result" = "1" ]; then
log_info "$field 字段存在"
else
log_error "$field 字段不存在"
all_exist=0
fi
done
return $all_exist
}
# 测试 5: 验证菜单权限已更新
test_menu_permissions() {
log_info "验证菜单权限已更新为 baseStaff..."
local result=$(mysql -h $DB_HOST -u $DB_USER -p$DB_PASS -D $DB_NAME -e "
SELECT COUNT(*) as cnt
FROM sys_menu
WHERE perms LIKE 'ccdi:baseStaff:%';" 2>/dev/null | tail -1)
if [ "$result" -ge 7 ]; then
log_info "找到 $result 个 baseStaff 权限配置"
# 列出所有权限
mysql -h $DB_HOST -u $DB_USER -p$DB_PASS -D $DB_NAME -e "
SELECT menu_name, perms
FROM sys_menu
WHERE perms LIKE 'ccdi:baseStaff:%'
ORDER BY menu_id;" 2>/dev/null
return 0
else
log_error "baseStaff 权限配置不足,期望至少 7 个,实际 $result"
return 1
fi
}
# 测试 6: 验证旧权限已删除
test_old_permissions_removed() {
log_info "验证旧的 employee 权限已删除..."
local result=$(mysql -h $DB_HOST -u $DB_USER -p$DB_PASS -D $DB_NAME -e "
SELECT COUNT(*) as cnt
FROM sys_menu
WHERE perms LIKE 'ccdi:employee:%';" 2>/dev/null | tail -1)
if [ "$result" = "0" ]; then
log_info "旧的 employee 权限已全部删除"
return 0
else
log_warn "仍有 $result 个 employee 权限未删除"
mysql -h $DB_HOST -u $DB_USER -p$DB_PASS -D $DB_NAME -e "
SELECT menu_name, perms
FROM sys_menu
WHERE perms LIKE 'ccdi:employee:%';" 2>/dev/null
return 1
fi
}
# 测试 7: 显示表结构
show_table_structure() {
log_info "显示 ccdi_base_staff 表结构..."
mysql -h $DB_HOST -u $DB_USER -p$DB_PASS -D $DB_NAME -e "
DESC ccdi_base_staff;" 2>/dev/null
return 0
}
# 测试 8: 显示索引
show_table_indexes() {
log_info "显示 ccdi_base_staff 表索引..."
mysql -h $DB_HOST -u $DB_USER -p$DB_PASS -D $DB_NAME -e "
SHOW INDEX FROM ccdi_base_staff;" 2>/dev/null
return 0
}
# 主测试流程
main() {
echo "=========================================="
echo "员工信息表重命名 - 数据库验证"
echo "=========================================="
echo "数据库: $DB_NAME"
echo "=========================================="
# 运行测试
test_case "验证表存在" "test_table_exists"
test_case "验证 staff_id 主键字段" "test_staff_id_field"
test_case "验证 teller_no 字段已删除" "test_teller_no_removed"
test_case "验证必需字段存在" "test_required_fields"
test_case "验证菜单权限已更新" "test_menu_permissions"
test_case "验证旧权限已删除" "test_old_permissions_removed"
# 显示表信息
echo -e "\n=========================================="
echo "表结构详情"
echo "=========================================="
show_table_structure
echo -e "\n=========================================="
echo "表索引详情"
echo "=========================================="
show_table_indexes
# 输出测试结果
echo -e "\n=========================================="
echo "测试结果汇总"
echo "=========================================="
echo -e "总测试数: ${TOTAL_TESTS}"
echo -e "${GREEN}通过: ${PASSED_TESTS}${NC}"
echo -e "${RED}失败: ${FAILED_TESTS}${NC}"
echo "=========================================="
if [ $FAILED_TESTS -eq 0 ]; then
log_info "所有测试通过!"
exit 0
else
log_error "存在失败的测试"
exit 1
fi
}
# 执行测试
main

View File

@@ -1,273 +0,0 @@
#!/bin/bash
# 员工信息表重命名数据库验证脚本
# 验证 ccdi_base_staff 表及相关配置
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# 测试结果统计
TOTAL_TESTS=0
PASSED_TESTS=0
FAILED_TESTS=0
# 数据库连接配置
DB_HOST="localhost"
DB_USER="root"
DB_PASS="root"
DB_NAME="ccdi"
# 日志函数
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
# 测试函数
test_case() {
TOTAL_TESTS=$((TOTAL_TESTS + 1))
local test_name=$1
local test_function=$2
echo -e "\n========================================"
echo "测试 ${TOTAL_TESTS}: $test_name"
echo "========================================"
$test_function
local result=$?
if [ $result -eq 0 ]; then
PASSED_TESTS=$((PASSED_TESTS + 1))
log_info "✓ 测试通过"
else
FAILED_TESTS=$((FAILED_TESTS + 1))
log_error "✗ 测试失败"
fi
}
# 测试 1: 验证表存在
test_table_exists() {
log_info "验证 ccdi_base_staff 表是否存在..."
local result=$(mysql -h $DB_HOST -u $DB_USER -p$DB_PASS -D $DB_NAME -e "
SELECT COUNT(*) as cnt
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = '$DB_NAME'
AND TABLE_NAME = 'ccdi_base_staff';" 2>/dev/null | tail -1)
if [ "$result" = "1" ]; then
log_info "表 ccdi_base_staff 存在"
return 0
else
log_error "表 ccdi_base_staff 不存在"
return 1
fi
}
# 测试 2: 验证 staff_id 主键字段
test_staff_id_field() {
log_info "验证 staff_id 字段存在且为主键..."
local result=$(mysql -h $DB_HOST -u $DB_USER -p$DB_PASS -D $DB_NAME -e "
SELECT COUNT(*) as cnt
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = '$DB_NAME'
AND TABLE_NAME = 'ccdi_base_staff'
AND COLUMN_NAME = 'staff_id';" 2>/dev/null | tail -1)
if [ "$result" = "1" ]; then
log_info "staff_id 字段存在"
# 验证是否为主键
local pk_result=$(mysql -h $DB_HOST -u $DB_USER -p$DB_PASS -D $DB_NAME -e "
SELECT COUNT(*) as cnt
FROM information_schema.KEY_COLUMN_USAGE
WHERE TABLE_SCHEMA = '$DB_NAME'
AND TABLE_NAME = 'ccdi_base_staff'
AND COLUMN_NAME = 'staff_id'
AND CONSTRAINT_NAME = 'PRIMARY';" 2>/dev/null | tail -1)
if [ "$pk_result" = "1" ]; then
log_info "staff_id 是主键"
return 0
else
log_error "staff_id 不是主键"
return 1
fi
else
log_error "staff_id 字段不存在"
return 1
fi
}
# 测试 3: 验证 teller_no 字段已删除
test_teller_no_removed() {
log_info "验证 teller_no 字段已删除..."
local result=$(mysql -h $DB_HOST -u $DB_USER -p$DB_PASS -D $DB_NAME -e "
SELECT COUNT(*) as cnt
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = '$DB_NAME'
AND TABLE_NAME = 'ccdi_base_staff'
AND COLUMN_NAME = 'teller_no';" 2>/dev/null | tail -1)
if [ "$result" = "0" ]; then
log_info "teller_no 字段已删除"
return 0
else
log_error "teller_no 字段仍然存在"
return 1
fi
}
# 测试 4: 验证其他必需字段存在
test_required_fields() {
log_info "验证必需字段存在..."
local fields=("name" "dept_id" "id_card" "phone" "hire_date" "status")
local all_exist=1
for field in "${fields[@]}"; do
local result=$(mysql -h $DB_HOST -u $DB_USER -p$DB_PASS -D $DB_NAME -e "
SELECT COUNT(*) as cnt
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = '$DB_NAME'
AND TABLE_NAME = 'ccdi_base_staff'
AND COLUMN_NAME = '$field';" 2>/dev/null | tail -1)
if [ "$result" = "1" ]; then
log_info "$field 字段存在"
else
log_error "$field 字段不存在"
all_exist=0
fi
done
return $all_exist
}
# 测试 5: 验证菜单权限已更新
test_menu_permissions() {
log_info "验证菜单权限已更新为 baseStaff..."
local result=$(mysql -h $DB_HOST -u $DB_USER -p$DB_PASS -D $DB_NAME -e "
SELECT COUNT(*) as cnt
FROM sys_menu
WHERE perms LIKE 'ccdi:baseStaff:%';" 2>/dev/null | tail -1)
if [ "$result" -ge 7 ]; then
log_info "找到 $result 个 baseStaff 权限配置"
# 列出所有权限
mysql -h $DB_HOST -u $DB_USER -p$DB_PASS -D $DB_NAME -e "
SELECT menu_name, perms
FROM sys_menu
WHERE perms LIKE 'ccdi:baseStaff:%'
ORDER BY menu_id;" 2>/dev/null
return 0
else
log_error "baseStaff 权限配置不足,期望至少 7 个,实际 $result"
return 1
fi
}
# 测试 6: 验证旧权限已删除
test_old_permissions_removed() {
log_info "验证旧的 employee 权限已删除..."
local result=$(mysql -h $DB_HOST -u $DB_USER -p$DB_PASS -D $DB_NAME -e "
SELECT COUNT(*) as cnt
FROM sys_menu
WHERE perms LIKE 'ccdi:employee:%';" 2>/dev/null | tail -1)
if [ "$result" = "0" ]; then
log_info "旧的 employee 权限已全部删除"
return 0
else
log_warn "仍有 $result 个 employee 权限未删除"
mysql -h $DB_HOST -u $DB_USER -p$DB_PASS -D $DB_NAME -e "
SELECT menu_name, perms
FROM sys_menu
WHERE perms LIKE 'ccdi:employee:%';" 2>/dev/null
return 1
fi
}
# 测试 7: 显示表结构
show_table_structure() {
log_info "显示 ccdi_base_staff 表结构..."
mysql -h $DB_HOST -u $DB_USER -p$DB_PASS -D $DB_NAME -e "
DESC ccdi_base_staff;" 2>/dev/null
return 0
}
# 测试 8: 显示索引
show_table_indexes() {
log_info "显示 ccdi_base_staff 表索引..."
mysql -h $DB_HOST -u $DB_USER -p$DB_PASS -D $DB_NAME -e "
SHOW INDEX FROM ccdi_base_staff;" 2>/dev/null
return 0
}
# 主测试流程
main() {
echo "=========================================="
echo "员工信息表重命名 - 数据库验证"
echo "=========================================="
echo "数据库: $DB_NAME"
echo "=========================================="
# 运行测试
test_case "验证表存在" "test_table_exists"
test_case "验证 staff_id 主键字段" "test_staff_id_field"
test_case "验证 teller_no 字段已删除" "test_teller_no_removed"
test_case "验证必需字段存在" "test_required_fields"
test_case "验证菜单权限已更新" "test_menu_permissions"
test_case "验证旧权限已删除" "test_old_permissions_removed"
# 显示表信息
echo -e "\n=========================================="
echo "表结构详情"
echo "=========================================="
show_table_structure
echo -e "\n=========================================="
echo "表索引详情"
echo "=========================================="
show_table_indexes
# 输出测试结果
echo -e "\n=========================================="
echo "测试结果汇总"
echo "=========================================="
echo -e "总测试数: ${TOTAL_TESTS}"
echo -e "${GREEN}通过: ${PASSED_TESTS}${NC}"
echo -e "${RED}失败: ${FAILED_TESTS}${NC}"
echo "=========================================="
if [ $FAILED_TESTS -eq 0 ]; then
log_info "所有测试通过!"
exit 0
else
log_error "存在失败的测试"
exit 1
fi
}
# 执行测试
main

View File

@@ -1,224 +0,0 @@
#!/bin/bash
# 员工信息表重命名测试脚本
# 测试 ccdi_base_staff 表及相关功能
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# 测试结果统计
TOTAL_TESTS=0
PASSED_TESTS=0
FAILED_TESTS=0
# 日志函数
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
# 测试函数
test_case() {
TOTAL_TESTS=$((TOTAL_TESTS + 1))
local test_name=$1
local test_command=$2
local expected_result=$3
echo -e "\n========================================"
echo "测试 ${TOTAL_TESTS}: $test_name"
echo "========================================"
eval "$test_command"
local actual_result=$?
if [ "$actual_result" -eq "$expected_result" ]; then
PASSED_TESTS=$((PASSED_TESTS + 1))
log_info "✓ 测试通过"
else
FAILED_TESTS=$((FAILED_TESTS + 1))
log_error "✗ 测试失败 (期望: $expected_result, 实际: $actual_result)"
fi
}
# 获取 Token
get_token() {
log_info "获取登录 Token..."
TOKEN=$(curl -s -X POST "http://localhost:8080/login/test" \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin123"}' | jq -r '.data.token // empty')
if [ -z "$TOKEN" ] || [ "$TOKEN" = "null" ]; then
log_error "无法获取 Token"
exit 1
fi
log_info "Token 获取成功: ${TOKEN:0:20}..."
}
# 测试 1: 验证表结构
test_table_structure() {
log_info "验证 ccdi_base_staff 表结构..."
local result=$(mysql -h localhost -u root -proot -D discipline_prelim_check -e "
SELECT COUNT(*) as cnt
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'discipline_prelim_check'
AND TABLE_NAME = 'ccdi_base_staff'
AND COLUMN_NAME = 'staff_id';" 2>/dev/null | tail -1)
if [ "$result" -eq 1 ]; then
return 0
else
return 1
fi
}
# 测试 2: 验证字段不存在
test_field_not_exist() {
log_info "验证 teller_no 字段已删除..."
local result=$(mysql -h localhost -u root -proot -D discipline_prelim_check -e "
SELECT COUNT(*) as cnt
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'discipline_prelim_check'
AND TABLE_NAME = 'ccdi_base_staff'
AND COLUMN_NAME = 'teller_no';" 2>/dev/null | tail -1)
if [ "$result" -eq 0 ]; then
return 0
else
return 1
fi
}
# 测试 3: 列表查询接口
test_list_api() {
log_info "测试列表查询接口..."
local response=$(curl -s -X GET "http://localhost:8080/ccdi/baseStaff/list?pageNum=1&pageSize=10" \
-H "Authorization: Bearer $TOKEN")
local code=$(echo $response | jq -r '.code // empty')
if [ "$code" = "200" ]; then
log_info "响应数据: $(echo $response | jq -r '.data.total // 0') 条记录"
return 0
else
log_error "API 响应码: $code"
log_error "响应内容: $response"
return 1
fi
}
# 测试 4: 详情查询接口
test_query_api() {
log_info "测试详情查询接口..."
local response=$(curl -s -X GET "http://localhost:8080/ccdi/baseStaff/1000001" \
-H "Authorization: Bearer $TOKEN")
local code=$(echo $response | jq -r '.code // empty')
if [ "$code" = "200" ] || [ "$code" = "500" ]; then
# 200 表示成功500 表示数据不存在也是正常的
return 0
else
log_error "API 响应码: $code"
return 1
fi
}
# 测试 5: 新增接口
test_add_api() {
log_info "测试新增接口..."
local response=$(curl -s -X POST "http://localhost:8080/ccdi/baseStaff" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"staffId": 9999999,
"name": "测试员工",
"deptId": 100,
"idCard": "110101199001011234",
"phone": "13800138000",
"status": "0"
}')
local code=$(echo $response | jq -r '.code // empty')
if [ "$code" = "200" ]; then
log_info "新增成功,清理测试数据..."
curl -s -X DELETE "http://localhost:8080/ccdi/baseStaff/9999999" \
-H "Authorization: Bearer $TOKEN" > /dev/null
return 0
else
log_error "新增失败,响应码: $code"
return 1
fi
}
# 测试 6: 权限验证
test_permission() {
log_info "测试权限字符验证..."
local result=$(mysql -h localhost -u root -proot -D discipline_prelim_check -e "
SELECT COUNT(*) as cnt
FROM sys_menu
WHERE perms LIKE 'ccdi:baseStaff:%';" 2>/dev/null | tail -1)
if [ "$result" -ge 7 ]; then
log_info "找到 $result 个权限配置"
return 0
else
log_error "权限配置不足,期望至少 7 个,实际 $result"
return 1
fi
}
# 主测试流程
main() {
echo "=========================================="
echo "员工信息表重命名测试"
echo "=========================================="
# 获取 Token
get_token
# 运行测试
test_case "验证表结构存在 staff_id 字段" "test_table_structure" 0
test_case "验证 teller_no 字段已删除" "test_field_not_exist" 0
test_case "验证权限配置" "test_permission" 0
test_case "测试列表查询接口" "test_list_api" 0
test_case "测试详情查询接口" "test_query_api" 0
test_case "测试新增接口" "test_add_api" 0
# 输出测试结果
echo -e "\n=========================================="
echo "测试结果汇总"
echo "=========================================="
echo -e "总测试数: ${TOTAL_TESTS}"
echo -e "${GREEN}通过: ${PASSED_TESTS}${NC}"
echo -e "${RED}失败: ${FAILED_TESTS}${NC}"
echo "=========================================="
if [ $FAILED_TESTS -eq 0 ]; then
log_info "所有测试通过!"
exit 0
else
log_error "存在失败的测试"
exit 1
fi
}
# 执行测试
main

View File

@@ -1,4 +0,0 @@
{
"msg": "\r\n### Error querying database. Cause: java.sql.SQLSyntaxErrorException: Unknown column 'r.contact_phone' in 'field list'\r\n### The error may exist in file [D:\\ccdi\\ccdi\\ruoyi-ccdi\\target\\classes\\mapper\\ccdi\\CcdiStaffFmyRelationMapper.xml]\r\n### The error may involve defaultParameterMap\r\n### The error occurred while setting parameters\r\n### SQL: SELECT r.id, r.person_id, s.name as person_name, r.relation_type, r.relation_name, r.gender, r.relation_cert_type, r.relation_cert_no, r.contact_phone, r.address, r.occupation, r.work_unit, r.effective_date, r.expiry_date, r.status, r.remark, r.data_source, r.is_emp_family, r.is_cust_family, r.created_by, r.create_time, r.updated_by, r.update_time FROM ccdi_staff_fmy_relation r LEFT JOIN ccdi_base_staff s ON r.person_id = s.person_id WHERE r.is_emp_family = 1 ORDER BY r.create_time DESC LIMIT ?\r\n### Cause: java.sql.SQLSyntaxErrorException: Unknown column 'r.contact_phone' in 'field list'\n; bad SQL grammar []",
"code": 500
}

View File

@@ -1,264 +0,0 @@
"""
员工亲属关系功能测试脚本
测试员工身份证号字段改造后的功能
"""
import requests
import json
BASE_URL = "http://localhost:8080"
# 登录获取 token
def login():
url = f"{BASE_URL}/login/test"
data = {
"username": "admin",
"password": "admin123"
}
response = requests.post(url, json=data)
result = response.json()
if result.get("code") == 200:
token = result.get("token")
print("✓ 登录成功")
return token
else:
print(f"✗ 登录失败: {result.get('msg')}")
return None
# 获取请求头
def get_headers(token):
return {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
}
# 测试1: 查询员工列表(用于下拉选择)
def test_list_staff():
print("\n【测试1】查询员工列表")
url = f"{BASE_URL}/ccdi/baseStaff/list"
params = {
"pageNum": 1,
"pageSize": 10
}
response = requests.get(url, params=params, headers=get_headers(token))
result = response.json()
if result.get("code") == 200:
rows = result.get("rows", [])
print(f"✓ 查询成功,共 {len(rows)} 条员工记录")
if rows:
print(f" 示例: {rows[0].get('name')} - {rows[0].get('idCard')}")
return rows[0].get("idCard") # 返回第一个员工的身份证号
else:
print(" 警告: 暂无员工数据")
return None
else:
print(f"✗ 查询失败: {result.get('msg')}")
return None
# 测试2: 根据身份证号搜索员工
def test_search_staff(keyword):
print(f"\n【测试2】根据身份证号搜索员工: {keyword}")
url = f"{BASE_URL}/ccdi/baseStaff/list"
params = {
"idCard": keyword,
"pageNum": 1,
"pageSize": 10
}
response = requests.get(url, params=params, headers=get_headers(token))
result = response.json()
if result.get("code") == 200:
rows = result.get("rows", [])
print(f"✓ 搜索成功,找到 {len(rows)} 条记录")
for row in rows[:3]: # 只显示前3条
print(f" - {row.get('name')} - {row.get('idCard')}")
return rows
else:
print(f"✗ 搜索失败: {result.get('msg')}")
return []
# 测试3: 查询已有亲属关系(避免重复插入)
def test_get_existing_relation(person_id):
print(f"\n【测试3】查询已有员工亲属关系")
url = f"{BASE_URL}/ccdi/staffFmyRelation/list"
params = {
"personId": person_id,
"pageNum": 1,
"pageSize": 1
}
response = requests.get(url, params=params, headers=get_headers(token))
result = response.json()
if result.get("code") == 200:
rows = result.get("rows", [])
if rows:
relation_id = rows[0].get("id")
print(f"✓ 找到已有记录, ID: {relation_id}")
return relation_id
else:
print(" 未找到已有记录,准备新增测试数据")
return None
else:
print(f"✗ 查询失败: {result.get('msg')}")
return None
# 测试4: 新增员工亲属关系(如果没有现有数据)
def test_add_relation(person_id):
print(f"\n【测试4】新增员工亲属关系")
url = f"{BASE_URL}/ccdi/staffFmyRelation"
import random
random_suffix = random.randint(10000, 99999)
data = {
"personId": person_id,
"relationType": "01", # 配偶
"relationName": "测试亲属",
"gender": "M",
"relationCertType": "01", # 身份证
"relationCertNo": f"11010119900101{random_suffix}", # 随机生成避免重复
"status": 1
}
response = requests.post(url, json=data, headers=get_headers(token))
result = response.json()
if result.get("code") == 200:
# 若依框架新增接口返回的是 "操作成功" 消息,没有返回ID
# 需要通过查询列表来获取新增的记录
print(f"✓ 新增成功")
# 查询列表获取最新记录的ID
list_url = f"{BASE_URL}/ccdi/staffFmyRelation/list"
list_params = {
"personId": person_id,
"pageNum": 1,
"pageSize": 1
}
list_response = requests.get(list_url, params=list_params, headers=get_headers(token))
list_result = list_response.json()
if list_result.get("rows"):
relation_id = list_result.get("rows")[0].get("id")
print(f" 获取到记录ID: {relation_id}")
return relation_id
return None
else:
print(f"✗ 新增失败: {result.get('msg')}")
return None
# 测试5: 查询员工亲属关系列表
def test_list_relations(person_id):
print(f"\n【测试5】查询员工亲属关系列表")
url = f"{BASE_URL}/ccdi/staffFmyRelation/list"
params = {
"personId": person_id,
"pageNum": 1,
"pageSize": 10
}
response = requests.get(url, params=params, headers=get_headers(token))
result = response.json()
if result.get("code") == 200:
rows = result.get("rows", [])
total = result.get("total", 0)
print(f"✓ 查询成功,共 {total} 条记录")
for row in rows:
print(f" - {row.get('personName')}({row.get('personId')}) 的{row.get('relationType')} - {row.get('relationName')}")
return rows
else:
print(f"✗ 查询失败: {result.get('msg')}")
return []
# 测试6: 查询亲属关系详情
def test_get_relation_detail(relation_id):
print(f"\n【测试6】查询亲属关系详情: ID={relation_id}")
url = f"{BASE_URL}/ccdi/staffFmyRelation/{relation_id}"
response = requests.get(url, headers=get_headers(token))
result = response.json()
if result.get("code") == 200:
data = result.get("data")
print(f"✓ 查询成功")
print(f" 员工: {data.get('personName')}({data.get('personId')})")
print(f" 关系: {data.get('relationType')} - {data.get('relationName')}")
print(f" 状态: {'有效' if data.get('status') == 1 else '无效'}")
return data
else:
print(f"✗ 查询失败: {result.get('msg')}")
return None
# 测试7: 编辑员工亲属关系(只修改非身份证号字段)
def test_update_relation(relation_id):
print(f"\n【测试7】编辑员工亲属关系: ID={relation_id}")
url = f"{BASE_URL}/ccdi/staffFmyRelation"
data = {
"id": relation_id,
"relationName": "测试亲属(已修改)",
"mobilePhone1": "13800138000",
"status": 1
}
response = requests.put(url, json=data, headers=get_headers(token))
result = response.json()
if result.get("code") == 200:
print(f"✓ 修改成功")
return True
else:
print(f"✗ 修改失败: {result.get('msg')}")
return False
# 测试8: 删除员工亲属关系
def test_delete_relation(relation_id):
print(f"\n【测试8】删除员工亲属关系: ID={relation_id}")
url = f"{BASE_URL}/ccdi/staffFmyRelation/{relation_id}"
response = requests.delete(url, headers=get_headers(token))
result = response.json()
if result.get("code") == 200:
print(f"✓ 删除成功")
return True
else:
print(f"✗ 删除失败: {result.get('msg')}")
return False
# 主测试流程
def main():
global token
print("=" * 60)
print("员工亲属关系功能测试")
print("=" * 60)
# 登录
token = login()
if not token:
return
# 测试1: 查询员工列表
person_id = test_list_staff()
if not person_id:
print("\n提示: 请先在系统中添加员工数据")
return
# 测试2: 搜索员工
test_search_staff(person_id[:6]) # 使用身份证号前6位搜索
# 测试3: 查询已有亲属关系
relation_id = test_get_existing_relation(person_id)
# 如果没有已有记录,则新增
if not relation_id:
relation_id = test_add_relation(person_id)
if not relation_id:
print("\n提示: 无法获取测试记录ID,跳过后续测试")
return
# 测试5: 查询亲属关系列表
test_list_relations(person_id)
# 测试6: 查询详情
test_get_relation_detail(relation_id)
# 测试7: 编辑亲属关系
test_update_relation(relation_id)
# 测试8: 再次查看详情(验证修改)
test_get_relation_detail(relation_id)
# 清理测试数据(仅限新增的数据)
print("\n【清理】测试结束(保留现有数据)")
print("\n" + "=" * 60)
print("测试完成!")
print("=" * 60)
if __name__ == "__main__":
main()

View File

@@ -1,105 +0,0 @@
import requests
import json
# 配置
BASE_URL = "http://localhost:8080"
LOGIN_URL = f"{BASE_URL}/login/test"
LIST_URL = f"{BASE_URL}/ccdi/staffFmyRelation/list"
# 测试账号
test_user = {
"username": "admin",
"password": "admin123"
}
def test_fix():
"""测试修复是否成功"""
print("=" * 60)
print("开始测试员工家庭关系接口修复")
print("=" * 60)
# Step 1: 获取token
print("\n[1/2] 正在登录获取token...")
headers = {
"Content-Type": "application/json"
}
login_response = requests.post(LOGIN_URL, json=test_user, headers=headers)
if login_response.status_code != 200:
print(f"❌ 登录失败: {login_response.status_code}")
print(login_response.text)
return False
login_data = login_response.json()
if login_data.get("code") != 200:
print(f"❌ 登录失败: {login_data.get('msg')}")
return False
token = login_data.get("token")
print(f"✅ 登录成功获取到token: {token[:20]}...")
# Step 2: 调用分页查询接口
print("\n[2/2] 正在测试分页查询接口...")
headers = {
"Authorization": f"Bearer {token}"
}
params = {
"pageNum": 1,
"pageSize": 10,
"isEmpFamily": 1
}
list_response = requests.get(LIST_URL, params=params, headers=headers)
print(f"\n响应状态码: {list_response.status_code}")
if list_response.status_code != 200:
print(f"❌ 接口调用失败")
print(list_response.text)
return False
result = list_response.json()
# 保存完整响应
with open("test_result.json", "w", encoding="utf-8") as f:
json.dump(result, f, ensure_ascii=False, indent=2)
print(f"\n完整响应已保存到 test_result.json")
if result.get("code") == 200:
rows = result.get("rows", [])
total = result.get("total", 0)
print(f"✅ 接口调用成功!")
print(f" - 数据总数: {total}")
print(f" - 当前页记录数: {len(rows)}")
if rows:
print(f"\n示例数据 (第一条):")
first_row = rows[0]
for key, value in first_row.items():
if key not in ["createTime", "updateTime"]:
print(f" {key}: {value}")
print("\n" + "=" * 60)
print("✅ 修复验证成功!数据库字段映射问题已解决")
print("=" * 60)
return True
else:
print(f"❌ 接口返回错误: {result.get('msg')}")
print(f"错误详情: {result}")
return False
if __name__ == "__main__":
try:
success = test_fix()
exit(0 if success else 1)
except Exception as e:
print(f"\n❌ 测试过程中发生异常: {str(e)}")
import traceback
traceback.print_exc()
exit(1)