# 中介黑名单管理模块 - 系统设计文档

## 文档信息

- **版本**: v1.0
- **日期**: 2026-02-04
- **作者**: Claude
- **项目**: 纪检初核系统 (CCDI)

---

## 1. 概述

### 1.1 功能简介

中介黑名单管理模块提供个人中介和实体中介两类中介信息的完整管理功能，包括：
- 个人中介的增删改查
- 实体中介的增删改查
- 统一列表查询（支持联合查询和个人/实体分类查询）
- 带字典下拉框的Excel导入模板下载
- 批量数据导入

### 1.2 核心特性

1. **双表存储**: 个人中介和实体中介分别存储在不同的数据表中
2. **统一查询**: 使用SQL UNION实现高效的联合查询和分页
3. **类型区分**: 通过`intermediary_type`字段区分个人(1)和实体(2)中介
4. **智能筛选**: 实体中介通过`risk_level='1'`(高风险) AND `ent_source='INTERMEDIARY'(中介)`筛选
5. **唯一性保证**: 个人中介的证件号`person_id`作为业务唯一键

### 1.3 技术栈

- **后端框架**: Spring Boot 3.5.8
- **ORM框架**: MyBatis Plus 3.5.10
- **Excel处理**: EasyExcel (带字典下拉框)
- **数据库**: MySQL 8.2.0
- **API文档**: SpringDoc 2.8.14

---

## 2. 数据库设计

### 2.1 个人中介表 (ccdi_biz_intermediary)

| 字段名 | 类型 | 可空 | 主键 | 注释 |
|--------|------|------|------|------|
| biz_id | VARCHAR | 否 | 是 | 人员ID |
| person_type | VARCHAR | 否 | 否 | 人员类型（中介、职业背债人等） |
| person_sub_type | VARCHAR | 是 | 否 | 人员子类型 |
| relation_type | VARCHAR | 是 | 否 | 关系类型（配偶、子女、父母等） |
| name | VARCHAR | 否 | 否 | 姓名 |
| gender | CHAR | 是 | 否 | 性别 |
| id_type | VARCHAR | 否 | 否 | 证件类型（默认身份证） |
| person_id | VARCHAR | 否 | 否 | **证件号码（业务唯一键）** |
| mobile | VARCHAR | 是 | 否 | 手机号码 |
| wechat_no | VARCHAR | 是 | 否 | 微信号 |
| contact_address | VARCHAR | 是 | 否 | 联系地址 |
| company | VARCHAR | 是 | 否 | 所在公司 |
| social_credit_code | VARCHAR | 是 | 否 | 企业统一信用码 |
| position | VARCHAR | 是 | 否 | 职位 |
| related_num_id | VARCHAR | 是 | 否 | 关联人员ID |
| relation_type | VARCHAR | 是 | 否 | 关联关系 |
| data_source | VARCHAR | 是 | 否 | 数据来源（MANUAL/SYSTEM/IMPORT/API） |
| remark | VARCHAR | 是 | 否 | 备注信息 |
| created_by | VARCHAR | 否 | 否 | 记录创建人 |
| updated_by | VARCHAR | 是 | 否 | 记录更新人 |
| create_time | DATETIME | 否 | 否 | 记录创建时间 |
| update_time | DATETIME | 是 | 否 | 记录更新时间 |

**索引设计**:
- PRIMARY KEY: `biz_id`
- UNIQUE KEY: `uk_person_id` (`person_id`)

### 2.2 实体中介表 (ccdi_enterprise_base_info)

| 字段名 | 类型 | 可空 | 主键 | 注释 |
|--------|------|------|------|------|
| social_credit_code | VARCHAR | 否 | 是 | **统一社会信用代码（主键）** |
| enterprise_name | VARCHAR | 否 | 否 | 企业名称 |
| enterprise_type | VARCHAR | 否 | 否 | 企业类型（有限责任公司、股份有限公司等） |
| enterprise_nature | VARCHAR | 是 | 否 | 企业性质（国企、民企、外企等） |
| industry_class | VARCHAR | 是 | 否 | 行业分类 |
| industry_name | VARCHAR | 是 | 否 | 所属行业 |
| establish_date | DATE | 是 | 否 | 成立日期 |
| register_address | VARCHAR | 是 | 否 | 注册地址 |
| legal_representative | VARCHAR | 是 | 否 | 法定代表人 |
| legal_cert_type | VARCHAR | 是 | 否 | 法定代表人证件类型 |
| legal_cert_no | VARCHAR | 是 | 否 | 法定代表人证件号码 |
| shareholder1-5 | VARCHAR | 是 | 否 | 股东信息 |
| status | VARCHAR | 是 | 否 | 经营状态 |
| create_time | DATETIME | 否 | 否 | 创建时间 |
| update_time | DATETIME | 否 | 否 | 更新时间 |
| created_by | VARCHAR | 否 | 否 | 创建人 |
| updated_by | VARCHAR | 是 | 否 | 更新人 |
| data_source | VARCHAR | 是 | 否 | 数据来源（MANUAL/SYSTEM/API/IMPORT） |
| **risk_level** | VARCHAR(10) | 是 | 否 | **风险等级：1-高风险, 2-中风险, 3-低风险** |
| **ent_source** | VARCHAR(20) | 否 | 否 | **企业来源：GENERAL/EMP_RELATION/CREDIT_CUSTOMER/INTERMEDIARY/BOTH** |

