# 中介黑名单管理模块实施计划

> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

**Goal:** 实现个人中介和实体中介的完整CRUD功能，包括统一列表查询、Excel导入导出，使用SQL UNION联合查询实现高效分页。

**Architecture:** 采用分层架构（Controller -> Service -> Mapper ->
Database），个人中介存储在ccdi_biz_intermediary表，实体中介存储在ccdi_enterprise_base_info表（通过risk_level='1' AND
ent_source='INTERMEDIARY'筛选）。使用MyBatis Plus进行CRUD操作，自定义XML实现UNION联合查询。

**Tech Stack:** Spring Boot 3.5.8, MyBatis Plus 3.5.10, EasyExcel (带字典下拉框), MySQL 8.2.0, SpringDoc 2.8.14

---

## Task 1: 创建个人中介Entity实体类

**Files:**

- Create: `ruoyi-info-collection/src/main/java/com/ruoyi/ccdi/domain/CcdiBizIntermediary.java`

**Step 1: 创建CcdiBizIntermediary实体类**

```java
package com.ruoyi.ccdi.domain;

import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;

import java.io.Serial;
import java.io.Serializable;
import java.util.Date;

/**
 * 个人中介对象 ccdi_biz_intermediary
 *
 * @author ruoyi
 * @date 2026-02-04
 */
@Data
@TableName("ccdi_biz_intermediary")
public class CcdiBizIntermediary implements Serializable {

    @Serial
    private static final long serialVersionUID = 1L;

    /** 人员ID */
    @TableId(type = IdType.ASSIGN_UUID)
    private String bizId;

    /** 人员类型，中介、职业背债人、房产中介等 */
    private String personType;

    /** 人员子类型 */
    private String personSubType;

    /** 关系类型，如：配偶、子女、父母、兄弟姐妹等 */
    private String relationType;

    /** 姓名 */
    private String name;

    /** 性别 */
    private String gender;

    /** 证件类型 */
    private String idType;

    /** 证件号码 */
    private String personId;

    /** 手机号码 */
    private String mobile;

    /** 微信号 */
    private String wechatNo;

    /** 联系地址 */
    private String contactAddress;

    /** 所在公司 */
    private String company;

    /** 企业统一信用码 */
    private String socialCreditCode;

    /** 职位 */
    private String position;

    /** 关联人员ID */
    private String relatedNumId;

    /** 关联关系 */
    private String relationType;

    /** 数据来源，MANUAL:手动录入, SYSTEM:系统同步, IMPORT:批量导入, API:接口获取 */
    private String dataSource;

    /** 备注信息 */
    private String remark;

    /** 记录创建人 */
    @TableField(fill = FieldFill.INSERT)
    private String createdBy;

    /** 记录创建时间 */
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;

    /** 记录更新人 */
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private String updatedBy;

    /** 记录更新时间 */
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;
}
```

**Step 2: 提交代码**

```bash
git add ruoyi-info-collection/src/main/java/com/ruoyi/ccdi/domain/CcdiBizIntermediary.java
git commit -m "feat: 添加个人中介实体类CcdiBizIntermediary"
```

---

## Task 2: 创建实体中介Entity实体类

**Files:**

- Create: `ruoyi-info-collection/src/main/java/com/ruoyi/ccdi/domain/CcdiEnterpriseBaseInfo.java`

**Step 1: 创建CcdiEnterpriseBaseInfo实体类**

```java
package com.ruoyi.ccdi.domain;

import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;

import java.io.Serial;
import java.io.Serializable;
import java.util.Date;

/**
 * 企业主体信息对象 ccdi_enterprise_base_info
 *
 * @author ruoyi
 * @date 2026-02-04
 */
@Data
@TableName("ccdi_enterprise_base_info")
public class CcdiEnterpriseBaseInfo implements Serializable {

    @Serial
    private static final long serialVersionUID = 1L;

    /** 统一社会信用代码，员工企业关联关系表的外键 */
    @TableId(type = IdType.INPUT)
    private String socialCreditCode;

    /** 企业名称 */
    private String enterpriseName;

    /** 企业类型,有限责任公司、股份有限公司、合伙企业、个体工商户、外资企业等 */
    private String enterpriseType;

    /** 企业性质,国企、民企、外企、合资、其他 */
    private String enterpriseNature;

    /** 行业分类 */
    private String industryClass;

    /** 所属行业 */
    private String industryName;

    /** 成立日期 */
    private Date establishDate;

    /** 注册地址 */
    private String registerAddress;

    /** 法定代表人 */
    private String legalRepresentative;

    /** 法定代表人证件类型 */
    private String legalCertType;

    /** 法定代表人证件号码 */
    private String legalCertNo;

    /** 股东1 */
    private String shareholder1;

    /** 股东2 */
    private String shareholder2;

    /** 股东3 */
    private String shareholder3;

    /** 股东4 */
    private String shareholder4;

    /** 股东5 */
    private String shareholder5;

    /** 经营状态 */
    private String status;

    /** 创建人 */
    @TableField(fill = FieldFill.INSERT)
    private String createdBy;

    /** 创建时间 */
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;

    /** 更新人 */
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private String updatedBy;

    /** 更新时间 */
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;

    /** 数据来源,MANUAL:手动录入, SYSTEM:系统同步, API:接口获取, IMPORT:批量导入 */
    private String dataSource;

    /** 风险等级：1-高风险, 2-中风险, 3-低风险 */
    private String riskLevel;

    /** 企业来源：GENERAL-一般企业, EMP_RELATION-员工关系人, CREDIT_CUSTOMER-信贷客户, INTERMEDIARY-中介, BOTH-兼有 */
    private String entSource;
}
```

**Step 2: 提交代码**

```bash
git add ruoyi-info-collection/src/main/java/com/ruoyi/ccdi/domain/CcdiEnterpriseBaseInfo.java
git commit -m "feat: 添加实体中介实体类CcdiEnterpriseBaseInfo"
```

---

## Task 3: 创建个人中介DTO

**Files:**

- Create: `ruoyi-info-collection/src/main/java/com/ruoyi/ccdi/domain/dto/CcdiIntermediaryPersonAddDTO.java`
- Create: `ruoyi-info-collection/src/main/java/com/ruoyi/ccdi/domain/dto/CcdiIntermediaryPersonEditDTO.java`

**Step 1: 创建个人中介新增DTO**

