# 员工实体关系 - 前后端字段匹配验证报告

**生成时间**: 2026-02-09
**验证范围**: 新增/编辑接口字段匹配

---

## 一、新增接口字段匹配

### 前端Form字段（index.vue）

```javascript
form: {
  id: null,                  // 编辑时使用
  personId: null,            // ✅ 必填
  relationPersonPost: null,  // ✅ 可选
  socialCreditCode: null,    // ✅ 必填
  enterpriseName: null,      // ✅ 必填
  status: '1',               // ✅ 默认有效
  remark: null               // ✅ 可选
}
```

### 后端AddDTO字段

```java
@NotNull private Long id;                          // ❌ 新增时不传递
@NotBlank private String personId;                 // ✅ 必填
@Size(max=100) private String relationPersonPost; // ✅ 可选
@NotBlank private String socialCreditCode;         // ✅ 必填
@NotBlank private String enterpriseName;           // ✅ 必填
private Integer status;                            // ✅ 可选，后端默认1
private String remark;                             // ✅ 可选
@Size(max=50) private String dataSource;          // ❌ 新增时不传递，后端设置
private Integer isEmployee;                        // ❌ 新增时不传递，后端设置
private Integer isEmpFamily;                       // ❌ 新增时不传递，后端设置
private Integer isCustomer;                        // ❌ 新增时不传递，后端设置
private Integer isCustFamily;                      // ❌ 新增时不传递，后端设置
```

### 匹配状态

| 字段                 | 前端    | 后端          | 匹配 | 说明              |
|--------------------|-------|-------------|----|-----------------|
| id                 | ❌ 不传递 | @NotNull    | ⚠️ | 新增时不传递，由数据库自增   |
| personId           | ✅     | ✅ @NotBlank | ✅  | 完全匹配            |
| relationPersonPost | ✅     | ✅ @Size     | ✅  | 完全匹配            |
| socialCreditCode   | ✅     | ✅ @NotBlank | ✅  | 完全匹配            |
| enterpriseName     | ✅     | ✅ @NotBlank | ✅  | 完全匹配            |
| status             | ✅ '1' | ✅ 可选        | ✅  | 前端传递，后端有默认值     |
| remark             | ✅     | ✅ 可选        | ✅  | 完全匹配            |
| dataSource         | ❌     | ✅ @Size     | ✅  | 后端自动设置为"MANUAL" |
| isEmployee         | ❌     | ✅           | ✅  | 后端自动设置为0        |
| isEmpFamily        | ❌     | ✅           | ✅  | 后端自动设置为1        |
| isCustomer         | ❌     | ✅           | ✅  | 后端自动设置为0        |
| isCustFamily       | ❌     | ✅           | ✅  | 后端自动设置为0        |

**结论**: ✅ 新增接口字段匹配正确，系统字段由后端自动设置

---

## 二、编辑接口字段匹配

### 前端Form字段（编辑时）

```javascript
form: {
  id: xxx,                  // ✅ 从接口获取
  personId: xxx,            // ✅ 从接口获取
  relationPersonPost: xxx,  // ✅ 可编辑
  socialCreditCode: xxx,    // ✅ 可编辑
  enterpriseName: xxx,      // ✅ 可编辑
  status: xxx,              // ✅ 可编辑（仅编辑时显示）
  remark: xxx               // ✅ 可编辑
}
```

### 后端EditDTO字段

```java
@NotNull private Long id;                          // ✅ 必填
@NotBlank private String personId;                 // ✅ 必填
@Size(max=100) private String relationPersonPost; // ✅ 可选
@NotBlank private String socialCreditCode;         // ✅ 必填
@NotBlank private String enterpriseName;           // ✅ 必填
private Integer status;                            // ✅ 可选
private String remark;                             // ✅ 可选
@Size(max=50) private String dataSource;          // ⚠️ 前端不传递
private Integer isEmployee;                        // ⚠️ 前端不传递
private Integer isEmpFamily;                       // ⚠️ 前端不传递
private Integer isCustomer;                        // ⚠️ 前端不传递
private Integer isCustFamily;                      // ⚠️ 前端不传递
```

### 后端更新逻辑（已修复）

```java
@Override
@Transactional
public int updateRelation(CcdiStaffEnterpriseRelationEditDTO editDTO) {
    // 使用LambdaUpdateWrapper只更新非null字段
    LambdaUpdateWrapper<CcdiStaffEnterpriseRelation> updateWrapper = new LambdaUpdateWrapper<>();
    updateWrapper.eq(CcdiStaffEnterpriseRelation::getId, editDTO.getId());

    // 只更新前端可编辑的字段
    updateWrapper.set(editDTO.getPersonId() != null, CcdiStaffEnterpriseRelation::getPersonId, editDTO.getPersonId());
    updateWrapper.set(editDTO.getRelationPersonPost() != null, CcdiStaffEnterpriseRelation::getRelationPersonPost, editDTO.getRelationPersonPost());
    updateWrapper.set(editDTO.getSocialCreditCode() != null, CcdiStaffEnterpriseRelation::getSocialCreditCode, editDTO.getSocialCreditCode());
    updateWrapper.set(editDTO.getEnterpriseName() != null, CcdiStaffEnterpriseRelation::getEnterpriseName, editDTO.getEnterpriseName());
    updateWrapper.set(editDTO.getStatus() != null, CcdiStaffEnterpriseRelation::getStatus, editDTO.getStatus());
    updateWrapper.set(editDTO.getRemark() != null, CcdiStaffEnterpriseRelation::getRemark, editDTO.getRemark());

    // 系统字段不更新，保留原值
    // - dataSource, isEmployee, isEmpFamily, isCustomer, isCustFamily

    return relationMapper.update(null, updateWrapper);
}
```

