中介黑名单更新
This commit is contained in:
@@ -0,0 +1,216 @@
|
||||
# 中介黑名单联合查询功能重构实现总结
|
||||
|
||||
## 一、问题描述
|
||||
|
||||
原始的SQL错误:`Unknown column 'relation_type_field' in 'field list'`
|
||||
|
||||
**根本原因:**
|
||||
1. 实体类 `CcdiBizIntermediary` 中定义了不存在的字段 `relationTypeField`
|
||||
2. 实体类中的 `dataSource` 字段与数据库字段 `date_source` 映射不匹配
|
||||
3. 原有的列表查询实现通过Java层合并两张表的数据,效率较低且无法利用数据库优化
|
||||
|
||||
## 二、解决方案
|
||||
|
||||
### 2.1 修复实体类字段映射
|
||||
|
||||
**文件:** `ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/domain/CcdiBizIntermediary.java`
|
||||
|
||||
**修改内容:**
|
||||
1. 删除了不存在的 `relationTypeField` 字段(第70行)
|
||||
2. 为 `dataSource` 字段添加了 `@TableField("date_source")` 注解(第70行)
|
||||
|
||||
```java
|
||||
// 修改前
|
||||
private String relationTypeField;
|
||||
private String dataSource;
|
||||
|
||||
// 修改后
|
||||
@TableField("date_source")
|
||||
private String dataSource;
|
||||
```
|
||||
|
||||
### 2.2 创建联合查询Mapper接口
|
||||
|
||||
**新增文件:** `ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/mapper/CcdiIntermediaryMapper.java`
|
||||
|
||||
**功能:**
|
||||
- 定义联合查询方法 `selectIntermediaryList()`
|
||||
- 定义统计查询方法 `selectIntermediaryCount()`
|
||||
- 支持按中介类型筛选:`1=个人, 2=实体, null=全部`
|
||||
|
||||
### 2.3 创建MyBatis XML Mapper
|
||||
|
||||
**新增文件:** `ruoyi-ccdi/src/main/resources/mapper/ccdi/CcdiIntermediaryMapper.xml`
|
||||
|
||||
**SQL设计策略:**
|
||||
|
||||
1. **单表查询模式**(当指定中介类型时)
|
||||
- `intermediaryType=1`:仅查询 `ccdi_biz_intermediary` 表
|
||||
- `intermediaryType=2`:仅查询 `ccdi_enterprise_base_info` 表
|
||||
|
||||
2. **联合查询模式**(当intermediaryType为null时)
|
||||
- 使用 `UNION ALL` 联合两张表
|
||||
- 外层包裹 `SELECT * FROM (...) AS combined_result` 用于统一排序和分页
|
||||
- 按创建时间倒序排列
|
||||
|
||||
3. **动态SQL特性**
|
||||
- 使用 MyBatis 动态SQL实现灵活的查询条件组合
|
||||
- 支持姓名模糊查询
|
||||
- 支持证件号/统一社会信用代码精确查询
|
||||
- 支持分页(LIMIT + OFFSET)
|
||||
|
||||
**查询条件映射:**
|
||||
|
||||
| 查询参数 | 个人中介表字段 | 实体中介表字段 |
|
||||
|---------|--------------|--------------|
|
||||
| name | name | enterprise_name |
|
||||
| certificateNo | person_id | social_credit_code |
|
||||
| intermediaryType | person_type='中介' | risk_level='1' AND ent_source='INTERMEDIARY' |
|
||||
|
||||
### 2.4 优化Service层实现
|
||||
|
||||
**文件:** `ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/service/impl/CcdiIntermediaryServiceImpl.java`
|
||||
|
||||
**修改内容:**
|
||||
|
||||
1. 注入新的 `CcdiIntermediaryMapper`
|
||||
2. 重写 `selectIntermediaryPage()` 方法,使用XML联合查询
|
||||
3. 删除原有的Java层合并数据和手动分页逻辑
|
||||
|
||||
**性能优势:**
|
||||
- 数据库层面实现分页,减少内存占用
|
||||
- 利用数据库索引优化查询性能
|
||||
- 减少网络传输数据量
|
||||
|
||||
### 2.5 扩展查询DTO
|
||||
|
||||
**文件:** `ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/domain/dto/CcdiIntermediaryQueryDTO.java`
|
||||
|
||||
**新增字段:**
|
||||
```java
|
||||
private Integer pageNum; // 页码
|
||||
private Integer pageSize; // 每页大小
|
||||
```
|
||||
|
||||
## 三、技术实现细节
|
||||
|
||||
### 3.1 分页实现
|
||||
|
||||
**MyBatis Plus的分页机制:**
|
||||
- MyBatis Plus的分页从1开始(`page.getCurrent()`)
|
||||
- SQL的OFFSET从0开始
|
||||
- 需要转换:`pageNum = page.getCurrent() - 1`
|
||||
|
||||
**SQL分页语法:**
|
||||
```sql
|
||||
LIMIT #{pageSize}
|
||||
OFFSET #{pageNum} * #{pageSize}
|
||||
```
|
||||
|
||||
### 3.2 UNION ALL vs UNION
|
||||
|
||||
- **使用 UNION ALL**:保留所有记录,包括重复记录
|
||||
- **性能优势**:UNION ALL 不进行去重排序,性能更好
|
||||
- **业务场景**:个人中介和实体中介不会重复,无需去重
|
||||
|
||||
### 3.3 动态SQL设计
|
||||
|
||||
使用MyBatis的 `<if>` 标签实现:
|
||||
```xml
|
||||
<if test="intermediaryType != null and intermediaryType == '1'">
|
||||
<!-- 个人中介查询 -->
|
||||
</if>
|
||||
<if test="intermediaryType != null and intermediaryType == '2'">
|
||||
<!-- 实体中介查询 -->
|
||||
</if>
|
||||
<if test="intermediaryType == null or intermediaryType == ''">
|
||||
<!-- 联合查询 -->
|
||||
</if>
|
||||
```
|
||||
|
||||
## 四、测试脚本
|
||||
|
||||
**文件:** `doc/test/scripts/test_union_query.sh`
|
||||
|
||||
**测试用例:**
|
||||
1. Test 1: 查询全部中介(UNION查询)
|
||||
2. Test 2: 仅查询个人中介(单表查询)
|
||||
3. Test 3: 仅查询实体中介(单表查询)
|
||||
4. Test 4: 按姓名模糊查询
|
||||
5. Test 5: 按证件号精确查询
|
||||
6. Test 6: 分页功能测试
|
||||
7. Test 7: 组合查询测试(类型+姓名+分页)
|
||||
|
||||
## 五、文件清单
|
||||
|
||||
### 修改的文件
|
||||
1. `ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/domain/CcdiBizIntermediary.java` - 删除冗余字段,修复字段映射
|
||||
2. `ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/service/impl/CcdiIntermediaryServiceImpl.java` - 重构查询逻辑
|
||||
3. `ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/domain/dto/CcdiIntermediaryQueryDTO.java` - 添加分页参数
|
||||
|
||||
### 新增的文件
|
||||
1. `ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/mapper/CcdiIntermediaryMapper.java` - 联合查询Mapper接口
|
||||
2. `ruoyi-ccdi/src/main/resources/mapper/ccdi/CcdiIntermediaryMapper.xml` - MyBatis XML Mapper
|
||||
3. `doc/test/scripts/test_union_query.sh` - 测试脚本
|
||||
|
||||
### 删除的文件
|
||||
1. `ruoyi-ccdi/src/main/resources/mapper/ccdi/CcdiIntermediaryMapper.xml` - 旧的错误配置
|
||||
|
||||
## 六、优势总结
|
||||
|
||||
### 6.1 性能提升
|
||||
- **数据库层面分页**:避免加载全部数据到内存
|
||||
- **索引优化**:充分利用数据库索引
|
||||
- **减少网络传输**:只传输需要的数据
|
||||
|
||||
### 6.2 代码质量
|
||||
- **职责分离**:查询逻辑集中在Mapper层
|
||||
- **代码简洁**:删除复杂的Java层合并逻辑
|
||||
- **易于维护**:SQL集中管理,便于优化
|
||||
|
||||
### 6.3 灵活性
|
||||
- **动态查询**:支持单表和联合查询灵活切换
|
||||
- **条件组合**:支持多种查询条件组合
|
||||
- **易于扩展**:后续新增字段或查询条件只需修改XML
|
||||
|
||||
## 七、后续建议
|
||||
|
||||
1. **索引优化**:
|
||||
- `ccdi_biz_intermediary`: 确保字段有合适索引
|
||||
- `ccdi_enterprise_base_info`: 确保 `risk_level` 和 `ent_source` 有索引
|
||||
|
||||
2. **性能监控**:
|
||||
- 监控慢查询日志
|
||||
- 根据实际数据量调整分页大小
|
||||
|
||||
3. **功能扩展**:
|
||||
- 考虑添加更多排序字段选项
|
||||
- 考虑支持批量导出时的流式查询
|
||||
|
||||
## 八、执行测试
|
||||
|
||||
```bash
|
||||
# Windows环境
|
||||
cd doc\test\scripts
|
||||
bash test_union_query.sh
|
||||
|
||||
# Linux/Mac环境
|
||||
cd doc/test/scripts
|
||||
chmod +x test_union_query.sh
|
||||
./test_union_query.sh
|
||||
```
|
||||
|
||||
## 九、回滚方案
|
||||
|
||||
如果新实现出现问题,可以通过Git回滚到之前的版本:
|
||||
```bash
|
||||
git checkout HEAD~1 -- ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/service/impl/CcdiIntermediaryServiceImpl.java
|
||||
```
|
||||
|
||||
删除新增的Mapper文件即可恢复原状。
|
||||
|
||||
---
|
||||
|
||||
**实现日期:** 2026-02-05
|
||||
**实现人:** Claude Code
|
||||
**版本:** v2.0
|
||||
@@ -0,0 +1,368 @@
|
||||
# 中介黑名单联合查询功能重构实现总结 (MyBatis Plus分页版本)
|
||||
|
||||
## 一、版本更新说明
|
||||
|
||||
**版本:** v2.1 (MyBatis Plus分页插件版本)
|
||||
**更新日期:** 2026-02-05
|
||||
**更新内容:** 使用MyBatis Plus分页插件替代手动分页,参考员工模块的实现方式
|
||||
|
||||
## 二、问题描述
|
||||
|
||||
### 2.1 原始错误
|
||||
```
|
||||
Unknown column 'relation_type_field' in 'field list'
|
||||
```
|
||||
|
||||
### 2.2 v2.0版本的问题
|
||||
虽然v2.0版本实现了XML联合查询,但使用了手动的LIMIT/OFFSET分页,这与若依框架的标准实现方式不一致:
|
||||
- **不一致性**:与员工模块等其他模块的实现方式不同
|
||||
- **维护性**:手动计算分页参数,容易出错
|
||||
- **功能限制**:无法利用MyBatis Plus分页插件的优化功能
|
||||
|
||||
## 三、解决方案(v2.1)
|
||||
|
||||
### 3.1 参考实现
|
||||
参考 `CcdiEmployeeController` 和 `CcdiEmployeeServiceImpl` 的实现方式:
|
||||
```java
|
||||
// Controller层
|
||||
PageDomain pageDomain = TableSupport.buildPageRequest();
|
||||
Page<CcdiEmployeeVO> page = new Page<>(pageDomain.getPageNum(), pageDomain.getPageSize());
|
||||
Page<CcdiEmployeeVO> result = employeeService.selectEmployeePage(page, queryDTO);
|
||||
|
||||
// Service层
|
||||
Page<CcdiEmployeeVO> resultPage = employeeMapper.selectEmployeePageWithDept(voPage, queryDTO);
|
||||
|
||||
// Mapper接口
|
||||
Page<CcdiEmployeeVO> selectEmployeePageWithDept(@Param("page") Page<CcdiEmployeeVO> page,
|
||||
@Param("query") CcdiEmployeeQueryDTO queryDTO);
|
||||
|
||||
// XML
|
||||
<select id="selectEmployeePageWithDept" resultMap="CcdiEmployeeVOResult">
|
||||
SELECT ... FROM ...
|
||||
WHERE ...
|
||||
ORDER BY ...
|
||||
<!-- 不包含LIMIT和OFFSET,由MyBatis Plus自动注入 -->
|
||||
</select>
|
||||
```
|
||||
|
||||
### 3.2 核心改动
|
||||
|
||||
#### 1. Mapper接口方法签名
|
||||
**文件:** `ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/mapper/CcdiIntermediaryMapper.java`
|
||||
|
||||
**修改前:**
|
||||
```java
|
||||
List<CcdiIntermediaryVO> selectIntermediaryList(CcdiIntermediaryQueryDTO queryDTO);
|
||||
long selectIntermediaryCount(CcdiIntermediaryQueryDTO queryDTO);
|
||||
```
|
||||
|
||||
**修改后:**
|
||||
```java
|
||||
Page<CcdiIntermediaryVO> selectIntermediaryList(
|
||||
Page<CcdiIntermediaryVO> page,
|
||||
@Param("query") CcdiIntermediaryQueryDTO queryDTO
|
||||
);
|
||||
```
|
||||
|
||||
**关键点:**
|
||||
- 第一个参数是 `Page` 对象
|
||||
- 查询条件使用 `@Param` 注解包装
|
||||
- 返回类型是 `Page<Vo>`
|
||||
- 删除了单独的count查询方法
|
||||
|
||||
#### 2. XML Mapper文件
|
||||
**文件:** `ruoyi-ccdi/src/main/resources/mapper/ccdi/CcdiIntermediaryMapper.xml`
|
||||
|
||||
**修改前(v2.0):**
|
||||
```xml
|
||||
<!-- 三个独立的SQL分支,每个分支都包含LIMIT和OFFSET -->
|
||||
<if test="intermediaryType == '1'">
|
||||
SELECT ... FROM ccdi_biz_intermediary ...
|
||||
LIMIT #{pageSize} OFFSET #{pageNum} * #{pageSize}
|
||||
</if>
|
||||
<if test="intermediaryType == '2'">
|
||||
SELECT ... FROM ccdi_enterprise_base_info ...
|
||||
LIMIT #{pageSize} OFFSET #{pageNum} * #{pageSize}
|
||||
</if>
|
||||
<if test="intermediaryType == null">
|
||||
SELECT * FROM (...) UNION ALL (...)
|
||||
LIMIT #{pageSize} OFFSET #{pageNum} * #{pageSize}
|
||||
</if>
|
||||
```
|
||||
|
||||
**修改后(v2.1):**
|
||||
```xml
|
||||
<!-- 统一的SQL结构,不包含LIMIT和OFFSET -->
|
||||
<select id="selectIntermediaryList" resultType="com.ruoyi.ccdi.domain.vo.CcdiIntermediaryVO">
|
||||
SELECT * FROM (
|
||||
<!-- 个人中介 -->
|
||||
SELECT ... FROM ccdi_biz_intermediary WHERE person_type = '中介'
|
||||
UNION ALL
|
||||
<!-- 实体中介 -->
|
||||
SELECT ... FROM ccdi_enterprise_base_info WHERE ...
|
||||
) AS combined_result
|
||||
<where>
|
||||
<!-- 动态查询条件 -->
|
||||
<if test="query.intermediaryType != null and query.intermediaryType != ''">
|
||||
AND intermediary_type = #{query.intermediaryType}
|
||||
</if>
|
||||
<if test="query.name != null and query.name != ''">
|
||||
AND name LIKE CONCAT('%', #{query.name}, '%')
|
||||
</if>
|
||||
<if test="query.certificateNo != null and query.certificateNo != ''">
|
||||
AND certificate_no = #{query.certificateNo}
|
||||
</if>
|
||||
</where>
|
||||
ORDER BY create_time DESC
|
||||
<!-- MyBatis Plus会自动在这里注入LIMIT和OFFSET -->
|
||||
</select>
|
||||
```
|
||||
|
||||
**关键点:**
|
||||
- 统一的查询结构,使用UNION ALL
|
||||
- 不包含LIMIT和OFFSET
|
||||
- 在最外层使用 `<where>` 进行动态过滤
|
||||
- MyBatis Plus分页插件会自动在ORDER BY后面注入分页SQL
|
||||
|
||||
#### 3. Service层实现
|
||||
**文件:** `ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/service/impl/CcdiIntermediaryServiceImpl.java`
|
||||
|
||||
**修改前(v2.0):**
|
||||
```java
|
||||
public Page<CcdiIntermediaryVO> selectIntermediaryPage(...) {
|
||||
// 手动查询总数
|
||||
long total = intermediaryMapper.selectIntermediaryCount(queryDTO);
|
||||
|
||||
// 手动设置分页参数
|
||||
queryDTO.setPageNum((int) (page.getCurrent() - 1));
|
||||
queryDTO.setPageSize((int) page.getSize());
|
||||
|
||||
// 手动查询列表
|
||||
List<CcdiIntermediaryVO> list = intermediaryMapper.selectIntermediaryList(queryDTO);
|
||||
|
||||
// 手动设置分页结果
|
||||
page.setRecords(list);
|
||||
page.setTotal(total);
|
||||
|
||||
return page;
|
||||
}
|
||||
```
|
||||
|
||||
**修改后(v2.1):**
|
||||
```java
|
||||
public Page<CcdiIntermediaryVO> selectIntermediaryPage(Page<CcdiIntermediaryVO> page, CcdiIntermediaryQueryDTO queryDTO) {
|
||||
// 直接调用Mapper的联合查询方法,MyBatis Plus会自动处理分页
|
||||
return intermediaryMapper.selectIntermediaryList(page, queryDTO);
|
||||
}
|
||||
```
|
||||
|
||||
**关键点:**
|
||||
- 一行代码搞定
|
||||
- MyBatis Plus自动处理count查询、分页SQL注入、结果封装
|
||||
- 无需手动计算分页参数
|
||||
|
||||
#### 4. QueryDTO清理
|
||||
**文件:** `ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/domain/dto/CcdiIntermediaryQueryDTO.java`
|
||||
|
||||
**删除字段:**
|
||||
```java
|
||||
// 不再需要,分页信息通过Page对象传递
|
||||
private Integer pageNum;
|
||||
private Integer pageSize;
|
||||
```
|
||||
|
||||
## 四、技术实现细节
|
||||
|
||||
### 4.1 MyBatis Plus分页插件工作原理
|
||||
|
||||
1. **拦截器机制**
|
||||
- MyBatis Plus使用拦截器在SQL执行前拦截
|
||||
- 自动在SQL后面添加LIMIT和OFFSET
|
||||
- 自动执行COUNT查询获取total
|
||||
|
||||
2. **分页SQL生成**
|
||||
```sql
|
||||
-- 原始SQL
|
||||
SELECT * FROM (UNION查询) AS t WHERE ... ORDER BY create_time DESC
|
||||
|
||||
-- MyBatis Plus自动注入后
|
||||
SELECT * FROM (
|
||||
SELECT * FROM (UNION查询) AS t WHERE ... ORDER BY create_time DESC
|
||||
LIMIT 10 OFFSET 0
|
||||
) AS page
|
||||
```
|
||||
|
||||
3. **参数传递**
|
||||
- Controller: `PageDomain` → `Page<Vo>`
|
||||
- Service: `Page<Vo>` 传递给Mapper
|
||||
- Mapper: `Page<Vo>` 作为第一个参数
|
||||
- XML: 通过MyBatis Plus拦截器自动处理
|
||||
|
||||
### 4.2 SQL优化
|
||||
|
||||
#### v2.0的问题
|
||||
- 三个独立的SQL分支
|
||||
- 每个分支都需要处理分页
|
||||
- 代码重复,维护困难
|
||||
|
||||
#### v2.1的优化
|
||||
- 统一的SQL结构
|
||||
- 外层WHERE条件过滤
|
||||
- MyBatis Plus统一处理分页
|
||||
- 代码简洁,易于维护
|
||||
|
||||
### 4.3 参数绑定变化
|
||||
|
||||
**v2.0:**
|
||||
```java
|
||||
// QueryDTO包含分页参数
|
||||
queryDTO.setPageNum(0);
|
||||
queryDTO.setPageSize(10);
|
||||
mapper.selectList(queryDTO);
|
||||
|
||||
// XML中直接使用
|
||||
#{pageNum}, #{pageSize}
|
||||
```
|
||||
|
||||
**v2.1:**
|
||||
```java
|
||||
// Page对象单独传递
|
||||
Page<CcdiIntermediaryVO> page = new Page<>(1, 10);
|
||||
mapper.selectList(page, queryDTO);
|
||||
|
||||
// XML中通过@Param包装
|
||||
#{query.intermediaryType}, #{query.name}
|
||||
```
|
||||
|
||||
## 五、文件清单
|
||||
|
||||
### 修改的文件
|
||||
1. `ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/domain/CcdiBizIntermediary.java` - 删除冗余字段,修复字段映射
|
||||
2. `ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/domain/dto/CcdiIntermediaryQueryDTO.java` - 删除分页参数
|
||||
3. `ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/mapper/CcdiIntermediaryMapper.java` - 修改方法签名
|
||||
4. `ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/service/impl/CcdiIntermediaryServiceImpl.java` - 简化分页逻辑
|
||||
5. `ruoyi-ccdi/src/main/resources/mapper/ccdi/CcdiIntermediaryMapper.xml` - 重写SQL结构
|
||||
|
||||
### 新增的文件
|
||||
1. `doc/test/scripts/test_union_query_mybatis_plus.sh` - 测试脚本
|
||||
2. `doc/plans/2026-02-05-intermediary-blacklist-union-query-mybatis-plus.md` - 本文档
|
||||
|
||||
### 删除的文件
|
||||
1. `doc/test/scripts/test_union_query.sh` - 旧版测试脚本(保留备份)
|
||||
|
||||
## 六、优势总结
|
||||
|
||||
### 6.1 与框架一致性
|
||||
- ✅ 与员工模块等其他模块实现方式一致
|
||||
- ✅ 符合若依框架的标准规范
|
||||
- ✅ 便于团队统一维护
|
||||
|
||||
### 6.2 代码简洁性
|
||||
- ✅ Service层从10+行代码减少到1行
|
||||
- ✅ XML从200+行减少到60行
|
||||
- ✅ 删除了手动分页的复杂逻辑
|
||||
|
||||
### 6.3 性能优化
|
||||
- ✅ MyBatis Plus分页插件经过优化
|
||||
- ✅ 自动缓存count查询结果
|
||||
- ✅ 支持多种数据库的分页方言
|
||||
|
||||
### 6.4 可维护性
|
||||
- ✅ 统一的SQL结构,易于理解
|
||||
- ✅ 动态条件集中在外层WHERE
|
||||
- ✅ 易于扩展新的查询条件
|
||||
|
||||
## 七、测试验证
|
||||
|
||||
### 7.1 测试脚本
|
||||
**文件:** `doc/test/scripts/test_union_query_mybatis_plus.sh`
|
||||
|
||||
**测试用例:**
|
||||
1. Test 1: UNION ALL查询全部中介
|
||||
2. Test 2: 按类型筛选个人中介
|
||||
3. Test 3: 按类型筛选实体中介
|
||||
4. Test 4: 按姓名模糊查询
|
||||
5. Test 5: 按证件号精确查询
|
||||
6. Test 6: MyBatis Plus分页功能测试
|
||||
7. Test 7: 组合查询测试
|
||||
8. Test 8: 大分页测试
|
||||
|
||||
### 7.2 执行测试
|
||||
```bash
|
||||
# Windows环境
|
||||
cd doc\test\scripts
|
||||
bash test_union_query_mybatis_plus.sh
|
||||
|
||||
# Linux/Mac环境
|
||||
cd doc/test/scripts
|
||||
chmod +x test_union_query_mybatis_plus.sh
|
||||
./test_union_query_mybatis_plus.sh
|
||||
```
|
||||
|
||||
## 八、对比总结
|
||||
|
||||
| 特性 | v2.0 (手动分页) | v2.1 (MyBatis Plus) |
|
||||
|-----|----------------|-------------------|
|
||||
| Service代码行数 | 10+ | 1 |
|
||||
| XML代码行数 | 200+ | 60 |
|
||||
| 一致性 | ❌ 与框架不一致 | ✅ 完全一致 |
|
||||
| 性能 | 一般 | 优化 |
|
||||
| 维护性 | 复杂 | 简单 |
|
||||
| 扩展性 | 困难 | 容易 |
|
||||
| Count查询 | 手动 | 自动 |
|
||||
| 分页计算 | 手动 | 自动 |
|
||||
|
||||
## 九、最佳实践
|
||||
|
||||
基于本次重构,总结以下最佳实践:
|
||||
|
||||
1. **遵循框架规范**
|
||||
- 优先使用框架提供的标准实现方式
|
||||
- 参考其他模块的成熟实现
|
||||
|
||||
2. **分页查询模式**
|
||||
```java
|
||||
// Mapper接口
|
||||
Page<VO> selectXxxPage(Page<VO> page, @Param("query") QueryDTO query);
|
||||
|
||||
// Service实现
|
||||
return mapper.selectXxxPage(page, query);
|
||||
|
||||
// XML
|
||||
<select id="selectXxxPage" resultType="VO">
|
||||
SELECT ... FROM ...
|
||||
<where>...</where>
|
||||
ORDER BY ...
|
||||
</select>
|
||||
```
|
||||
|
||||
3. **联合查询优化**
|
||||
- 使用UNION ALL而不是多个分支
|
||||
- 在最外层使用WHERE进行过滤
|
||||
- 避免在XML中写LIMIT和OFFSET
|
||||
|
||||
4. **参数传递**
|
||||
- Page对象作为第一个参数
|
||||
- 查询条件使用@Param包装
|
||||
- 避免在实体中混入分页参数
|
||||
|
||||
## 十、后续建议
|
||||
|
||||
1. **性能监控**
|
||||
- 监控UNION ALL查询的执行计划
|
||||
- 优化索引以提升查询性能
|
||||
|
||||
2. **功能扩展**
|
||||
- 考虑添加更多排序字段选项
|
||||
- 考虑支持批量导出的流式查询
|
||||
|
||||
3. **代码优化**
|
||||
- 其他模块如有类似实现,建议统一改造
|
||||
- 建立统一的分页查询模板
|
||||
|
||||
---
|
||||
|
||||
**实现日期:** 2026-02-05
|
||||
**实现人:** Claude Code
|
||||
**版本:** v2.1 (MyBatis Plus分页插件版本)
|
||||
**参考模块:** CcdiEmployeeController/CcdiEmployeeServiceImpl
|
||||
642
doc/plans/2026-02-05-中介黑名单前端适配APIv2.0重构设计.md
Normal file
642
doc/plans/2026-02-05-中介黑名单前端适配APIv2.0重构设计.md
Normal file
@@ -0,0 +1,642 @@
|
||||
# 中介黑名单前端适配API v2.0重构设计文档
|
||||
|
||||
**文档版本**: v1.0
|
||||
**创建日期**: 2026-02-05
|
||||
**设计目标**: 将前端字段完全对齐API v2.0规范,实现前后端字段名一致
|
||||
|
||||
---
|
||||
|
||||
## 一、变更背景
|
||||
|
||||
### 1.1 API v2.0核心变更
|
||||
|
||||
后端API已升级至v2.0版本,主要变更包括:
|
||||
|
||||
- **统一业务ID**: 使用`bizId`替代`intermediaryId`作为主键
|
||||
- **接口分离**: 个人和实体中介使用独立的详情查询接口
|
||||
- **字段规范化**: 统一字段命名规范,消除歧义
|
||||
- **DTO/VO分离**: 请求和响应对象完全分离
|
||||
|
||||
### 1.2 重构目标
|
||||
|
||||
1. **字段名对齐**: 前端表单字段与API请求字段完全一致
|
||||
2. **消除映射**: 移除前后端字段名转换逻辑
|
||||
3. **代码简化**: 降低维护成本,提升可读性
|
||||
4. **类型安全**: 确保个人和实体中介字段正确隔离
|
||||
|
||||
---
|
||||
|
||||
## 二、字段映射方案
|
||||
|
||||
### 2.1 个人中介字段映射
|
||||
|
||||
| 旧前端字段 | API v2.0字段 | 说明 |
|
||||
|-----------|-------------|------|
|
||||
| intermediaryId | bizId | 主键ID |
|
||||
| certificateNo | personId | 证件号码 |
|
||||
| indivType | personType | 人员类型 |
|
||||
| indivSubType | personSubType | 人员子类型 |
|
||||
| indivGender | gender | 性别 |
|
||||
| indivCertType | idType | 证件类型 |
|
||||
| indivPhone | mobile | 手机号码 |
|
||||
| indivWechat | wechatNo | 微信号 |
|
||||
| indivAddress | contactAddress | 联系地址 |
|
||||
| indivCompany | company | 所在公司 |
|
||||
| indivPosition | position | 职位 |
|
||||
| indivRelatedId | relatedNumId | 关联人员ID |
|
||||
| indivRelation | relationType | 关系类型 |
|
||||
|
||||
**保持不变的字段:**
|
||||
- name (姓名)
|
||||
- remark (备注)
|
||||
- intermediaryType (中介类型)
|
||||
- status (状态)
|
||||
|
||||
### 2.2 实体中介字段映射
|
||||
|
||||
| 旧前端字段 | API v2.0字段 | 说明 |
|
||||
|-----------|-------------|------|
|
||||
| intermediaryId | bizId | 主键ID |
|
||||
| name | enterpriseName | 机构名称 |
|
||||
| certificateNo / corpCreditCode | socialCreditCode | 统一社会信用代码 |
|
||||
| corpType | enterpriseType | 主体类型 |
|
||||
| corpNature | enterpriseNature | 企业性质 |
|
||||
| corpIndustryCategory | industryClass | 行业分类 |
|
||||
| corpIndustry | industryName | 所属行业 |
|
||||
| corpEstablishDate | establishDate | 成立日期 |
|
||||
| corpAddress | registerAddress | 注册地址 |
|
||||
| corpLegalRep | legalRepresentative | 法定代表人 |
|
||||
| corpLegalCertType | legalCertType | 法定代表人证件类型 |
|
||||
| corpLegalCertNo | legalCertNo | 法定代表人证件号码 |
|
||||
| corpShareholder1-5 | shareholder1-5 | 股东信息(1-5) |
|
||||
|
||||
**保持不变的字段:**
|
||||
- remark (备注)
|
||||
- intermediaryType (中介类型)
|
||||
- status (状态)
|
||||
|
||||
---
|
||||
|
||||
## 三、文件修改清单
|
||||
|
||||
### 3.1 需要修改的文件
|
||||
|
||||
| 序号 | 文件路径 | 修改类型 | 优先级 |
|
||||
|-----|---------|---------|-------|
|
||||
| 1 | `ruoyi-ui/src/api/ccdiIntermediary.js` | API层 | P0 |
|
||||
| 2 | `ruoyi-ui/src/views/ccdiIntermediary/index.vue` | 主页面 | P0 |
|
||||
| 3 | `ruoyi-ui/src/views/ccdiIntermediary/components/EditDialog.vue` | 编辑组件 | P0 |
|
||||
| 4 | `ruoyi-ui/src/views/ccdiIntermediary/components/DetailDialog.vue` | 详情组件 | P1 |
|
||||
| 5 | `ruoyi-ui/src/views/ccdiIntermediary/components/ImportDialog.vue` | 导入组件 | P1 |
|
||||
|
||||
### 3.2 无需修改的文件
|
||||
|
||||
| 序号 | 文件路径 | 原因 |
|
||||
|-----|---------|------|
|
||||
| 1 | `SearchForm.vue` | 查询参数与API兼容 |
|
||||
| 2 | `DataTable.vue` | 已使用友好名称字段 |
|
||||
|
||||
---
|
||||
|
||||
## 四、API层修改详情
|
||||
|
||||
### 4.1 ccdiIntermediary.js
|
||||
|
||||
#### 新增接口
|
||||
|
||||
```javascript
|
||||
// 查询个人中介详情
|
||||
export function getPersonIntermediary(bizId) {
|
||||
return request({
|
||||
url: '/ccdi/intermediary/person/' + bizId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 查询实体中介详情
|
||||
export function getEntityIntermediary(socialCreditCode) {
|
||||
return request({
|
||||
url: '/ccdi/intermediary/entity/' + socialCreditCode,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
#### 删除接口
|
||||
|
||||
```javascript
|
||||
// 删除以下旧版统一接口
|
||||
// getIntermediary(intermediaryId)
|
||||
// addIntermediary(data)
|
||||
// updateIntermediary(data)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、主页面修改详情
|
||||
|
||||
### 5.1 index.vue - 数据模型
|
||||
|
||||
#### queryParams修改
|
||||
|
||||
```javascript
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
name: null,
|
||||
certificateNo: null, // 保持不变(API查询参数兼容)
|
||||
intermediaryType: null,
|
||||
status: null
|
||||
}
|
||||
```
|
||||
|
||||
#### form数据模型
|
||||
|
||||
```javascript
|
||||
form: {
|
||||
// 通用字段
|
||||
bizId: null, // 原 intermediaryId
|
||||
intermediaryType: '1',
|
||||
status: '0',
|
||||
remark: null,
|
||||
|
||||
// 个人中介字段
|
||||
name: null,
|
||||
personId: null, // 原 certificateNo
|
||||
personType: null, // 原 indivType
|
||||
personSubType: null, // 原 indivSubType
|
||||
relationType: null, // 原 indivRelation
|
||||
gender: null, // 原 indivGender
|
||||
idType: null, // 原 indivCertType
|
||||
mobile: null, // 原 indivPhone
|
||||
wechatNo: null, // 原 indivWechat
|
||||
contactAddress: null, // 原 indivAddress
|
||||
company: null, // 原 indivCompany
|
||||
socialCreditCode: null, // 新增
|
||||
position: null, // 原 indivPosition
|
||||
relatedNumId: null, // 原 indivRelatedId
|
||||
|
||||
// 实体中介字段
|
||||
enterpriseName: null, // 原 name
|
||||
socialCreditCode: null, // 原 certificateNo/corpCreditCode
|
||||
enterpriseType: null, // 原 corpType
|
||||
enterpriseNature: null, // 原 corpNature
|
||||
industryClass: null, // 原 corpIndustryCategory
|
||||
industryName: null, // 原 corpIndustry
|
||||
establishDate: null, // 原 corpEstablishDate
|
||||
registerAddress: null, // 原 corpAddress
|
||||
legalRepresentative: null, // 原 corpLegalRep
|
||||
legalCertType: null, // 原 corpLegalCertType
|
||||
legalCertNo: null, // 原 corpLegalCertNo
|
||||
shareholder1: null, // 原 corpShareholder1
|
||||
shareholder2: null, // 原 corpShareholder2
|
||||
shareholder3: null, // 原 corpShareholder3
|
||||
shareholder4: null, // 原 corpShareholder4
|
||||
shareholder5: null // 原 corpShareholder5
|
||||
}
|
||||
```
|
||||
|
||||
### 5.2 核心方法修改
|
||||
|
||||
#### handleSelectionChange
|
||||
|
||||
```javascript
|
||||
handleSelectionChange(selection) {
|
||||
this.ids = selection.map(item => item.bizId); // 原 intermediaryId
|
||||
this.single = selection.length !== 1;
|
||||
this.multiple = !selection.length;
|
||||
}
|
||||
```
|
||||
|
||||
#### handleDetail
|
||||
|
||||
```javascript
|
||||
handleDetail(row) {
|
||||
if (row.intermediaryType === '1') {
|
||||
// 个人中介
|
||||
getPersonIntermediary(row.bizId).then(response => {
|
||||
this.detailData = response.data;
|
||||
this.detailOpen = true;
|
||||
});
|
||||
} else {
|
||||
// 实体中介
|
||||
getEntityIntermediary(row.socialCreditCode).then(response => {
|
||||
this.detailData = response.data;
|
||||
this.detailOpen = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### handleUpdate
|
||||
|
||||
```javascript
|
||||
handleUpdate(row) {
|
||||
this.reset();
|
||||
if (row.intermediaryType === '1') {
|
||||
getPersonIntermediary(row.bizId).then(response => {
|
||||
this.form = response.data;
|
||||
this.open = true;
|
||||
this.title = "修改中介黑名单";
|
||||
});
|
||||
} else {
|
||||
getEntityIntermediary(row.socialCreditCode).then(response => {
|
||||
this.form = response.data;
|
||||
this.open = true;
|
||||
this.title = "修改中介黑名单";
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### submitForm
|
||||
|
||||
```javascript
|
||||
submitForm() {
|
||||
if (this.form.bizId != null) { // 原 intermediaryId
|
||||
// 修改模式
|
||||
if (this.form.intermediaryType === '1') {
|
||||
updatePersonIntermediary(this.form).then(response => {
|
||||
this.$modal.msgSuccess("修改成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
} else {
|
||||
updateEntityIntermediary(this.form).then(response => {
|
||||
this.$modal.msgSuccess("修改成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// 新增模式
|
||||
if (this.form.intermediaryType === '1') {
|
||||
addPersonIntermediary(this.form).then(response => {
|
||||
this.$modal.msgSuccess("新增成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
} else {
|
||||
addEntityIntermediary(this.form).then(response => {
|
||||
this.$modal.msgSuccess("新增成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### handleDelete
|
||||
|
||||
```javascript
|
||||
handleDelete(row) {
|
||||
const bizIds = row.bizId || this.ids.join(','); // 原 intermediaryIds
|
||||
this.$modal.confirm('是否确认删除中介黑名单编号为"' + bizIds + '"的数据项?')
|
||||
.then(function() {
|
||||
return delIntermediary(bizIds);
|
||||
}).then(() => {
|
||||
this.getList();
|
||||
this.$modal.msgSuccess("删除成功");
|
||||
}).catch(() => {});
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、EditDialog组件修改详情
|
||||
|
||||
### 6.1 个人中介表单字段修改
|
||||
|
||||
| 行号 | 修改内容 |
|
||||
|-----|---------|
|
||||
| 46 | `form.certificateNo` → `form.personId` |
|
||||
| 54 | `form.indivType` → `form.personType` |
|
||||
| 66 | `form.indivSubType` → `form.personSubType` |
|
||||
| 80 | `form.indivGender` → `form.gender` |
|
||||
| 92 | `form.indivCertType` → `form.idType` |
|
||||
| 106 | `form.indivPhone` → `form.mobile` |
|
||||
| 110 | `form.indivWechat` → `form.wechatNo` |
|
||||
| 116 | `form.indivAddress` → `form.contactAddress` |
|
||||
| 121 | `form.indivCompany` → `form.company` |
|
||||
| 126 | `form.indivPosition` → `form.position` |
|
||||
| 133 | `form.indivRelatedId` → `form.relatedNumId` |
|
||||
| 138 | `form.indivRelation` → `form.relationType` |
|
||||
|
||||
### 6.2 实体中介表单字段修改
|
||||
|
||||
| 行号 | 修改内容 |
|
||||
|-----|---------|
|
||||
| 172 | `form.name` → `form.enterpriseName` |
|
||||
| 179 | `form.certificateNo` → `form.socialCreditCode` |
|
||||
| 190 | `form.corpType` → `form.enterpriseType` |
|
||||
| 202 | `form.corpNature` → `form.enterpriseNature` |
|
||||
| 227 | `form.corpIndustryCategory` → `form.industryClass` |
|
||||
| 234 | `form.corpIndustry` → `form.industryName` |
|
||||
| 217 | `form.corpEstablishDate` → `form.establishDate` |
|
||||
| 239 | `form.corpAddress` → `form.registerAddress` |
|
||||
| 244 | `form.corpLegalRep` → `form.legalRepresentative` |
|
||||
| 249-251 | 添加下拉框:`form.legalCertType` (证件类型) |
|
||||
| 254 | `form.corpLegalCertNo` → `form.legalCertNo` |
|
||||
| 260-284 | `form.corpShareholder1-5` → `form.shareholder1-5` |
|
||||
|
||||
### 6.3 Script部分修改
|
||||
|
||||
#### computed属性
|
||||
|
||||
```javascript
|
||||
isAddMode() {
|
||||
return !this.form || !this.form.bizId; // 原 intermediaryId
|
||||
}
|
||||
```
|
||||
|
||||
#### initDialogState方法
|
||||
|
||||
```javascript
|
||||
const isAdd = !this.form || !this.form.bizId; // 原 intermediaryId
|
||||
```
|
||||
|
||||
#### 删除方法
|
||||
|
||||
删除`handleCertificateNoChange`方法(v2.0无需字段同步)
|
||||
|
||||
#### 验证规则修改
|
||||
|
||||
**个人中介:**
|
||||
|
||||
```javascript
|
||||
indivRules: {
|
||||
name: [
|
||||
{ required: true, message: "姓名不能为空", trigger: "blur" },
|
||||
{ max: 100, message: "姓名长度不能超过100个字符", trigger: "blur" }
|
||||
],
|
||||
personId: [ // 原 certificateNo
|
||||
{ required: true, message: "证件号不能为空", trigger: "blur" },
|
||||
{ max: 50, message: "证件号长度不能超过50个字符", trigger: "blur" }
|
||||
],
|
||||
remark: [
|
||||
{ max: 500, message: "备注长度不能超过500个字符", trigger: "blur" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**实体中介:**
|
||||
|
||||
```javascript
|
||||
corpRules: {
|
||||
enterpriseName: [ // 原 name
|
||||
{ required: true, message: "机构名称不能为空", trigger: "blur" },
|
||||
{ max: 200, message: "机构名称长度不能超过200个字符", trigger: "blur" }
|
||||
],
|
||||
socialCreditCode: [ // 原 certificateNo
|
||||
{ required: true, message: "统一社会信用代码不能为空", trigger: "blur" },
|
||||
{ max: 50, message: "统一社会信用代码长度不能超过50个字符", trigger: "blur" }
|
||||
],
|
||||
remark: [
|
||||
{ max: 500, message: "备注长度不能超过500个字符", trigger: "blur" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 七、DetailDialog组件修改详情
|
||||
|
||||
### 7.1 核心字段修改
|
||||
|
||||
```vue
|
||||
<!-- 业务ID -->
|
||||
<el-descriptions-item label="业务ID">{{ detailData.bizId }}</el-descriptions-item>
|
||||
|
||||
<!-- 证件号/信用代码 -->
|
||||
<el-descriptions-item label="证件号/信用代码">
|
||||
<span v-if="detailData.intermediaryType === '1'">{{ detailData.personId || '-' }}</span>
|
||||
<span v-else>{{ detailData.socialCreditCode || '-' }}</span>
|
||||
</el-descriptions-item>
|
||||
```
|
||||
|
||||
### 7.2 个人中介字段修改
|
||||
|
||||
| 旧字段 | 新字段 |
|
||||
|--------|--------|
|
||||
| detailData.indivType | detailData.personType |
|
||||
| detailData.indivSubType | detailData.personSubType |
|
||||
| detailData.indivGenderName | detailData.genderName |
|
||||
| detailData.indivCertType | detailData.idType |
|
||||
| detailData.indivPhone | detailData.mobile |
|
||||
| detailData.indivWechat | detailData.wechatNo |
|
||||
| detailData.indivAddress | detailData.contactAddress |
|
||||
| detailData.indivCompany | detailData.company |
|
||||
| detailData.indivPosition | detailData.position |
|
||||
| detailData.indivRelatedId | detailData.relatedNumId |
|
||||
| detailData.indivRelation | detailData.relationType |
|
||||
|
||||
**新增字段:**
|
||||
- detailData.socialCreditCode (企业统一信用码)
|
||||
|
||||
### 7.3 实体中介字段修改
|
||||
|
||||
| 旧字段 | 新字段 |
|
||||
|--------|--------|
|
||||
| detailData.corpCreditCode | detailData.socialCreditCode |
|
||||
| detailData.corpType | detailData.enterpriseType |
|
||||
| detailData.corpNature | detailData.enterpriseNature |
|
||||
| detailData.corpIndustryCategory | detailData.industryClass |
|
||||
| detailData.corpIndustry | detailData.industryName |
|
||||
| detailData.corpEstablishDate | detailData.establishDate |
|
||||
| detailData.corpAddress | detailData.registerAddress |
|
||||
| detailData.corpLegalRep | detailData.legalRepresentative |
|
||||
| detailData.corpLegalCertType | detailData.legalCertType |
|
||||
| detailData.corpLegalCertNo | detailData.legalCertNo |
|
||||
| detailData.corpShareholder1-5 | detailData.shareholder1-5 |
|
||||
|
||||
---
|
||||
|
||||
## 八、ImportDialog组件修改详情
|
||||
|
||||
### 8.1 模板下载URL修正
|
||||
|
||||
**错误代码:**
|
||||
|
||||
```javascript
|
||||
this.download('dpc/intermediary/importPersonTemplate', ...)
|
||||
this.download('dpc/intermediary/importEntityTemplate', ...)
|
||||
```
|
||||
|
||||
**修正为:**
|
||||
|
||||
```javascript
|
||||
handleDownloadTemplate() {
|
||||
if (this.formData.importType === 'person') {
|
||||
this.download('ccdi/intermediary/importPersonTemplate', {}, `个人中介黑名单模板_${new Date().getTime()}.xlsx`);
|
||||
} else {
|
||||
this.download('ccdi/intermediary/importEntityTemplate', {}, `机构中介黑名单模板_${new Date().getTime()}.xlsx`);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 九、下拉框优化
|
||||
|
||||
### 9.1 新增下拉框
|
||||
|
||||
**法定代表人证件类型** (实体中介表单)
|
||||
|
||||
```vue
|
||||
<el-form-item label="法定代表人证件类型">
|
||||
<el-select v-model="form.legalCertType" placeholder="请选择证件类型" clearable style="width: 100%">
|
||||
<el-option
|
||||
v-for="item in certTypeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
```
|
||||
|
||||
### 9.2 已有下拉框验证
|
||||
|
||||
- ✅ 性别 (genderOptions)
|
||||
- ✅ 证件类型 (certTypeOptions)
|
||||
- ✅ 主体类型 (corpTypeOptions)
|
||||
- ✅ 企业性质 (corpNatureOptions)
|
||||
- ✅ 人员类型 (indivTypeOptions)
|
||||
- ✅ 人员子类型 (indivSubTypeOptions)
|
||||
- ✅ 关联关系 (relationTypeOptions)
|
||||
|
||||
---
|
||||
|
||||
## 十、测试计划
|
||||
|
||||
### 10.1 功能测试清单
|
||||
|
||||
**查询功能:**
|
||||
- [ ] 列表查询正常显示
|
||||
- [ ] 按姓名/机构名称模糊查询
|
||||
- [ ] 按证件号精确查询
|
||||
- [ ] 按中介类型筛选(个人/机构)
|
||||
- [ ] 分页功能正常
|
||||
|
||||
**个人中介CRUD:**
|
||||
- [ ] 新增个人中介 - 所有字段保存成功
|
||||
- [ ] 查看个人中介详情 - 所有字段正确显示
|
||||
- [ ] 修改个人中介 - 数据更新成功
|
||||
- [ ] 删除个人中介 - 删除成功
|
||||
|
||||
**机构中介CRUD:**
|
||||
- [ ] 新增机构中介 - 所有字段保存成功
|
||||
- [ ] 查看机构中介详情 - 所有字段正确显示
|
||||
- [ ] 修改机构中介 - 数据更新成功
|
||||
- [ ] 删除机构中介 - 删除成功
|
||||
|
||||
**导入功能:**
|
||||
- [ ] 下载个人中介导入模板成功
|
||||
- [ ] 下载机构中介导入模板成功
|
||||
- [ ] 个人中介数据导入成功
|
||||
- [ ] 机构中介数据导入成功
|
||||
- [ ] 导入时更新已存在数据功能正常
|
||||
|
||||
**下拉框验证:**
|
||||
- [ ] 性别下拉框显示正确
|
||||
- [ ] 证件类型下拉框显示正确
|
||||
- [ ] 法定代表人证件类型下拉框显示正确
|
||||
- [ ] 主体类型下拉框显示正确
|
||||
- [ ] 企业性质下拉框显示正确
|
||||
|
||||
### 10.2 回归测试
|
||||
|
||||
- [ ] 权限控制正常
|
||||
- [ ] 表单验证规则生效
|
||||
- [ ] 错误提示信息正确
|
||||
- [ ] 响应式布局正常
|
||||
- [ ] 浏览器兼容性(Chrome/Firefox/Edge)
|
||||
|
||||
---
|
||||
|
||||
## 十一、风险与注意事项
|
||||
|
||||
### 11.1 兼容性风险
|
||||
|
||||
**影响范围**: 所有中介黑名单相关功能
|
||||
|
||||
**缓解措施**:
|
||||
1. 完整的功能测试覆盖
|
||||
2. 保留旧版代码备份
|
||||
3. 分步骤部署,先测试环境验证
|
||||
|
||||
### 11.2 数据风险
|
||||
|
||||
**风险点**: 字段名变更可能导致数据丢失
|
||||
|
||||
**缓解措施**:
|
||||
1. 确保后端已做好兼容处理
|
||||
2. 导出测试数据进行对比验证
|
||||
3. 增量导入测试
|
||||
|
||||
### 11.3 注意事项
|
||||
|
||||
1. **字段同步**: 确保前后端字段完全一致,不要遗留转换逻辑
|
||||
2. **类型判断**: 所有详情查询必须根据`intermediaryType`调用不同接口
|
||||
3. **验证规则**: 个人和实体中介的必填字段不同,需分别配置
|
||||
4. **下拉框复用**: 法定代表人证件类型可复用`certTypeOptions`
|
||||
|
||||
---
|
||||
|
||||
## 十二、实施建议
|
||||
|
||||
### 12.1 实施步骤
|
||||
|
||||
1. **第一阶段**: API层修改
|
||||
- 新增详情查询接口
|
||||
- 删除旧版统一接口
|
||||
- 验证接口调用正常
|
||||
|
||||
2. **第二阶段**: 主页面修改
|
||||
- 修改数据模型
|
||||
- 修改核心方法
|
||||
- 测试查询和删除功能
|
||||
|
||||
3. **第三阶段**: 组件修改
|
||||
- EditDialog组件字段重命名
|
||||
- DetailDialog组件字段重命名
|
||||
- ImportDialog组件URL修正
|
||||
- 测试新增和修改功能
|
||||
|
||||
4. **第四阶段**: 全面测试
|
||||
- 功能测试
|
||||
- 回归测试
|
||||
- 兼容性测试
|
||||
|
||||
### 12.2 回滚方案
|
||||
|
||||
如发现问题严重,可按以下步骤回滚:
|
||||
|
||||
1. 恢复API层接口
|
||||
2. 恢复前端文件备份
|
||||
3. 重启前端服务
|
||||
4. 清理浏览器缓存
|
||||
|
||||
---
|
||||
|
||||
## 附录
|
||||
|
||||
### 附录A: 相关文档
|
||||
|
||||
- [中介黑名单管理API文档-v2.0.md](../api/中介黑名单管理API文档-v2.0.md)
|
||||
- [中介黑名单后端设计文档.md](../docs/中介黑名单后端.md)
|
||||
|
||||
### 附录B: 变更历史
|
||||
|
||||
| 版本 | 日期 | 作者 | 变更说明 |
|
||||
|-----|------|------|---------|
|
||||
| v1.0 | 2026-02-05 | Claude | 初始版本,完成前端适配设计 |
|
||||
|
||||
### 附录C: 审批记录
|
||||
|
||||
| 角色 | 姓名 | 审批状态 | 日期 |
|
||||
|-----|------|---------|------|
|
||||
| 开发 | - | 待审批 | - |
|
||||
| 测试 | - | 待审批 | - |
|
||||
| 产品 | - | 待审批 | - |
|
||||
Reference in New Issue
Block a user