```java
package com.ruoyi.ccdi.domain.dto;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;

import java.io.Serial;
import java.io.Serializable;

/**
 * 个人中介新增DTO
 *
 * @author ruoyi
 * @date 2026-02-04
 */
@Data
@Schema(description = "个人中介新增DTO")
public class CcdiIntermediaryPersonAddDTO implements Serializable {

    @Serial
    private static final long serialVersionUID = 1L;

    /** 姓名 */
    @Schema(description = "姓名")
    @NotBlank(message = "姓名不能为空")
    @Size(max = 100, message = "姓名长度不能超过100个字符")
    private String name;

    /** 人员类型 */
    @Schema(description = "人员类型")
    private String personType;

    /** 人员子类型 */
    @Schema(description = "人员子类型")
    private String personSubType;

    /** 关系类型 */
    @Schema(description = "关系类型")
    private String relationType;

    /** 性别 */
    @Schema(description = "性别")
    private String gender;

    /** 证件类型 */
    @Schema(description = "证件类型")
    private String idType;

    /** 证件号码 */
    @Schema(description = "证件号码")
    @NotBlank(message = "证件号码不能为空")
    @Size(max = 50, message = "证件号码长度不能超过50个字符")
    private String personId;

    /** 手机号码 */
    @Schema(description = "手机号码")
    @Size(max = 20, message = "手机号码长度不能超过20个字符")
    private String mobile;

    /** 微信号 */
    @Schema(description = "微信号")
    @Size(max = 50, message = "微信号长度不能超过50个字符")
    private String wechatNo;

    /** 联系地址 */
    @Schema(description = "联系地址")
    @Size(max = 200, message = "联系地址长度不能超过200个字符")
    private String contactAddress;

    /** 所在公司 */
    @Schema(description = "所在公司")
    @Size(max = 200, message = "所在公司长度不能超过200个字符")
    private String company;

    /** 企业统一信用码 */
    @Schema(description = "企业统一信用码")
    @Size(max = 50, message = "企业统一信用码长度不能超过50个字符")
    private String socialCreditCode;

    /** 职位 */
    @Schema(description = "职位")
    @Size(max = 100, message = "职位长度不能超过100个字符")
    private String position;

    /** 关联人员ID */
    @Schema(description = "关联人员ID")
    @Size(max = 50, message = "关联人员ID长度不能超过50个字符")
    private String relatedNumId;

    /** 关联关系 */
    @Schema(description = "关联关系")
    @Size(max = 50, message = "关联关系长度不能超过50个字符")
    private String relation;

    /** 备注 */
    @Schema(description = "备注")
    @Size(max = 500, message = "备注长度不能超过500个字符")
    private String remark;
}
```

**Step 2: 创建个人中介修改DTO**

```java
package com.ruoyi.ccdi.domain.dto;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;

import java.io.Serial;
import java.io.Serializable;

/**
 * 个人中介修改DTO
 *
 * @author ruoyi
 * @date 2026-02-04
 */
@Data
@Schema(description = "个人中介修改DTO")
public class CcdiIntermediaryPersonEditDTO implements Serializable {

    @Serial
    private static final long serialVersionUID = 1L;

    /** 人员ID */
    @Schema(description = "人员ID")
    @NotBlank(message = "人员ID不能为空")
    private String bizId;

    /** 姓名 */
    @Schema(description = "姓名")
    @NotBlank(message = "姓名不能为空")
    @Size(max = 100, message = "姓名长度不能超过100个字符")
    private String name;

    /** 人员类型 */
    @Schema(description = "人员类型")
    private String personType;

    /** 人员子类型 */
    @Schema(description = "人员子类型")
    private String personSubType;

    /** 关系类型 */
    @Schema(description = "关系类型")
    private String relationType;

    /** 性别 */
    @Schema(description = "性别")
    private String gender;

    /** 证件类型 */
    @Schema(description = "证件类型")
    private String idType;

    /** 证件号码 */
    @Schema(description = "证件号码")
    @Size(max = 50, message = "证件号码长度不能超过50个字符")
    private String personId;

    /** 手机号码 */
    @Schema(description = "手机号码")
    @Size(max = 20, message = "手机号码长度不能超过20个字符")
    private String mobile;

    /** 微信号 */
    @Schema(description = "微信号")
    @Size(max = 50, message = "微信号长度不能超过50个字符")
    private String wechatNo;

    /** 联系地址 */
    @Schema(description = "联系地址")
    @Size(max = 200, message = "联系地址长度不能超过200个字符")
    private String contactAddress;

    /** 所在公司 */
    @Schema(description = "所在公司")
    @Size(max = 200, message = "所在公司长度不能超过200个字符")
    private String company;

    /** 企业统一信用码 */
    @Schema(description = "企业统一信用码")
    @Size(max = 50, message = "企业统一信用码长度不能超过50个字符")
    private String socialCreditCode;

    /** 职位 */
    @Schema(description = "职位")
    @Size(max = 100, message = "职位长度不能超过100个字符")
    private String position;

    /** 关联人员ID */
    @Schema(description = "关联人员ID")
    @Size(max = 50, message = "关联人员ID长度不能超过50个字符")
    private String relatedNumId;

    /** 关联关系 */
    @Schema(description = "关联关系")
    @Size(max = 50, message = "关联关系长度不能超过50个字符")
    private String relation;

    /** 备注 */
    @Schema(description = "备注")
    @Size(max = 500, message = "备注长度不能超过500个字符")
    private String remark;
}
```

**Step 3: 提交代码**

```bash
git add ruoyi-info-collection/src/main/java/com/ruoyi/ccdi/domain/dto/CcdiIntermediaryPersonAddDTO.java
git add ruoyi-info-collection/src/main/java/com/ruoyi/ccdi/domain/dto/CcdiIntermediaryPersonEditDTO.java
git commit -m "feat: 添加个人中介DTO类"
```

---

## Task 4: 创建实体中介DTO

**Files:**

- Create: `ruoyi-info-collection/src/main/java/com/ruoyi/ccdi/domain/dto/CcdiIntermediaryEntityAddDTO.java`
- Create: `ruoyi-info-collection/src/main/java/com/ruoyi/ccdi/domain/dto/CcdiIntermediaryEntityEditDTO.java`

**Step 1: 创建实体中介新增DTO**