### 匹配状态

| 字段                 | 前端传递   | 后端处理        | 匹配 | 说明        |
|--------------------|--------|-------------|----|-----------|
| id                 | ✅      | ✅ @NotNull  | ✅  | 必填，用于定位记录 |
| personId           | ✅      | ✅ @NotBlank | ✅  | 完全匹配      |
| relationPersonPost | ✅      | ✅ @Size     | ✅  | 完全匹配      |
| socialCreditCode   | ✅      | ✅ @NotBlank | ✅  | 完全匹配      |
| enterpriseName     | ✅      | ✅ @NotBlank | ✅  | 完全匹配      |
| status             | ✅      | ✅ 可选        | ✅  | 完全匹配      |
| remark             | ✅      | ✅ 可选        | ✅  | 完全匹配      |
| dataSource         | ❌ null | ✅ 保留原值      | ✅  | 系统字段，不更新  |
| isEmployee         | ❌ null | ✅ 保留原值      | ✅  | 系统字段，不更新  |
| isEmpFamily        | ❌ null | ✅ 保留原值      | ✅  | 系统字段，不更新  |
| isCustomer         | ❌ null | ✅ 保留原值      | ✅  | 系统字段，不更新  |
| isCustFamily       | ❌ null | ✅ 保留原值      | ✅  | 系统字段，不更新  |

**结论**: ✅ 编辑接口字段匹配正确，使用LambdaUpdateWrapper保护系统字段

---

## 三、修复前的问题

### 问题1：使用BeanUtils.copyProperties + updateById

```java
// 修复前的问题代码
CcdiStaffEnterpriseRelation relation = new CcdiStaffEnterpriseRelation();
BeanUtils.copyProperties(editDTO, relation);
int result = relationMapper.updateById(relation);
```

**问题描述**:

- `BeanUtils.copyProperties` 会复制所有字段，包括null值
- `updateById` 会更新所有字段，将系统字段覆盖为null
- 导致 `dataSource`, `isEmployee`, `isEmpFamily` 等字段丢失

**影响**:

- 编辑后数据来源变为null
- 编辑后员工标识字段变为null
- 数据完整性受损

### 问题2：前端状态字段类型

```javascript
// 前端传递字符串
status: '1'  // 字符串
```

```java
// 后端期望Integer
private Integer status;  // 整数
```

**解决方案**: Spring自动进行类型转换 ✅

---

## 四、修复后的改进

### 改进1：使用LambdaUpdateWrapper

```java
// 修复后的正确代码
LambdaUpdateWrapper<CcdiStaffEnterpriseRelation> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(CcdiStaffEnterpriseRelation::getId, editDTO.getId());

// 只更新非null字段
updateWrapper.set(editDTO.getPersonId() != null, CcdiStaffEnterpriseRelation::getPersonId, editDTO.getPersonId());
// ... 其他字段

int result = relationMapper.update(null, updateWrapper);
```

**优点**:

- ✅ 只更新非null字段
- ✅ 保护系统字段不被覆盖
- ✅ 符合业务逻辑（系统字段由后端控制）

### 改进2：字段名统一

| 原字段名                    | 统一后                  | 位置      |
|-------------------------|----------------------|---------|
| `idCard`                | `personId`           | 前端 → 后端 |
| `enterpriseUscc`        | `socialCreditCode`   | 前端 → 后端 |
| `positionInEnterprise`  | `relationPersonPost` | 前端 → 后端 |
| `supplementDescription` | `remark`             | 前端 → 后端 |

---

## 五、测试验证建议

### 新增测试

1. 提交完整必填字段，验证保存成功
2. 验证系统字段自动设置：
    - status = 1
    - dataSource = "MANUAL"
    - isEmployee = 0
    - isEmpFamily = 1
    - isCustomer = 0
    - isCustFamily = 0

### 编辑测试

1. 修改可编辑字段，验证更新成功
2. 验证系统字段保持不变：
    - dataSource 不变
    - isEmployee 不变
    - isEmpFamily 不变
    - isCustomer 不变
    - isCustFamily 不变

### 边界测试

1. 编辑时清空可选字段（relationPersonPost, remark），验证更新为空字符串而非null
2. 编辑时修改状态，验证状态正确更新

---

## 六、总结

| 项目         | 状态    | 说明                          |
|------------|-------|-----------------------------|
| **新增接口**   | ✅ 正常  | 字段匹配正确，系统字段自动设置             |
| **编辑接口**   | ✅ 已修复 | 使用LambdaUpdateWrapper保护系统字段 |
| **字段名统一**  | ✅ 已完成 | 前后端字段名完全一致                  |
| **默认值设置**  | ✅ 正常  | 新增时status默认为1（有效）           |
| **系统字段保护** | ✅ 已修复 | 编辑时不会覆盖系统字段                 |

**修复文件**: `CcdiStaffEnterpriseRelationServiceImpl.java`
**修复内容**: 将 `BeanUtils.copyProperties + updateById` 改为 `LambdaUpdateWrapper` 条件更新