**索引设计**:
- PRIMARY KEY: `social_credit_code`
- INDEX: `idx_risk_ent_source` (`risk_level`, `ent_source`)

**实体中介筛选条件**:
- `risk_level = '1'` (高风险)
- `ent_source = 'INTERMEDIARY'` (中介)

---

## 3. 架构设计

### 3.1 整体架构

```
Controller Layer (CcdiIntermediaryController)
    ↓
Service Layer (ICcdiIntermediaryService)
    ↓
Mapper Layer (CcdiBizIntermediaryMapper, CcdiEnterpriseBaseInfoMapper)
    ↓
Database (ccdi_biz_intermediary, ccdi_enterprise_base_info)
```

### 3.2 分层说明

**Controller层**:
- 统一的Controller处理个人和实体中介的请求
- 使用不同的路径区分个人和实体中介操作
- 权限控制: `ccdi:intermediary:*`

**Service层**:
- 统一的服务接口
- 根据中介类型路由到不同的业务逻辑
- 处理唯一性校验、数据自动填充等业务规则

**Mapper层**:
- 每个表对应独立的Mapper接口
- 继承MyBatis Plus的BaseMapper
- 自定义XML实现UNION联合查询

**DTO/VO层**:
- 严格分离，不与Entity混用
- DTO用于接口参数接收
- VO用于数据返回

---

## 4. 接口设计

### 4.1 基础信息

- **基础路径**: `/ccdi/intermediary`
- **权限前缀**: `ccdi:intermediary`
- **响应格式**: AjaxResult

### 4.2 统一列表查询

**接口**: `GET /ccdi/intermediary/list`

**权限**: `ccdi:intermediary:list`

**请求参数**:
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| name | String | 否 | 姓名/机构名称（模糊查询） |
| certificateNo | String | 否 | 证件号/统一社会信用代码（精确查询） |
| intermediaryType | String | 否 | 中介类型（1=个人, 2=实体, null=全部） |
| pageNum | Integer | 否 | 页码（默认1） |
| pageSize | Integer | 否 | 每页数量（默认10） |

**响应**: TableDataInfo (分页结果)

**实现**: SQL UNION联合查询，支持按类型筛选优化

### 4.3 个人中介接口

#### 4.3.1 新增个人中介
**接口**: `POST /ccdi/intermediary/person`
**权限**: `ccdi:intermediary:add`
**请求体**: CcdiIntermediaryPersonAddDTO
**业务逻辑**:
- 校验姓名必填
- 校验证件号必填且唯一
- 自动设置data_source='MANUAL'
- 自动设置person_type='中介'

#### 4.3.2 修改个人中介
**接口**: `PUT /ccdi/intermediary/person`
**权限**: `ccdi:intermediary:edit`
**请求体**: CcdiIntermediaryPersonEditDTO
**业务逻辑**:
- biz_id不可修改
- 证件号修改时需校验唯一性（排除自身）

#### 4.3.3 查询个人中介详情
**接口**: `GET /ccdi/intermediary/person/{bizId}`
**权限**: `ccdi:intermediary:query`
**响应**: CcdiIntermediaryPersonDetailVO

### 4.4 实体中介接口

#### 4.4.1 新增实体中介
**接口**: `POST /ccdi/intermediary/entity`
**权限**: `ccdi:intermediary:add`
**请求体**: CcdiIntermediaryEntityAddDTO
**业务逻辑**:
- 校验企业名称必填
- 校验统一社会信用代码唯一
- 自动设置risk_level='1'(高风险)
- 自动设置ent_source='INTERMEDIARY'(中介)
- 自动设置data_source='MANUAL'