```java
package com.ruoyi.ccdi.domain.dto;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import lombok.Data;

import java.io.Serial;
import java.io.Serializable;
import java.util.Date;

/**
 * 实体中介新增DTO
 *
 * @author ruoyi
 * @date 2026-02-04
 */
@Data
@Schema(description = "实体中介新增DTO")
public class CcdiIntermediaryEntityAddDTO implements Serializable {

    @Serial
    private static final long serialVersionUID = 1L;

    /** 机构名称 */
    @Schema(description = "机构名称")
    @NotBlank(message = "机构名称不能为空")
    @Size(max = 200, message = "机构名称长度不能超过200个字符")
    private String enterpriseName;

    /** 统一社会信用代码 */
    @Schema(description = "统一社会信用代码")
    @Size(max = 50, message = "统一社会信用代码长度不能超过50个字符")
    private String socialCreditCode;

    /** 主体类型 */
    @Schema(description = "主体类型")
    @Size(max = 50, message = "主体类型长度不能超过50个字符")
    private String enterpriseType;

    /** 企业性质 */
    @Schema(description = "企业性质")
    @Size(max = 50, message = "企业性质长度不能超过50个字符")
    private String enterpriseNature;

    /** 行业分类 */
    @Schema(description = "行业分类")
    @Size(max = 100, message = "行业分类长度不能超过100个字符")
    private String industryClass;

    /** 所属行业 */
    @Schema(description = "所属行业")
    @Size(max = 100, message = "所属行业长度不能超过100个字符")
    private String industryName;

    /** 成立日期 */
    @Schema(description = "成立日期")
    private Date establishDate;

    /** 注册地址 */
    @Schema(description = "注册地址")
    @Size(max = 500, message = "注册地址长度不能超过500个字符")
    private String registerAddress;

    /** 法定代表人 */
    @Schema(description = "法定代表人")
    @Size(max = 100, message = "法定代表人长度不能超过100个字符")
    private String legalRepresentative;

    /** 法定代表人证件类型 */
    @Schema(description = "法定代表人证件类型")
    @Size(max = 50, message = "法定代表人证件类型长度不能超过50个字符")
    private String legalCertType;

    /** 法定代表人证件号码 */
    @Schema(description = "法定代表人证件号码")
    @Size(max = 50, message = "法定代表人证件号码长度不能超过50个字符")
    private String legalCertNo;

    /** 股东1 */
    @Schema(description = "股东1")
    @Size(max = 100, message = "股东1长度不能超过100个字符")
    private String shareholder1;

    /** 股东2 */
    @Schema(description = "股东2")
    @Size(max = 100, message = "股东2长度不能超过100个字符")
    private String shareholder2;

    /** 股东3 */
    @Schema(description = "股东3")
    @Size(max = 100, message = "股东3长度不能超过100个字符")
    private String shareholder3;

    /** 股东4 */
    @Schema(description = "股东4")
    @Size(max = 100, message = "股东4长度不能超过100个字符")
    private String shareholder4;

    /** 股东5 */
    @Schema(description = "股东5")
    @Size(max = 100, message = "股东5长度不能超过100个字符")
    private String shareholder5;

    /** 备注 */
    @Schema(description = "备注")
    @Size(max = 500, message = "备注长度不能超过500个字符")
    private String remark;
}
```

**Step 2: 创建实体中介修改DTO**

```java
package com.ruoyi.ccdi.domain.dto;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import lombok.Data;

import java.io.Serial;
import java.io.Serializable;
import java.util.Date;

/**
 * 实体中介修改DTO
 *
 * @author ruoyi
 * @date 2026-02-04
 */
@Data
@Schema(description = "实体中介修改DTO")
public class CcdiIntermediaryEntityEditDTO implements Serializable {

    @Serial
    private static final long serialVersionUID = 1L;

    /** 统一社会信用代码 */
    @Schema(description = "统一社会信用代码")
    @NotBlank(message = "统一社会信用代码不能为空")
    private String socialCreditCode;

    /** 机构名称 */
    @Schema(description = "机构名称")
    @NotBlank(message = "机构名称不能为空")
    @Size(max = 200, message = "机构名称长度不能超过200个字符")
    private String enterpriseName;

    /** 主体类型 */
    @Schema(description = "主体类型")
    @Size(max = 50, message = "主体类型长度不能超过50个字符")
    private String enterpriseType;

    /** 企业性质 */
    @Schema(description = "企业性质")
    @Size(max = 50, message = "企业性质长度不能超过50个字符")
    private String enterpriseNature;

    /** 行业分类 */
    @Schema(description = "行业分类")
    @Size(max = 100, message = "行业分类长度不能超过100个字符")
    private String industryClass;

    /** 所属行业 */
    @Schema(description = "所属行业")
    @Size(max = 100, message = "所属行业长度不能超过100个字符")
    private String industryName;

    /** 成立日期 */
    @Schema(description = "成立日期")
    private Date establishDate;

    /** 注册地址 */
    @Schema(description = "注册地址")
    @Size(max = 500, message = "注册地址长度不能超过500个字符")
    private String registerAddress;

    /** 法定代表人 */
    @Schema(description = "法定代表人")
    @Size(max = 100, message = "法定代表人长度不能超过100个字符")
    private String legalRepresentative;

    /** 法定代表人证件类型 */
    @Schema(description = "法定代表人证件类型")
    @Size(max = 50, message = "法定代表人证件类型长度不能超过50个字符")
    private String legalCertType;

    /** 法定代表人证件号码 */
    @Schema(description = "法定代表人证件号码")
    @Size(max = 50, message = "法定代表人证件号码长度不能超过50个字符")
    private String legalCertNo;

    /** 股东1 */
    @Schema(description = "股东1")
    @Size(max = 100, message = "股东1长度不能超过100个字符")
    private String shareholder1;

    /** 股东2 */
    @Schema(description = "股东2")
    @Size(max = 100, message = "股东2长度不能超过100个字符")
    private String shareholder2;

    /** 股东3 */
    @Schema(description = "股东3")
    @Size(max = 100, message = "股东3长度不能超过100个字符")
    private String shareholder3;

    /** 股东4 */
    @Schema(description = "股东4")
    @Size(max = 100, message = "股东4长度不能超过100个字符")
    private String shareholder4;

    /** 股东5 */
    @Schema(description = "股东5")
    @Size(max = 100, message = "股东5长度不能超过100个字符")
    private String shareholder5;

    /** 备注 */
    @Schema(description = "备注")
    @Size(max = 500, message = "备注长度不能超过500个字符")
    private String remark;
}
```

**Step 3: 提交代码**

```bash
git add ruoyi-info-collection/src/main/java/com/ruoyi/ccdi/domain/dto/CcdiIntermediaryEntityAddDTO.java
git add ruoyi-info-collection/src/main/java/com/ruoyi/ccdi/domain/dto/CcdiIntermediaryEntityEditDTO.java
git commit -m "feat: 添加实体中介DTO类"
```

---

## Task 5: 创建查询DTO和统一VO

**Files:**

- Create: `ruoyi-info-collection/src/main/java/com/ruoyi/ccdi/domain/dto/CcdiIntermediaryQueryDTO.java`
- Create: `ruoyi-info-collection/src/main/java/com/ruoyi/ccdi/domain/vo/CcdiIntermediaryVO.java`
- Create: `ruoyi-info-collection/src/main/java/com/ruoyi/ccdi/domain/vo/CcdiIntermediaryPersonDetailVO.java`
- Create: `ruoyi-info-collection/src/main/java/com/ruoyi/ccdi/domain/vo/CcdiIntermediaryEntityDetailVO.java`

**Step 1: 创建查询DTO**

```java
package com.ruoyi.ccdi.domain.dto;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

import java.io.Serial;
import java.io.Serializable;

/**
 * 中介查询DTO
 *
 * @author ruoyi
 * @date 2026-02-04
 */
@Data
@Schema(description = "中介查询DTO")
public class CcdiIntermediaryQueryDTO implements Serializable {

    @Serial
    private static final long serialVersionUID = 1L;

    /** 姓名/机构名称 */
    @Schema(description = "姓名/机构名称")
    private String name;

    /** 证件号/统一社会信用代码 */
    @Schema(description = "证件号/统一社会信用代码")
    private String certificateNo;

    /** 中介类型（1=个人, 2=实体） */
    @Schema(description = "中介类型（1=个人, 2=实体）")
    private String intermediaryType;
}
```

**Step 2: 创建统一列表VO**