#### 4.4.2 修改实体中介
**接口**: `PUT /ccdi/intermediary/entity`
**权限**: `ccdi:intermediary:edit`
**请求体**: CcdiIntermediaryEntityEditDTO
**业务逻辑**:
- social_credit_code不可修改
- 企业名称修改时需校验唯一性（排除自身）

#### 4.4.3 查询实体中介详情
**接口**: `GET /ccdi/intermediary/entity/{socialCreditCode}`
**权限**: `ccdi:intermediary:query`
**响应**: CcdiIntermediaryEntityDetailVO

### 4.5 删除接口

**接口**: `DELETE /ccdi/intermediary/{ids}`
**权限**: `ccdi:intermediary:remove`
**路径参数**: ids (支持个人和实体的ID，逗号分隔)

### 4.6 导入导出接口

#### 4.6.1 个人中介模板下载
**接口**: `POST /ccdi/intermediary/importPersonTemplate`
**权限**: 无需登录
**功能**: 下载带字典下拉框的Excel模板
**下拉字段**:
- 性别: `ccdi_indiv_gender`
- 证件类型: `ccdi_certificate_type`
- 关联关系: `ccdi_relation_type`

#### 4.6.2 实体中介模板下载
**接口**: `POST /ccdi/intermediary/importEntityTemplate`
**权限**: 无需登录
**功能**: 下载带字典下拉框的Excel模板
**下拉字段**:
- 主体类型: `ccdi_entity_type`
- 企业性质: `ccdi_enterprise_nature`
- 法人证件类型: `ccdi_certificate_type`

#### 4.6.3 个人中介数据导入
**接口**: `POST /ccdi/intermediary/importPersonData`
**权限**: `ccdi:intermediary:import`
**参数**:
- file: MultipartFile
- updateSupport: Boolean (是否更新已存在数据)
**Excel类**: CcdiIntermediaryPersonExcel
**业务逻辑**:
- 解析Excel数据
- 校验姓名必填、证件号必填
- 检查person_id唯一性
- 批量插入ccdi_biz_intermediary表
- 自动设置: data_source='IMPORT', person_type='中介'

#### 4.6.4 实体中介数据导入
**接口**: `POST /ccdi/intermediary/importEntityData`
**权限**: `ccdi:intermediary:import`
**参数**:
- file: MultipartFile
- updateSupport: Boolean (是否更新已存在数据)
**Excel类**: CcdiIntermediaryEntityExcel
**业务逻辑**:
- 解析Excel数据
- 校验企业名称必填
- 检查social_credit_code唯一性
- 批量插入ccdi_enterprise_base_info表
- 自动设置: risk_level='1', ent_source='INTERMEDIARY', data_source='IMPORT'

---

## 5. UNION联合查询实现

### 5.1 SQL查询语句

```xml
<select id="selectIntermediaryList" resultType="CcdiIntermediaryVO">
    <!-- 查询个人中介 -->
    SELECT
        biz_id as id,
        name,
        person_id as certificate_no,
        '1' as intermediary_type,
        person_type,
        gender,
        id_type,
        mobile,
        company,
        data_source,
        create_time
    FROM ccdi_biz_intermediary
    WHERE person_type = '中介'
    <if test="intermediaryType == null or intermediaryType == '1'">
        AND name LIKE CONCAT('%', #{name}, '%')
        <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,
        null as gender,
        null as id_type,
        null as mobile,
        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'">
        AND enterprise_name LIKE CONCAT('%', #{name}, '%')
        <if test="certificateNo != null and certificateNo != ''">
            AND social_credit_code = #{certificateNo}
        </if>
    </if>

    ORDER BY create_time DESC
</select>
```

### 5.2 分页实现

- 使用MyBatis Plus的Page对象进行分页
- 在Service层调用`page(intermediaryQueryDTO, Page)`方法
- 自动处理total和rows

### 5.3 查询优化

- 根据intermediaryType参数优化查询，如果指定类型则只查询对应表
- 添加索引优化查询性能

---

## 6. 数据对象设计

### 6.1 Entity实体类

**CcdiBizIntermediary**:
- 使用`@Data`注解
- 不继承BaseEntity
- 单独添加审计字段
- 主键: biz_id (String)

**CcdiEnterpriseBaseInfo**:
- 使用`@Data`注解
- 不继承BaseEntity
- 单独添加审计字段
- 主键: social_credit_code (String)

### 6.2 DTO数据传输对象

**CcdiIntermediaryPersonAddDTO**: 个人中介新增DTO
- 包含所有个人字段
- 使用JSR-303校验注解

**CcdiIntermediaryPersonEditDTO**: 个人中介修改DTO
- 包含biz_id和可编辑字段
- biz_id不可为空

**CcdiIntermediaryEntityAddDTO**: 实体中介新增DTO
- 包含所有企业字段
- 使用JSR-303校验注解

**CcdiIntermediaryEntityEditDTO**: 实体中介修改DTO
- 包含social_credit_code和可编辑字段
- social_credit_code不可为空

**CcdiIntermediaryQueryDTO**: 统一查询DTO
- 支持: name, certificateNo, intermediaryType筛选

### 6.3 VO视图对象

**CcdiIntermediaryVO**: 统一列表VO
- 包含intermediary_type字段区分类型(1=个人, 2=实体)
- 统一字段: id, name, certificate_no, intermediary_type, company, create_time等

**CcdiIntermediaryPersonDetailVO**: 个人中介详情VO
- 包含个人中介的所有详细信息

**CcdiIntermediaryEntityDetailVO**: 实体中介详情VO
- 包含实体中介的所有详细信息

### 6.4 Excel导入导出类

**CcdiIntermediaryPersonExcel**: 个人中介Excel类
- 使用EasyExcel注解
- 字段校验和格式化

**CcdiIntermediaryEntityExcel**: 实体中介Excel类
- 使用EasyExcel注解
- 字段校验和格式化

---

## 7. 业务规则

### 7.1 唯一性约束

1. **个人中介**:
   - `person_id`(证件号)必须唯一
   - 新增时检查是否已存在
   - 修改时检查是否已存在（排除自身）

2. **实体中介**:
   - `social_credit_code`(统一社会信用代码)必须唯一
   - 新增时检查是否已存在
   - 修改时检查是否已存在（排除自身）

### 7.2 数据自动填充

**个人中介**:
- data_source: MANUAL(手动录入) / IMPORT(批量导入)
- person_type: 中介

**实体中介**:
- risk_level: 1 (高风险)
- ent_source: INTERMEDIARY (中介)
- data_source: MANUAL(手动录入) / IMPORT(批量导入)

### 7.3 字典类型

| 字典类型 | 用途 |
|---------|------|
| ccdi_indiv_gender | 个人中介性别 |
| ccdi_certificate_type | 证件类型 |
| ccdi_relation_type | 关联关系 |
| ccdi_entity_type | 主体类型 |
| ccdi_enterprise_nature | 企业性质 |

---

## 8. 错误处理

### 8.1 业务错误码

| 错误码 | 说明 |
|--------|------|
| 1001 | 证件号已存在 |
| 1002 | 统一社会信用代码已存在 |
| 1003 | 数据不存在 |
| 1004 | 姓名不能为空 |
| 1005 | 证件号不能为空 |
| 1006 | 企业名称不能为空 |

### 8.2 异常处理策略

- 使用`@ControllerAdvice`全局异常处理
- 业务异常使用自定义BizException
- 参数校验异常自动返回字段错误信息

---

## 9. 测试策略

### 9.1 单元测试

- Service层业务逻辑测试
- Mapper层SQL查询测试
- 唯一性校验测试

### 9.2 集成测试

- Controller接口测试
- 导入导出功能测试
- 联合查询分页测试

### 9.3 测试脚本

- 生成可执行的HTTP测试脚本
- 使用admin/admin123账号获取token
- 保存测试结果并生成测试报告

---

## 10. 实现计划

### 10.1 开发顺序

1. 创建Entity实体类
2. 创建Mapper接口和XML
3. 创建DTO/VO对象
4. 实现Service层业务逻辑
5. 实现Controller层接口
6. 实现Excel导入导出功能
7. 编写测试用例
8. 生成API文档

### 10.2 技术要点

- 使用MyBatis Plus的BaseMapper简化CRUD操作
- 使用@Resource注入，替代@Autowired
- 实体类不继承BaseEntity，单独添加审计字段
- 简单CRUD使用MyBatis Plus方法，复杂查询使用XML
- 所有Controller接口添加完整的Swagger注解
- 使用@Validated和JSR-303进行参数校验

---

## 11. 附录

### 11.1 相关文档

- [中介黑名单管理API文档.md](../api/中介黑名单管理API文档.md)
- [中介黑名单后端.md](../docs/中介黑名单后端.md)
- [ccdi_biz_intermediary.csv](../docs/ccdi_biz_intermediary.csv)
- [ccdi_enterprise_base_info.csv](../docs/ccdi_enterprise_base_info.csv)

### 11.2 更新日志

| 版本 | 日期 | 说明 |
|------|------|------|
| 1.0 | 2026-02-04 | 初始版本，完成系统设计 |

---

**文档结束**