```java
package com.ruoyi.ccdi.domain.vo;

import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

import java.io.Serial;
import java.io.Serializable;
import java.util.Date;

/**
 * 中介统一列表VO
 *
 * @author ruoyi
 * @date 2026-02-04
 */
@Data
@Schema(description = "中介统一列表VO")
public class CcdiIntermediaryVO implements Serializable {

    @Serial
    private static final long serialVersionUID = 1L;

    /** ID (bizId 或 socialCreditCode) */
    @Schema(description = "ID")
    private String id;

    /** 姓名/机构名称 */
    @Schema(description = "姓名/机构名称")
    private String name;

    /** 证件号/统一社会信用代码 */
    @Schema(description = "证件号/统一社会信用代码")
    private String certificateNo;

    /** 中介类型（1=个人, 2=实体） */
    @Schema(description = "中介类型（1=个人, 2=实体）")
    private String intermediaryType;

    /** 人员类型/实体 */
    @Schema(description = "人员类型")
    private String personType;

    /** 公司 */
    @Schema(description = "公司")
    private String company;

    /** 数据来源 */
    @Schema(description = "数据来源")
    private String dataSource;

    /** 创建时间 */
    @Schema(description = "创建时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date createTime;
}
```

**Step 3: 创建个人中介详情VO**

```java
package com.ruoyi.ccdi.domain.vo;

import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

import java.io.Serial;
import java.io.Serializable;
import java.util.Date;

/**
 * 个人中介详情VO
 *
 * @author ruoyi
 * @date 2026-02-04
 */
@Data
@Schema(description = "个人中介详情VO")
public class CcdiIntermediaryPersonDetailVO implements Serializable {

    @Serial
    private static final long serialVersionUID = 1L;

    @Schema(description = "人员ID")
    private String bizId;

    @Schema(description = "姓名")
    private String name;

    @Schema(description = "人员类型")
    private String personType;

    @Schema(description = "人员子类型")
    private String personSubType;

    @Schema(description = "性别")
    private String gender;

    @Schema(description = "证件类型")
    private String idType;

    @Schema(description = "证件号码")
    private String personId;

    @Schema(description = "手机号码")
    private String mobile;

    @Schema(description = "微信号")
    private String wechatNo;

    @Schema(description = "联系地址")
    private String contactAddress;

    @Schema(description = "所在公司")
    private String company;

    @Schema(description = "职位")
    private String position;

    @Schema(description = "关联人员ID")
    private String relatedNumId;

    @Schema(description = "关联关系")
    private String relationType;

    @Schema(description = "数据来源")
    private String dataSource;

    @Schema(description = "备注")
    private String remark;

    @Schema(description = "创建时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date createTime;
}
```

**Step 4: 创建实体中介详情VO**

```java
package com.ruoyi.ccdi.domain.vo;

import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

import java.io.Serial;
import java.io.Serializable;
import java.util.Date;

/**
 * 实体中介详情VO
 *
 * @author ruoyi
 * @date 2026-02-04
 */
@Data
@Schema(description = "实体中介详情VO")
public class CcdiIntermediaryEntityDetailVO implements Serializable {

    @Serial
    private static final long serialVersionUID = 1L;

    @Schema(description = "统一社会信用代码")
    private String socialCreditCode;

    @Schema(description = "企业名称")
    private String enterpriseName;

    @Schema(description = "企业类型")
    private String enterpriseType;

    @Schema(description = "企业性质")
    private String enterpriseNature;

    @Schema(description = "行业分类")
    private String industryClass;

    @Schema(description = "所属行业")
    private String industryName;

    @Schema(description = "成立日期")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date establishDate;

    @Schema(description = "注册地址")
    private String registerAddress;

    @Schema(description = "法定代表人")
    private String legalRepresentative;

    @Schema(description = "法定代表人证件类型")
    private String legalCertType;

    @Schema(description = "法定代表人证件号码")
    private String legalCertNo;

    @Schema(description = "股东1")
    private String shareholder1;

    @Schema(description = "股东2")
    private String shareholder2;

    @Schema(description = "股东3")
    private String shareholder3;

    @Schema(description = "股东4")
    private String shareholder4;

    @Schema(description = "股东5")
    private String shareholder5;

    @Schema(description = "风险等级")
    private String riskLevel;

    @Schema(description = "企业来源")
    private String entSource;

    @Schema(description = "数据来源")
    private String dataSource;

    @Schema(description = "备注")
    private String remark;

    @Schema(description = "创建时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date createTime;
}
```

**Step 5: 提交代码**

```bash
git add ruoyi-info-collection/src/main/java/com/ruoyi/ccdi/domain/dto/CcdiIntermediaryQueryDTO.java
git add ruoyi-info-collection/src/main/java/com/ruoyi/ccdi/domain/vo/CcdiIntermediaryVO.java
git add ruoyi-info-collection/src/main/java/com/ruoyi/ccdi/domain/vo/CcdiIntermediaryPersonDetailVO.java
git add ruoyi-info-collection/src/main/java/com/ruoyi/ccdi/domain/vo/CcdiIntermediaryEntityDetailVO.java
git commit -m "feat: 添加中介查询DTO和VO类"
```

---

## Task 6: 创建Mapper接口

**Files:**

- Create: `ruoyi-info-collection/src/main/java/com/ruoyi/ccdi/mapper/CcdiBizIntermediaryMapper.java`
- Create: `ruoyi-info-collection/src/main/java/com/ruoyi/ccdi/mapper/CcdiEnterpriseBaseInfoMapper.java`
- Create: `ruoyi-info-collection/src/main/resources/mapper/ccdi/CcdiIntermediaryMapper.xml`

**Step 1: 创建个人中介Mapper接口**

```java
package com.ruoyi.ccdi.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.ccdi.domain.CcdiBizIntermediary;
import org.apache.ibatis.annotations.Mapper;

/**
 * 个人中介Mapper接口
 *
 * @author ruoyi
 * @date 2026-02-04
 */
@Mapper
public interface CcdiBizIntermediaryMapper extends BaseMapper<CcdiBizIntermediary> {

}
```

**Step 2: 创建实体中介Mapper接口**

```java
package com.ruoyi.ccdi.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.ccdi.domain.CcdiEnterpriseBaseInfo;
import org.apache.ibatis.annotations.Mapper;

/**
 * 实体中介Mapper接口
 *
 * @author ruoyi
 * @date 2026-02-04
 */
@Mapper
public interface CcdiEnterpriseBaseInfoMapper extends BaseMapper<CcdiEnterpriseBaseInfo> {

}
```

**Step 3: 创建联合查询XML映射文件**

```xml
<?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.CcdiBizIntermediaryMapper">

    <!-- 统一列表联合查询 -->
    <select id="selectIntermediaryList" resultType="com.ruoyi.ccdi.domain.vo.CcdiIntermediaryVO">
        <!-- 查询个人中介 -->
        SELECT
            biz_id as id,
            name,
            person_id as certificate_no,
            '1' as intermediary_type,
            person_type,
            company,
            data_source,
            create_time
        FROM ccdi_biz_intermediary
        WHERE person_type = '中介'
        <if test="intermediaryType == null or intermediaryType == '1'">
            <if test="name != null and name != ''">
                AND name LIKE CONCAT('%', #{name}, '%')
            </if>
            <if test="certificateNo != null and certificateNo != ''">
                AND person_id = #{certificateNo}
            </if>
        </if>

        UNION ALL

        <!-- 查询实体中介 -->
        SELECT
            social_credit_code as id,
            enterprise_name as name,
            social_credit_code as certificate_no,
            '2' as intermediary_type,
            '实体' as person_type,
            enterprise_name as company,
            data_source,
            create_time
        FROM ccdi_enterprise_base_info
        WHERE risk_level = '1' AND ent_source = 'INTERMEDIARY'
        <if test="intermediaryType == null or intermediaryType == '2'">
            <if test="name != null and name != ''">
                AND enterprise_name LIKE CONCAT('%', #{name}, '%')
            </if>
            <if test="certificateNo != null and certificateNo != ''">
                AND social_credit_code = #{certificateNo}
            </if>
        </if>

        ORDER BY create_time DESC
    </select>

</mapper>
```

**Step 4: 提交代码**

```bash
git add ruoyi-info-collection/src/main/java/com/ruoyi/ccdi/mapper/CcdiBizIntermediaryMapper.java
git add ruoyi-info-collection/src/main/java/com/ruoyi/ccdi/mapper/CcdiEnterpriseBaseInfoMapper.java
git add ruoyi-info-collection/src/main/resources/mapper/ccdi/CcdiIntermediaryMapper.xml
git commit -m "feat: 添加中介Mapper接口和XML映射"
```

---

## Task 7: 创建Service接口和实现类

**Files:**

- Create: `ruoyi-info-collection/src/main/java/com/ruoyi/ccdi/service/ICcdiIntermediaryService.java`
- Create: `ruoyi-info-collection/src/main/java/com/ruoyi/ccdi/service/impl/CcdiIntermediaryServiceImpl.java`

**Step 1: 创建Service接口**

```java
package com.ruoyi.ccdi.service;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.ccdi.domain.dto.*;
import com.ruoyi.ccdi.domain.vo.CcdiIntermediaryEntityDetailVO;
import com.ruoyi.ccdi.domain.vo.CcdiIntermediaryPersonDetailVO;
import com.ruoyi.ccdi.domain.vo.CcdiIntermediaryVO;

/**
 * 中介Service接口
 *
 * @author ruoyi
 * @date 2026-02-04
 */
public interface ICcdiIntermediaryService {

    /**
     * 分页查询中介列表（UNION联合查询）
     */
    Page<CcdiIntermediaryVO> selectIntermediaryPage(Page<CcdiIntermediaryVO> page, CcdiIntermediaryQueryDTO queryDTO);

    /**
     * 查询个人中介详情
     */
    CcdiIntermediaryPersonDetailVO selectIntermediaryPersonDetail(String bizId);

    /**
     * 查询实体中介详情
     */
    CcdiIntermediaryEntityDetailVO selectIntermediaryEntityDetail(String socialCreditCode);

    /**
     * 新增个人中介
     */
    int insertIntermediaryPerson(CcdiIntermediaryPersonAddDTO addDTO);

    /**
     * 修改个人中介
     */
    int updateIntermediaryPerson(CcdiIntermediaryPersonEditDTO editDTO);

    /**
     * 新增实体中介
     */
    int insertIntermediaryEntity(CcdiIntermediaryEntityAddDTO addDTO);

    /**
     * 修改实体中介
     */
    int updateIntermediaryEntity(CcdiIntermediaryEntityEditDTO editDTO);

    /**
     * 批量删除中介
     */
    int deleteIntermediaryByIds(String[] ids);

    /**
     * 校验个人中介证件号唯一性
     */
    boolean checkPersonIdUnique(String personId, String bizId);

    /**
     * 校验实体中介信用代码唯一性
     */
    boolean checkSocialCreditCodeUnique(String socialCreditCode, String excludeId);
}
```

**Step 2: 创建Service实现类**

```java
package com.ruoyi.ccdi.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.ccdi.domain.CcdiBizIntermediary;
import com.ruoyi.ccdi.domain.CcdiEnterpriseBaseInfo;
import com.ruoyi.ccdi.domain.dto.*;
import com.ruoyi.ccdi.domain.vo.CcdiIntermediaryEntityDetailVO;
import com.ruoyi.ccdi.domain.vo.CcdiIntermediaryPersonDetailVO;
import com.ruoyi.ccdi.domain.vo.CcdiIntermediaryVO;
import com.ruoyi.ccdi.mapper.CcdiBizIntermediaryMapper;
import com.ruoyi.ccdi.mapper.CcdiEnterpriseBaseInfoMapper;
import com.ruoyi.ccdi.service.ICcdiIntermediaryService;
import com.ruoyi.common.utils.StringUtils;
import jakarta.annotation.Resource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;

/**
 * 中介Service实现
 *
 * @author ruoyi
 * @date 2026-02-04
 */
@Service
public class CcdiIntermediaryServiceImpl implements ICcdiIntermediaryService {

    @Resource
    private CcdiBizIntermediaryMapper personMapper;

    @Resource
    private CcdiEnterpriseBaseInfoMapper entityMapper;

    @Resource
    private SqlSessionFactory sqlSessionFactory;

    /**
     * 分页查询中介列表（UNION联合查询）
     */
    @Override
    public Page<CcdiIntermediaryVO> selectIntermediaryPage(Page<CcdiIntermediaryVO> page, CcdiIntermediaryQueryDTO queryDTO) {
        // 使用MyBatis原生查询实现UNION分页
        var sqlSession = sqlSessionFactory.openSession();
        try {
            var countSql = buildCountQuery(queryDTO);
            var dataSql = buildDataQuery(queryDTO);

            // 查询总数
            var countStatement = sqlSession.getConnection().prepareStatement(countSql);
            var countResult = countStatement.executeQuery();
            int total = 0;
            if (countResult.next()) {
                total = countResult.getInt(1);
            }

            // 设置总数
            page.setTotal(total);

            // 查询分页数据
            var offset = (page.getCurrent() - 1) * page.getSize();
            var dataSqlWithPage = dataSql + " LIMIT " + page.getSize() + " OFFSET " + offset;
            var dataStatement = sqlSession.getConnection().prepareStatement(dataSqlWithPage);
            var dataResult = dataStatement.executeQuery();

            var records = new java.util.ArrayList<CcdiIntermediaryVO>();
            while (dataResult.next()) {
                var vo = new CcdiIntermediaryVO();
                vo.setId(dataResult.getString("id"));
                vo.setName(dataResult.getString("name"));
                vo.setCertificateNo(dataResult.getString("certificate_no"));
                vo.setIntermediaryType(dataResult.getString("intermediary_type"));
                vo.setPersonType(dataResult.getString("person_type"));
                vo.setCompany(dataResult.getString("company"));
                vo.setDataSource(dataResult.getString("data_source"));
                vo.setCreateTime(dataResult.getTimestamp("create_time"));
                records.add(vo);
            }
            page.setRecords(records);

            return page;
        } catch (Exception e) {
            throw new RuntimeException("查询失败", e);
        } finally {
            sqlSession.close();
        }
    }

    private String buildCountQuery(CcdiIntermediaryQueryDTO queryDTO) {
        String sql = """
            SELECT COUNT(*) FROM (
                SELECT biz_id FROM ccdi_biz_intermediary WHERE person_type = '中介'
            """;
        }
    }
}
```

由于Service实现类代码较长，完整代码见补充文档。此处提供核心方法框架。

**Step 3: 提交Service框架**

```bash
git add ruoyi-info-collection/src/main/java/com/ruoyi/ccdi/service/
git commit -m "feat: 添加中介Service接口和实现类框架"
```

---

## Task 8: 创建Excel导入导出类

**Files:**

- Create: `ruoyi-info-collection/src/main/java/com/ruoyi/ccdi/domain/excel/CcdiIntermediaryPersonExcel.java`
- Create: `ruoyi-info-collection/src/main/java/com/ruoyi/ccdi/domain/excel/CcdiIntermediaryEntityExcel.java`

**Step 1: 创建个人中介Excel类**

```java
package com.ruoyi.ccdi.domain.excel;

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.ruoyi.ccdi.handler.DictDropdownWriteHandler;
import lombok.Data;

import java.io.Serial;
import java.io.Serializable;

/**
 * 个人中介Excel类
 *
 * @author ruoyi
 * @date 2026-02-04
 */
@Data
public class CcdiIntermediaryPersonExcel implements Serializable {

    @Serial
    private static final long serialVersionUID = 1L;

    @ExcelProperty(value = "姓名", index = 0)
    @ColumnWidth(15)
    private String name;

    @ExcelProperty(value = "人员类型", index = 1)
    @ColumnWidth(15)
    private String personType;

    @ExcelProperty(value = "人员子类型", index = 2)
    @ColumnWidth(15)
    private String personSubType;

    @ExcelProperty(value = "性别", index = 3)
    @ColumnWidth(10)
    @DictDropdown(dictType = "ccdi_indiv_gender")
    private String gender;

    @ExcelProperty(value = "证件类型", index = 4)
    @ColumnWidth(15)
    @DictDropdown(dictType = "ccdi_certificate_type")
    private String idType;

    @ExcelProperty(value = "证件号码", index = 5)
    @ColumnWidth(20)
    private String personId;

    @ExcelProperty(value = "手机号码", index = 6)
    @ColumnWidth(15)
    private String mobile;

    @ExcelProperty(value = "微信号", index = 7)
    @ColumnWidth(15)
    private String wechatNo;

    @ExcelProperty(value = "联系地址", index = 8)
    @ColumnWidth(30)
    private String contactAddress;

    @ExcelProperty(value = "所在公司", index = 9)
    @ColumnWidth(30)
    private String company;

    @ExcelProperty(value = "职位", index = 10)
    @ColumnWidth(15)
    private String position;

    @ExcelProperty(value = "关联人员ID", index = 11)
    @ColumnWidth(15)
    private String relatedNumId;

    @ExcelProperty(value = "关联关系", index = 12)
    @ColumnWidth(15)
    @DictDropdown(dictType = "ccdi_relation_type")
    private String relationType;

    @ExcelProperty(value = "备注", index = 13)
    @ColumnWidth(30)
    private String remark;
}
```

**Step 2: 创建实体中介Excel类**

```java
package com.ruoyi.ccdi.domain.excel;

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.ruoyi.ccdi.handler.DictDropdownWriteHandler;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;

import java.io.Serial;
import java.io.Serializable;
import java.util.Date;

/**
 * 实体中介Excel类
 *
 * @author ruoyi
 * @date 2026-02-04
 */
@Data
public class CcdiIntermediaryEntityExcel implements Serializable {

    @Serial
    private static final long serialVersionUID = 1L;

    @ExcelProperty(value = "机构名称", index = 0)
    @ColumnWidth(30)
    private String enterpriseName;

    @ExcelProperty(value = "统一社会信用代码", index = 1)
    @ColumnWidth(25)
    private String socialCreditCode;

    @ExcelProperty(value = "主体类型", index = 2)
    @ColumnWidth(15)
    @DictDropdown(dictType = "ccdi_entity_type")
    private String enterpriseType;

    @ExcelProperty(value = "企业性质", index = 3)
    @ColumnWidth(15)
    @DictDropdown(dictType = "ccdi_enterprise_nature")
    private String enterpriseNature;

    @ExcelProperty(value = "行业分类", index = 4)
    @ColumnWidth(15)
    private String industryClass;

    @ExcelProperty(value = "所属行业", index = 5)
    @ColumnWidth(15)
    private String industryName;

    @ExcelProperty(value = "成立日期", index = 6)
    @ColumnWidth(15)
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date establishDate;

    @ExcelProperty(value = "注册地址", index = 7)
    @ColumnWidth(30)
    private String registerAddress;

    @ExcelProperty(value = "法定代表人", index = 8)
    @ColumnWidth(15)
    private String legalRepresentative;

    @ExcelProperty(value = "法人证件类型", index = 9)
    @ColumnWidth(15)
    @DictDropdown(dictType = "ccdi_certificate_type")
    private String legalCertType;

    @ExcelProperty(value = "法人证件号码", index = 10)
    @ColumnWidth(20)
    private String legalCertNo;

    @ExcelProperty(value = "股东1", index = 11)
    @ColumnWidth(15)
    private String shareholder1;

    @ExcelProperty(value = "股东2", index = 12)
    @ColumnWidth(15)
    private String shareholder2;

    @ExcelProperty(value = "股东3", index = 13)
    @ColumnWidth(15)
    private String shareholder3;

    @ExcelProperty(value = "股东4", index = 14)
    @ColumnWidth(15)
    private String shareholder4;

    @ExcelProperty(value = "股东5", index = 15)
    @ColumnWidth(15)
    private String shareholder5;

    @ExcelProperty(value = "备注", index = 16)
    @ColumnWidth(30)
    private String remark;
}
```

**Step 3: 提交Excel类**

```bash
git add ruoyi-info-collection/src/main/java/com/ruoyi/ccdi/domain/excel/
git commit -m "feat: 添加中介Excel导入导出类"
```

---

## Task 9: 创建Controller控制器

**Files:**

- Create: `ruoyi-info-collection/src/main/java/com/ruoyi/ccdi/controller/CcdiIntermediaryController.java`

**Step 1: 创建CcdiIntermediaryController**

```java
package com.ruoyi.ccdi.controller;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.ccdi.domain.dto.*;
import com.ruoyi.ccdi.domain.excel.CcdiIntermediaryEntityExcel;
import com.ruoyi.ccdi.domain.excel.CcdiIntermediaryPersonExcel;
import com.ruoyi.ccdi.domain.vo.CcdiIntermediaryEntityDetailVO;
import com.ruoyi.ccdi.domain.vo.CcdiIntermediaryPersonDetailVO;
import com.ruoyi.ccdi.domain.vo.CcdiIntermediaryVO;
import com.ruoyi.ccdi.service.ICcdiIntermediaryService;
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 2026-02-04
 */
@Tag(name = "中介黑名单管理")
@RestController
@RequestMapping("/ccdi/intermediary")
public class CcdiIntermediaryController extends BaseController {

    @Resource
    private ICcdiIntermediaryService intermediaryService;

    /**
     * 查询中介列表（UNION联合查询）
     */
    @Operation(summary = "查询中介列表")
    @PreAuthorize("@ss.hasPermi('ccdi:intermediary:list')")
    @GetMapping("/list")
    public TableDataInfo list(CcdiIntermediaryQueryDTO queryDTO) {
        PageDomain pageDomain = TableSupport.buildPageRequest();
        Page<CcdiIntermediaryVO> page = new Page<>(pageDomain.getPageNum(), pageDomain.getPageSize());
        Page<CcdiIntermediaryVO> result = intermediaryService.selectIntermediaryPage(page, queryDTO);
        return getDataTable(result.getRecords(), result.getTotal());
    }

    /**
     * 查询个人中介详情
     */
    @Operation(summary = "查询个人中介详情")
    @PreAuthorize("@ss.hasPermi('ccdi:intermediary:query')")
    @GetMapping("/person/{bizId}")
    public AjaxResult getPersonInfo(@PathVariable String bizId) {
        CcdiIntermediaryPersonDetailVO detail = intermediaryService.selectIntermediaryPersonDetail(bizId);
        return success(detail);
    }

    /**
     * 查询实体中介详情
     */
    @Operation(summary = "查询实体中介详情")
    @PreAuthorize("@ss.hasPermi('ccdi:intermediary:query')")
    @GetMapping("/entity/{socialCreditCode}")
    public AjaxResult getEntityInfo(@PathVariable String socialCreditCode) {
        CcdiIntermediaryEntityDetailVO detail = intermediaryService.selectIntermediaryEntityDetail(socialCreditCode);
        return success(detail);
    }

    /**
     * 新增个人中介
     */
    @Operation(summary = "新增个人中介")
    @PreAuthorize("@ss.hasPermi('ccdi:intermediary:add')")
    @Log(title = "中介黑名单", businessType = BusinessType.INSERT)
    @PostMapping("/person")
    public AjaxResult addPerson(@Validated @RequestBody CcdiIntermediaryPersonAddDTO addDTO) {
        if (!intermediaryService.checkPersonIdUnique(addDTO.getPersonId(), null)) {
            return error("新增个人中介失败，证件号已存在");
        }
        return toAjax(intermediaryService.insertIntermediaryPerson(addDTO));
    }

    /**
     * 修改个人中介
     */
    @Operation(summary = "修改个人中介")
    @PreAuthorize("@ss.hasPermi('ccdi:intermediary:edit')")
    @Log(title = "中介黑名单", businessType = BusinessType.UPDATE)
    @PutMapping("/person")
    public AjaxResult editPerson(@Validated @RequestBody CcdiIntermediaryPersonEditDTO editDTO) {
        if (!intermediaryService.checkPersonIdUnique(editDTO.getPersonId(), editDTO.getBizId())) {
            return error("修改个人中介失败，证件号已存在");
        }
        return toAjax(intermediaryService.updateIntermediaryPerson(editDTO));
    }

    /**
     * 新增实体中介
     */
    @Operation(summary = "新增实体中介")
    @PreAuthorize("@ss.hasPermi('ccdi:intermediary:add')")
    @Log(title = "中介黑名单", businessType = BusinessType.INSERT)
    @PostMapping("/entity")
    public AjaxResult addEntity(@Validated @RequestBody CcdiIntermediaryEntityAddDTO addDTO) {
        if (!intermediaryService.checkSocialCreditCodeUnique(addDTO.getSocialCreditCode(), null)) {
            return error("新增实体中介失败，统一社会信用代码已存在");
        }
        return toAjax(intermediaryService.insertIntermediaryEntity(addDTO));
    }

    /**
     * 修改实体中介
     */
    @Operation(summary = "修改实体中介")
    @PreAuthorize("@ss.hasPermi('ccdi:intermediary:edit')")
    @Log(title = "中介黑名单", businessType = BusinessType.UPDATE)
    @PutMapping("/entity")
    public AjaxResult editEntity(@Validated @RequestBody CcdiIntermediaryEntityEditDTO editDTO) {
        return toAjax(intermediaryService.updateIntermediaryEntity(editDTO));
    }

    /**
     * 删除中介
     */
    @Operation(summary = "删除中介")
    @PreAuthorize("@ss.hasPermi('ccdi:intermediary:remove')")
    @Log(title = "中介黑名单", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    public AjaxResult remove(@PathVariable String[] ids) {
        return toAjax(intermediaryService.deleteIntermediaryByIds(ids));
    }

    /**
     * 下载个人中介导入模板
     */
    @Operation(summary = "下载个人中介导入模板")
    @PostMapping("/importPersonTemplate")
    public void importPersonTemplate(HttpServletResponse response) {
        EasyExcelUtil.importTemplateWithDictDropdown(response, CcdiIntermediaryPersonExcel.class, "个人中介黑名单");
    }

    /**
     * 下载实体中介导入模板
     */
    @Operation(summary = "下载实体中介导入模板")
    @PostMapping("/importEntityTemplate")
    public void importEntityTemplate(HttpServletResponse response) {
        EasyExcelUtil.importTemplateWithDictDropdown(response, CcdiIntermediaryEntityExcel.class, "实体中介黑名单");
    }

    /**
     * 导入个人中介数据
     */
    @Operation(summary = "导入个人中介数据")
    @PreAuthorize("@ss.hasPermi('ccdi:intermediary:import')")
    @Log(title = "中介黑名单", businessType = BusinessType.IMPORT)
    @PostMapping("/importPersonData")
    public AjaxResult importPersonData(MultipartFile file, boolean updateSupport) throws Exception {
        List<CcdiIntermediaryPersonExcel> list = EasyExcelUtil.importExcel(file.getInputStream(), CcdiIntermediaryPersonExcel.class);
        String message = intermediaryService.importIntermediaryPerson(list, updateSupport);
        return success(message);
    }

    /**
     * 导入实体中介数据
     */
    @Operation(summary = "导入实体中介数据")
    @PreAuthorize("@ss.hasPermi('ccdi:intermediary:import')")
    @Log(title = "中介黑名单", businessType = BusinessType.IMPORT)
    @PostMapping("/importEntityData")
    public AjaxResult importEntityData(MultipartFile file, boolean updateSupport) throws Exception {
        List<CcdiIntermediaryEntityExcel> list = EasyExcelUtil.importExcel(file.getInputStream(), CcdiIntermediaryEntityExcel.class);
        String message = intermediaryService.importIntermediaryEntity(list, updateSupport);
        return success(message);
    }
}
```

**Step 2: 提交Controller**

```bash
git add ruoyi-info-collection/src/main/java/com/ruoyi/ccdi/controller/CcdiIntermediaryController.java
git commit -m "feat: 添加中介黑名单Controller"
```

---

## Task 10: 补充Service实现类的完整代码

**Files:**

- Complete: `ruoyi-info-collection/src/main/java/com/ruoyi/ccdi/service/impl/CcdiIntermediaryServiceImpl.java`

完整的Service实现需要包含所有业务逻辑方法，包括：

- UNION联合查询的分页实现
- 个人中介和实体中介的CRUD
- 唯一性校验
- Excel导入处理

由于代码较长，建议参考CcdiEmployeeServiceImpl的实现模式，逐步完善每个方法。

**Step 1: 提交完整的Service实现**

```bash
git add ruoyi-info-collection/src/main/java/com/ruoyi/ccdi/service/impl/CcdiIntermediaryServiceImpl.java
git commit -m "feat: 完善中介Service实现类"
```

---

## Task 11: 编写测试脚本

**Files:**

- Create: `doc/scripts/test-intermediary-api.sh`

**Step 1: 创建API测试脚本**

```bash
#!/bin/bash

# 获取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')

echo "Token: $TOKEN"
echo ""

# 测试查询列表
echo "=== 测试查询列表 ==="
curl -s -X GET "http://localhost:8080/ccdi/intermediary/list?pageNum=1&pageSize=10" \
  -H "Authorization: Bearer $TOKEN" | jq '.'

echo ""
echo "=== 测试新增个人中介 ==="
curl -s -X POST "http://localhost:8080/ccdi/intermediary/person" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "测试中介",
    "personType": "中介",
    "gender": "M",
    "idType": "身份证",
    "personId": "110101199001011234",
    "mobile": "13800138000",
    "company": "测试公司"
  }' | jq '.'

echo ""
echo "=== 测试新增实体中介 ==="
curl -s -X POST "http://localhost:8080/ccdi/intermediary/entity" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "enterpriseName": "测试中介公司",
    "socialCreditCode": "91110000123456789X",
    "enterpriseType": "有限责任公司",
    "enterpriseNature": "民企"
  }' | jq '.'

echo ""
echo "=== 测试完成 ==="
```

**Step 2: 创建测试报告模板**

**Files:**

- Create: `doc/test/intermediary-blacklist-test-report.md`

```markdown
# 中介黑名单管理模块测试报告

## 测试环境
- 测试账号: admin / admin123
- 测试日期: 2026-02-04

## 测试用例

### 1. 统一列表查询
- [ ] 查询全部中介
- [ ] 按类型筛选（个人）
- [ ] 按类型筛选（实体）
- [ ] 按名称模糊查询
- [ ] 按证件号精确查询
- [ ] 分页功能

### 2. 个人中介管理
- [ ] 新增个人中介
- [ ] 证件号唯一性校验
- [ ] 修改个人中介
- [ ] 查询个人中介详情
- [ ] 删除个人中介

### 3. 实体中介管理
- [ ] 新增实体中介
- [ ] 信用代码唯一性校验
- [ ] 修改实体中介
- [ ] 查询实体中介详情
- [ ] 删除实体中介

### 4. Excel导入导出
- [ ] 下载个人中介模板
- [ ] 个人中介模板下拉框验证
- [ ] 导入个人中介数据
- [ ] 下载实体中介模板
- [ ] 实体中介模板下拉框验证
- [ ] 导入实体中介数据

## 测试结果

（测试完成后填写实际结果）

## 问题记录

（记录发现的问题）
```

**Step 3: 提交测试文件**

```bash
git add doc/scripts/test-intermediary-api.sh
git add doc/test/intermediary-blacklist-test-report.md
git commit -m "test: 添加中介黑名单测试脚本和报告模板"
```

---

## Task 12: 生成API文档

**Files:**

- Create: `doc/api/中介黑名单管理API文档-v2.0.md`

**Step 1: 生成Swagger API文档**

访问 `http://localhost:8080/swagger-ui/index.html` 并导出所有中介相关接口的文档。

**Step 2: 创建API文档**

参考已有的API文档格式，创建完整的API文档，包括所有接口的请求参数、响应格式、错误码等。

**Step 3: 提交文档**

```bash
git add doc/api/中介黑名单管理API文档-v2.0.md
git commit -m "docs: 添加中介黑名单管理API文档"
```

---

## Task 13: 前端菜单配置

**Step 1: 更新系统菜单表**

在数据库中执行SQL，添加中介黑名单管理的菜单项：

```sql
-- 中介黑名单管理菜单
INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, query, route_name, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
VALUES
('中介黑名单', 2000, 5, 'intermediary', 'ccdi/intermediary/index', NULL, NULL, 1, 0, 'C', '0', '0', 'ccdi:intermediary:list', 'peoples', 'admin', NOW(), '', NULL, '中介黑名单管理菜单');

-- 获取刚插入的菜单ID
SET @menu_id = LAST_INSERT_ID();

-- 按钮权限
INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, query, route_name, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
VALUES
('中介查询', @menu_id, 1, NULL, NULL, NULL, NULL, 1, 0, 'F', '0', '0', 'ccdi:intermediary:query', '#', 'admin', NOW(), '', NULL, ''),
('中介新增', @menu_id, 2, NULL, NULL, NULL, NULL, 1, 0, 'F', '0', '0', 'ccdi:intermediary:add', '#', 'admin', NOW(), '', NULL, ''),
('中介修改', @menu_id, 3, NULL, NULL, NULL, NULL, 1, 0, 'F', '0', '0', 'ccdi:intermediary:edit', '#', 'admin', NOW(), '', NULL, ''),
('中介删除', @menu_id, 4, NULL, NULL, NULL, NULL, 1, 0, 'F', '0', '0', 'ccdi:intermediary:remove', '#', 'admin', NOW(), '', NULL, ''),
('中介导出', @menu_id, 5, NULL, NULL, NULL, NULL, 1, 0, 'F', '0', '0', 'ccdi:intermediary:export', '#', 'admin', NOW(), '', NULL, ''),
('中介导入', @menu_id, 6, NULL, NULL, NULL, NULL, 1, 0, 'F', '0', '0', 'ccdi:intermediary:import', '#', 'admin', NOW(), '', NULL, '');
```

**Step 2: 提交菜单SQL**

```bash
git add sql/menu-intermediary.sql
git commit -m "feat: 添加中介黑名单管理菜单SQL"
```

---

## Task 14: 最终验证和文档整理

**Step 1: 运行完整测试**

执行测试脚本，验证所有功能：

```bash
bash doc/scripts/test-intermediary-api.sh > doc/test/intermediary-test-result.log 2>&1
```

**Step 2: 生成测试报告**

根据测试结果填写测试报告。

**Step 3: 提交最终代码**

```bash
git add .
git commit -m "feat: 完成中介黑名单管理模块开发"
```

---

**计划完成并已保存到 `doc/plans/2026-02-04-intermediary-blacklist-implementation.md`。**

**两种执行选项：**

**1. Subagent-Driven (当前会话)** - 我会为每个任务派发新的子代理,任务之间进行审查,快速迭代

**2. Parallel Session (独立会话)** - 在新会话中打开worktree,使用executing-plans批量执行,带有检查点

**您选择哪种方式？**
