Compare commits
17 Commits
worktree-l
...
81d4038302
| Author | SHA1 | Date | |
|---|---|---|---|
| 81d4038302 | |||
| 1af2677c05 | |||
| cca2e620b5 | |||
| e0ce344d09 | |||
| 85d4289ba7 | |||
| 4e55105c9e | |||
| 36698468f4 | |||
| 7084b3ee6a | |||
| b20abce3d4 | |||
| fe0eb8eca2 | |||
| 74c69956f9 | |||
| 5ccb68a98b | |||
| 1a944c2ba6 | |||
| dc8f1be4c3 | |||
| bc2959b93c | |||
| 72e2539134 | |||
| 16dc95de06 |
@@ -44,7 +44,41 @@
|
||||
"Bash(git rm:*)",
|
||||
"Bash(git add:*)",
|
||||
"Skill(document-skills:frontend-design)",
|
||||
"Bash(test:*)"
|
||||
"Bash(test:*)",
|
||||
"mcp__chrome-devtools__list_pages",
|
||||
"mcp__chrome-devtools__navigate_page",
|
||||
"mcp__chrome-devtools__take_snapshot",
|
||||
"mcp__chrome-devtools__take_screenshot",
|
||||
"mcp__zai-mcp-server__ui_to_artifact",
|
||||
"mcp__chrome-devtools__click",
|
||||
"Skill(backend-restart)",
|
||||
"Bash(tasklist:*)",
|
||||
"Bash(wmic:*)",
|
||||
"Bash(mvn spring-boot:run:*)",
|
||||
"Bash(timeout:*)",
|
||||
"mcp__chrome-devtools__wait_for",
|
||||
"Bash(start cmd /k \"mvn spring-boot:run -pl ruoyi-admin\")",
|
||||
"mcp__mysql__list_tables",
|
||||
"mcp__mysql__describe_table",
|
||||
"mcp__mysql__query",
|
||||
"Bash(grep:*)",
|
||||
"mcp__mysql__connect_db",
|
||||
"Skill(superpowers:writing-plans)",
|
||||
"Skill(superpowers:subagent-driven-development)",
|
||||
"Bash(chmod:*)",
|
||||
"Bash(ls:*)",
|
||||
"Bash(test_report.sh \")",
|
||||
"mcp__mysql__show_statement",
|
||||
"Bash(if not exist \"doc\\\\designs\" mkdir docdesigns)",
|
||||
"Bash(if [ ! -d \"D:\\\\ccdi\\\\ccdi\\\\ruoyi-ccdi\\\\src\\\\main\\\\java\\\\com\\\\ruoyi\\\\ccdi\\\\domain\\\\dto\" ])",
|
||||
"Bash(then mkdir -p \"D:\\\\ccdi\\\\ccdi\\\\ruoyi-ccdi\\\\src\\\\main\\\\java\\\\com\\\\ruoyi\\\\ccdi\\\\domain\\\\dto\")",
|
||||
"Bash(fi)",
|
||||
"Bash(cat:*)",
|
||||
"Skill(superpowers:executing-plans)",
|
||||
"Skill(superpowers:finishing-a-development-branch)",
|
||||
"Skill(superpowers:systematic-debugging)",
|
||||
"mcp__mysql__execute",
|
||||
"Skill(document-skills:xlsx)"
|
||||
]
|
||||
},
|
||||
"enabledMcpjsonServers": [
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
- 在进行需求分析与分解任务时,按照不同的模块分为不同的文件,创建模块名的文件夹并将对应文件保存在文件夹中,然后对模块的功能文件进行继续分解
|
||||
- 在使用/openspec:proposal时,自动开启深度思考模式,输入 “think more”、“think a lot”、“think harder” 或 “think longer” 触发更深层的思考
|
||||
- 在执行/openspec:apply后,使用code-simplifier 进行代码精简
|
||||
- 在分析生成需求文档时,每次都需要在doc目录下新建文件夹并以需求内容为命名
|
||||
|
||||
## Communication
|
||||
- 永远使用简体中文进行思考和对话
|
||||
|
||||
273
doc/README-中介黑名单测试部署.md
Normal file
273
doc/README-中介黑名单测试部署.md
Normal file
@@ -0,0 +1,273 @@
|
||||
# 中介黑名单管理模块 - 测试与部署文档
|
||||
|
||||
## 文件说明
|
||||
|
||||
本目录包含中介黑名单管理模块(v2.0)的测试脚本、API文档、菜单配置和测试报告模板。
|
||||
|
||||
```
|
||||
doc/
|
||||
├── scripts/
|
||||
│ ├── test-intermediary-api.sh # API自动化测试脚本
|
||||
│ └── cleanup-intermediary-test-data.sh # 测试数据清理脚本
|
||||
├── api/
|
||||
│ └── 中介黑名单管理API文档-v2.0.md # 完整的API接口文档
|
||||
├── test/
|
||||
│ └── intermediary-blacklist-test-report.md # 测试报告模板
|
||||
└── sql/
|
||||
└── menu-intermediary.sql # 菜单配置SQL
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 1. 执行菜单SQL
|
||||
|
||||
首先在数据库中执行菜单配置SQL,为系统添加中介黑名单管理菜单:
|
||||
|
||||
```bash
|
||||
mysql -u root -p ruoyi < sql/menu-intermediary.sql
|
||||
```
|
||||
|
||||
或者直接在MySQL客户端中执行:
|
||||
|
||||
```sql
|
||||
source D:/ccdi/ccdi/sql/menu-intermediary.sql;
|
||||
```
|
||||
|
||||
执行后,在角色管理中为相应角色分配权限。
|
||||
|
||||
### 2. 运行API测试脚本
|
||||
|
||||
确保后端服务已启动(http://localhost:8080),然后执行测试脚本:
|
||||
|
||||
```bash
|
||||
cd D:/ccdi/ccdi/doc/scripts
|
||||
bash test-intermediary-api.sh
|
||||
```
|
||||
|
||||
测试脚本会自动:
|
||||
- 获取Token
|
||||
- 测试查询列表
|
||||
- 测试新增个人中介
|
||||
- 测试新增实体中介
|
||||
- 测试查询详情
|
||||
- 测试修改操作
|
||||
- 测试唯一性校验
|
||||
- 测试条件查询
|
||||
|
||||
### 3. 清理测试数据
|
||||
|
||||
测试完成后,运行清理脚本删除测试数据:
|
||||
|
||||
```bash
|
||||
cd D:/ccdi/ccdi/doc/scripts
|
||||
bash cleanup-intermediary-test-data.sh
|
||||
```
|
||||
|
||||
### 4. 查看API文档
|
||||
|
||||
参考API文档进行接口对接:
|
||||
|
||||
- 文件位置: `doc/api/中介黑名单管理API文档-v2.0.md`
|
||||
- Swagger UI: http://localhost:8080/swagger-ui/index.html
|
||||
|
||||
### 5. 填写测试报告
|
||||
|
||||
根据测试结果填写测试报告模板:
|
||||
|
||||
- 文件位置: `doc/test/intermediary-blacklist-test-report.md`
|
||||
|
||||
---
|
||||
|
||||
## API接口列表
|
||||
|
||||
### 基础路径
|
||||
`/ccdi/intermediary`
|
||||
|
||||
### 主要接口
|
||||
|
||||
| 方法 | 路径 | 说明 | 权限 |
|
||||
|------|------|------|------|
|
||||
| GET | /list | 查询中介列表 | ccdi:intermediary:list |
|
||||
| GET | /person/{bizId} | 查询个人中介详情 | ccdi:intermediary:query |
|
||||
| GET | /entity/{socialCreditCode} | 查询实体中介详情 | ccdi:intermediary:query |
|
||||
| POST | /person | 新增个人中介 | ccdi:intermediary:add |
|
||||
| POST | /entity | 新增实体中介 | ccdi:intermediary:add |
|
||||
| PUT | /person | 修改个人中介 | ccdi:intermediary:edit |
|
||||
| PUT | /entity | 修改实体中介 | ccdi:intermediary:edit |
|
||||
| DELETE | /{ids} | 删除中介 | ccdi:intermediary:remove |
|
||||
| GET | /checkPersonIdUnique | 校验人员ID唯一性 | 无 |
|
||||
| GET | /checkSocialCreditCodeUnique | 校验统一社会信用代码唯一性 | 无 |
|
||||
| POST | /importPersonTemplate | 下载个人中介导入模板 | 无 |
|
||||
| POST | /importEntityTemplate | 下载实体中介导入模板 | 无 |
|
||||
| POST | /importPersonData | 导入个人中介数据 | ccdi:intermediary:import |
|
||||
| POST | /importEntityData | 导入实体中介数据 | ccdi:intermediary:import |
|
||||
|
||||
详细接口说明请参考API文档。
|
||||
|
||||
---
|
||||
|
||||
## 测试账号
|
||||
|
||||
- **用户名**: admin
|
||||
- **密码**: admin123
|
||||
- **角色**: 管理员
|
||||
|
||||
---
|
||||
|
||||
## 菜单权限说明
|
||||
|
||||
执行menu-intermediary.sql后,系统会创建以下权限:
|
||||
|
||||
| 权限标识 | 说明 |
|
||||
|---------|------|
|
||||
| ccdi:intermediary:query | 查询中介详情 |
|
||||
| ccdi:intermediary:list | 查询中介列表 |
|
||||
| ccdi:intermediary:add | 新增中介 |
|
||||
| ccdi:intermediary:edit | 修改中介 |
|
||||
| ccdi:intermediary:remove | 删除中介 |
|
||||
| ccdi:intermediary:export | 导出中介数据 |
|
||||
| ccdi:intermediary:import | 导入中介数据 |
|
||||
|
||||
在角色管理中为相应角色分配这些权限。
|
||||
|
||||
---
|
||||
|
||||
## 数据字典说明
|
||||
|
||||
模块使用的数据字典类型:
|
||||
|
||||
| 字典类型 | 字典名称 | 用途 |
|
||||
|---------|---------|------|
|
||||
| ccdi_indiv_gender | 个人中介性别 | 个人中介模板性别下拉框 |
|
||||
| ccdi_certificate_type | 证件类型 | 个人中介模板证件类型下拉框 |
|
||||
| ccdi_entity_type | 主体类型 | 机构中介模板主体类型下拉框 |
|
||||
| ccdi_enterprise_nature | 企业性质 | 机构中介模板企业性质下拉框 |
|
||||
| ccdi_data_source | 数据来源 | 数据来源字段映射 |
|
||||
|
||||
确保这些字典类型在系统中已配置。
|
||||
|
||||
---
|
||||
|
||||
## 测试用例统计
|
||||
|
||||
本模块共包含44个测试用例,涵盖:
|
||||
|
||||
1. **列表查询** (7个用例)
|
||||
- 基础列表查询
|
||||
- 分页查询
|
||||
- 按姓名查询
|
||||
- 按证件号查询
|
||||
- 按中介类型查询
|
||||
- 组合条件查询
|
||||
|
||||
2. **个人中介管理** (8个用例)
|
||||
- 新增个人中介
|
||||
- 字段验证
|
||||
- 唯一性校验
|
||||
- 修改个人中介
|
||||
- 查询详情
|
||||
|
||||
3. **实体中介管理** (7个用例)
|
||||
- 新增实体中介
|
||||
- 字段验证
|
||||
- 唯一性校验
|
||||
- 修改实体中介
|
||||
- 查询详情
|
||||
|
||||
4. **唯一性校验** (2个用例)
|
||||
- 人员ID唯一性
|
||||
- 统一社会信用代码唯一性
|
||||
|
||||
5. **删除功能** (3个用例)
|
||||
- 删除单条记录
|
||||
- 批量删除
|
||||
- 删除不存在的记录
|
||||
|
||||
6. **导入导出** (11个用例)
|
||||
- 模板下载
|
||||
- 数据导入
|
||||
- 数据导出
|
||||
- 异常处理
|
||||
|
||||
7. **权限控制** (6个用例)
|
||||
- 各功能点的权限验证
|
||||
|
||||
---
|
||||
|
||||
## 常见问题
|
||||
|
||||
### 1. 测试脚本无法执行
|
||||
|
||||
**问题**: bash: test-intermediary-api.sh: command not found
|
||||
|
||||
**解决**: 使用bash命令执行
|
||||
```bash
|
||||
bash test-intermediary-api.sh
|
||||
```
|
||||
|
||||
### 2. jq命令未安装
|
||||
|
||||
**问题**: jq: command not found
|
||||
|
||||
**解决**: 安装jq命令
|
||||
```bash
|
||||
# Ubuntu/Debian
|
||||
apt-get install jq
|
||||
|
||||
# CentOS/RHEL
|
||||
yum install jq
|
||||
|
||||
# Windows (使用Git Bash)
|
||||
# 下载jq for Windows并添加到PATH
|
||||
```
|
||||
|
||||
### 3. Token获取失败
|
||||
|
||||
**问题**: Token获取失败或返回null
|
||||
|
||||
**解决**:
|
||||
- 确保后端服务已启动
|
||||
- 确认用户名密码正确(admin/admin123)
|
||||
- 检查/login/test接口是否正常
|
||||
|
||||
### 4. 菜单不显示
|
||||
|
||||
**问题**: 执行SQL后菜单不显示
|
||||
|
||||
**解决**:
|
||||
- 在角色管理中为当前角色分配权限
|
||||
- 刷新页面或重新登录
|
||||
- 检查父级菜单ID(2000)是否存在
|
||||
|
||||
### 5. 导入失败
|
||||
|
||||
**问题**: 导入数据时报错
|
||||
|
||||
**解决**:
|
||||
- 确认Excel模板格式正确
|
||||
- 检查必填字段是否为空
|
||||
- 检查证件号或统一社会信用代码是否重复
|
||||
|
||||
---
|
||||
|
||||
## 版本历史
|
||||
|
||||
| 版本 | 日期 | 说明 |
|
||||
|------|------|------|
|
||||
| 2.0.0 | 2026-02-04 | 重构版本:使用MyBatis Plus,分离DTO/VO,统一业务ID |
|
||||
| 1.3.0 | 2026-01-29 | 新增接口分离:新增个人/机构专用新增接口 |
|
||||
| 1.2.0 | 2026-01-29 | 修改接口分离:新增个人/机构专用修改接口 |
|
||||
| 1.1.0 | 2026-01-29 | 添加字典下拉框功能,分离个人/机构模板 |
|
||||
| 1.0.0 | 2026-01-29 | 初始版本,支持个人和机构分类管理 |
|
||||
|
||||
---
|
||||
|
||||
## 联系方式
|
||||
|
||||
如有问题,请联系开发团队。
|
||||
|
||||
---
|
||||
|
||||
**最后更新**: 2026-02-04
|
||||
610
doc/api/中介黑名单管理API文档-v2.0.md
Normal file
610
doc/api/中介黑名单管理API文档-v2.0.md
Normal file
@@ -0,0 +1,610 @@
|
||||
# 中介黑名单管理 API 文档 v2.0
|
||||
|
||||
## 概述
|
||||
|
||||
中介黑名单管理模块提供个人和实体两类中介信息的增删改查、类型化模板下载和批量导入导出功能。
|
||||
|
||||
**基础路径**: `/ccdi/intermediary`
|
||||
|
||||
**权限标识前缀**: `ccdi:intermediary`
|
||||
|
||||
**文档版本**: v2.0
|
||||
|
||||
**更新日期**: 2026-02-04
|
||||
|
||||
---
|
||||
|
||||
## API 接口列表
|
||||
|
||||
### 1. 查询中介列表
|
||||
|
||||
**接口地址**: `GET /ccdi/intermediary/list`
|
||||
|
||||
**权限要求**: `ccdi:intermediary:list`
|
||||
|
||||
**请求参数** (Query Params):
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| name | String | 否 | 姓名/机构名称(模糊查询) |
|
||||
| certificateNo | String | 否 | 证件号/统一社会信用代码(精确查询) |
|
||||
| intermediaryType | String | 否 | 中介类型(1=个人, 2=实体) |
|
||||
| pageNum | Integer | 否 | 页码(默认1) |
|
||||
| pageSize | Integer | 否 | 每页数量(默认10) |
|
||||
|
||||
**响应示例**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"rows": [
|
||||
{
|
||||
"bizId": "I202602040001",
|
||||
"name": "张三",
|
||||
"certificateNo": "110101199001011234",
|
||||
"intermediaryType": "1",
|
||||
"intermediaryTypeName": "个人",
|
||||
"status": "0",
|
||||
"statusName": "正常",
|
||||
"remark": "测试数据",
|
||||
"createBy": "admin",
|
||||
"createTime": "2026-02-04 10:00:00"
|
||||
}
|
||||
],
|
||||
"total": 1
|
||||
}
|
||||
```
|
||||
|
||||
**响应字段说明**:
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
|--------|------|------|
|
||||
| bizId | String | 业务ID |
|
||||
| name | String | 姓名/机构名称 |
|
||||
| certificateNo | String | 证件号/统一社会信用代码 |
|
||||
| intermediaryType | String | 中介类型(1=个人, 2=实体) |
|
||||
| intermediaryTypeName | String | 中介类型名称 |
|
||||
| status | String | 状态(0=正常, 1=停用) |
|
||||
| statusName | String | 状态名称 |
|
||||
| remark | String | 备注 |
|
||||
| createBy | String | 创建人 |
|
||||
| createTime | String | 创建时间 |
|
||||
|
||||
---
|
||||
|
||||
### 2. 查询个人中介详情
|
||||
|
||||
**接口地址**: `GET /ccdi/intermediary/person/{bizId}`
|
||||
|
||||
**权限要求**: `ccdi:intermediary:query`
|
||||
|
||||
**路径参数**:
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| bizId | String | 是 | 业务ID |
|
||||
|
||||
**响应示例**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"data": {
|
||||
"bizId": "I202602040001",
|
||||
"name": "张三",
|
||||
"certificateNo": "110101199001011234",
|
||||
"intermediaryType": "1",
|
||||
"intermediaryTypeName": "个人",
|
||||
"status": "0",
|
||||
"statusName": "正常",
|
||||
"personType": "中介",
|
||||
"personSubType": "本人",
|
||||
"relationType": "正常",
|
||||
"gender": "M",
|
||||
"genderName": "男",
|
||||
"idType": "身份证",
|
||||
"personId": "110101199001011234",
|
||||
"mobile": "13800138000",
|
||||
"wechatNo": "zhangsan",
|
||||
"contactAddress": "北京市朝阳区",
|
||||
"company": "XX公司",
|
||||
"socialCreditCode": "91110000123456789X",
|
||||
"position": "经纪人",
|
||||
"relatedNumId": "",
|
||||
"relation": "",
|
||||
"remark": "测试数据",
|
||||
"createBy": "admin",
|
||||
"createTime": "2026-02-04 10:00:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. 查询实体中介详情
|
||||
|
||||
**接口地址**: `GET /ccdi/intermediary/entity/{socialCreditCode}`
|
||||
|
||||
**权限要求**: `ccdi:intermediary:query`
|
||||
|
||||
**路径参数**:
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| socialCreditCode | String | 是 | 统一社会信用代码 |
|
||||
|
||||
**响应示例**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"data": {
|
||||
"bizId": "I202602040002",
|
||||
"name": "XX中介公司",
|
||||
"certificateNo": "91110000123456789X",
|
||||
"intermediaryType": "2",
|
||||
"intermediaryTypeName": "实体",
|
||||
"status": "0",
|
||||
"statusName": "正常",
|
||||
"enterpriseName": "XX中介公司",
|
||||
"socialCreditCode": "91110000123456789X",
|
||||
"enterpriseType": "有限责任公司",
|
||||
"enterpriseNature": "民企",
|
||||
"industryClass": "房地产",
|
||||
"industryName": "房地产业",
|
||||
"establishDate": "2020-01-01",
|
||||
"registerAddress": "北京市朝阳区",
|
||||
"legalRepresentative": "张三",
|
||||
"legalCertType": "身份证",
|
||||
"legalCertNo": "110101199001011234",
|
||||
"shareholder1": "李四",
|
||||
"shareholder2": "王五",
|
||||
"shareholder3": "",
|
||||
"shareholder4": "",
|
||||
"shareholder5": "",
|
||||
"remark": "测试数据",
|
||||
"createBy": "admin",
|
||||
"createTime": "2026-02-04 10:00:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4. 新增个人中介
|
||||
|
||||
**接口地址**: `POST /ccdi/intermediary/person`
|
||||
|
||||
**权限要求**: `ccdi:intermediary:add`
|
||||
|
||||
**请求体** (application/json):
|
||||
```json
|
||||
{
|
||||
"name": "张三",
|
||||
"personType": "中介",
|
||||
"personSubType": "本人",
|
||||
"relationType": "正常",
|
||||
"gender": "M",
|
||||
"idType": "身份证",
|
||||
"personId": "110101199001011234",
|
||||
"mobile": "13800138000",
|
||||
"wechatNo": "zhangsan",
|
||||
"contactAddress": "北京市朝阳区",
|
||||
"company": "XX公司",
|
||||
"socialCreditCode": "91110000123456789X",
|
||||
"position": "经纪人",
|
||||
"relatedNumId": "",
|
||||
"relation": "",
|
||||
"remark": "测试数据"
|
||||
}
|
||||
```
|
||||
|
||||
**字段说明**:
|
||||
|
||||
| 字段名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| name | String | 是 | 姓名(最大100字符) |
|
||||
| personId | String | 是 | 证件号码(最大50字符) |
|
||||
| personType | String | 否 | 人员类型 |
|
||||
| personSubType | String | 否 | 人员子类型 |
|
||||
| relationType | String | 否 | 关系类型 |
|
||||
| gender | String | 否 | 性别(M=男, F=女, O=其他) |
|
||||
| idType | String | 否 | 证件类型 |
|
||||
| mobile | String | 否 | 手机号码(最大20字符) |
|
||||
| wechatNo | String | 否 | 微信号(最大50字符) |
|
||||
| contactAddress | String | 否 | 联系地址(最大200字符) |
|
||||
| company | String | 否 | 所在公司(最大200字符) |
|
||||
| socialCreditCode | String | 否 | 企业统一信用码(最大50字符) |
|
||||
| position | String | 否 | 职位(最大100字符) |
|
||||
| relatedNumId | String | 否 | 关联人员ID(最大50字符) |
|
||||
| relation | String | 否 | 关联关系(最大50字符) |
|
||||
| remark | String | 否 | 备注(最大500字符) |
|
||||
|
||||
**响应示例**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5. 新增实体中介
|
||||
|
||||
**接口地址**: `POST /ccdi/intermediary/entity`
|
||||
|
||||
**权限要求**: `ccdi:intermediary:add`
|
||||
|
||||
**请求体** (application/json):
|
||||
```json
|
||||
{
|
||||
"enterpriseName": "XX中介公司",
|
||||
"socialCreditCode": "91110000123456789X",
|
||||
"enterpriseType": "有限责任公司",
|
||||
"enterpriseNature": "民企",
|
||||
"industryClass": "房地产",
|
||||
"industryName": "房地产业",
|
||||
"establishDate": "2020-01-01",
|
||||
"registerAddress": "北京市朝阳区",
|
||||
"legalRepresentative": "张三",
|
||||
"legalCertType": "身份证",
|
||||
"legalCertNo": "110101199001011234",
|
||||
"shareholder1": "李四",
|
||||
"shareholder2": "王五",
|
||||
"shareholder3": "",
|
||||
"shareholder4": "",
|
||||
"shareholder5": "",
|
||||
"remark": "测试数据"
|
||||
}
|
||||
```
|
||||
|
||||
**字段说明**:
|
||||
|
||||
| 字段名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| enterpriseName | String | 是 | 机构名称(最大200字符) |
|
||||
| socialCreditCode | String | 否 | 统一社会信用代码(最大50字符) |
|
||||
| enterpriseType | String | 否 | 主体类型(最大50字符) |
|
||||
| enterpriseNature | String | 否 | 企业性质(最大50字符) |
|
||||
| industryClass | String | 否 | 行业分类(最大100字符) |
|
||||
| industryName | String | 否 | 所属行业(最大100字符) |
|
||||
| establishDate | Date | 否 | 成立日期 |
|
||||
| registerAddress | String | 否 | 注册地址(最大500字符) |
|
||||
| legalRepresentative | String | 否 | 法定代表人(最大100字符) |
|
||||
| legalCertType | String | 否 | 法定代表人证件类型(最大50字符) |
|
||||
| legalCertNo | String | 否 | 法定代表人证件号码(最大50字符) |
|
||||
| shareholder1-5 | String | 否 | 股东信息(每个最大100字符) |
|
||||
| remark | String | 否 | 备注(最大500字符) |
|
||||
|
||||
**响应示例**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 6. 修改个人中介
|
||||
|
||||
**接口地址**: `PUT /ccdi/intermediary/person`
|
||||
|
||||
**权限要求**: `ccdi:intermediary:edit`
|
||||
|
||||
**请求体** (application/json):
|
||||
```json
|
||||
{
|
||||
"bizId": "I202602040001",
|
||||
"name": "张三",
|
||||
"personType": "中介",
|
||||
"personSubType": "本人",
|
||||
"relationType": "正常",
|
||||
"gender": "M",
|
||||
"idType": "身份证",
|
||||
"personId": "110101199001011234",
|
||||
"mobile": "13800138000",
|
||||
"wechatNo": "zhangsan",
|
||||
"contactAddress": "北京市朝阳区",
|
||||
"company": "XX公司",
|
||||
"socialCreditCode": "91110000123456789X",
|
||||
"position": "经纪人",
|
||||
"relatedNumId": "",
|
||||
"relation": "",
|
||||
"remark": "测试数据"
|
||||
}
|
||||
```
|
||||
|
||||
**字段说明**: 与新增个人中介相同,bizId为必填项
|
||||
|
||||
**响应示例**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 7. 修改实体中介
|
||||
|
||||
**接口地址**: `PUT /ccdi/intermediary/entity`
|
||||
|
||||
**权限要求**: `ccdi:intermediary:edit`
|
||||
|
||||
**请求体** (application/json):
|
||||
```json
|
||||
{
|
||||
"socialCreditCode": "91110000123456789X",
|
||||
"enterpriseName": "XX中介公司",
|
||||
"enterpriseType": "有限责任公司",
|
||||
"enterpriseNature": "民企",
|
||||
"industryClass": "房地产",
|
||||
"industryName": "房地产业",
|
||||
"establishDate": "2020-01-01",
|
||||
"registerAddress": "北京市朝阳区",
|
||||
"legalRepresentative": "张三",
|
||||
"legalCertType": "身份证",
|
||||
"legalCertNo": "110101199001011234",
|
||||
"shareholder1": "李四",
|
||||
"shareholder2": "王五",
|
||||
"shareholder3": "",
|
||||
"shareholder4": "",
|
||||
"shareholder5": "",
|
||||
"remark": "测试数据"
|
||||
}
|
||||
```
|
||||
|
||||
**字段说明**: 与新增实体中介相同,socialCreditCode为必填项
|
||||
|
||||
**响应示例**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 8. 删除中介
|
||||
|
||||
**接口地址**: `DELETE /ccdi/intermediary/{ids}`
|
||||
|
||||
**权限要求**: `ccdi:intermediary:remove`
|
||||
|
||||
**路径参数**:
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| ids | String[] | 是 | 业务ID数组(逗号分隔) |
|
||||
|
||||
**响应示例**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 9. 校验人员ID唯一性
|
||||
|
||||
**接口地址**: `GET /ccdi/intermediary/checkPersonIdUnique`
|
||||
|
||||
**权限要求**: 无
|
||||
|
||||
**请求参数**:
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| personId | String | 是 | 证件号码 |
|
||||
| bizId | String | 否 | 排除的业务ID(修改时使用) |
|
||||
|
||||
**响应示例**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"data": true
|
||||
}
|
||||
```
|
||||
|
||||
**data字段说明**: true=唯一可用, false=已存在
|
||||
|
||||
---
|
||||
|
||||
### 10. 校验统一社会信用代码唯一性
|
||||
|
||||
**接口地址**: `GET /ccdi/intermediary/checkSocialCreditCodeUnique`
|
||||
|
||||
**权限要求**: 无
|
||||
|
||||
**请求参数**:
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| socialCreditCode | String | 是 | 统一社会信用代码 |
|
||||
| excludeId | String | 否 | 排除的ID(修改时使用) |
|
||||
|
||||
**响应示例**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"data": true
|
||||
}
|
||||
```
|
||||
|
||||
**data字段说明**: true=唯一可用, false=已存在
|
||||
|
||||
---
|
||||
|
||||
### 11. 下载个人中介导入模板
|
||||
|
||||
**接口地址**: `POST /ccdi/intermediary/importPersonTemplate`
|
||||
|
||||
**权限要求**: 无
|
||||
|
||||
**响应**: Excel模板文件下载
|
||||
|
||||
**Excel格式说明**:
|
||||
|
||||
**Sheet1: 个人中介信息**
|
||||
| 姓名 | 人员类型 | 人员子类型 | 关系类型 | 性别▼ | 证件类型▼ | 证件号码 | 手机号码 | 微信号 | 联系地址 | 所在公司 | 企业统一信用码 | 职位 | 关联人员ID | 关联关系 | 备注 |
|
||||
|------|---------|-----------|---------|-------|-----------|---------|---------|--------|---------|---------|--------------|-----|-----------|---------|------|
|
||||
| 张三 | 中介 | 本人 | 正常 | 男 | 身份证 | 110101199001011234 | 13800138000 | zhangsan | 北京市朝阳区 | XX公司 | 91110000XXXXXXXXXX | 经纪人 | - | - | 测试 |
|
||||
|
||||
**注**: 带▼标记的列包含下拉框,选项来自字典
|
||||
|
||||
---
|
||||
|
||||
### 12. 下载实体中介导入模板
|
||||
|
||||
**接口地址**: `POST /ccdi/intermediary/importEntityTemplate`
|
||||
|
||||
**权限要求**: 无
|
||||
|
||||
**响应**: Excel模板文件下载
|
||||
|
||||
**Excel格式说明**:
|
||||
|
||||
**Sheet1: 实体中介信息**
|
||||
| 机构名称 | 统一社会信用代码 | 主体类型▼ | 企业性质▼ | 行业分类 | 所属行业 | 成立日期 | 注册地址 | 法定代表人 | 法定代表人证件类型 | 法定代表人证件号码 | 股东1 | 股东2 | 股东3 | 股东4 | 股东5 | 备注 |
|
||||
|---------|-----------------|-----------|-----------|---------|---------|---------|---------|-----------|-------------------|-------------------|-------|-------|-------|-------|-------|------|
|
||||
| XX公司 | 91110000XXXXXXXXXX | 有限责任公司 | 民企 | 房地产 | 房地产业 | 2020-01-01 | 北京市朝阳区 | 张三 | 身份证 | 110101199001011234 | 李四 | 王五 | - | - | - | - |
|
||||
|
||||
---
|
||||
|
||||
### 13. 导入个人中介数据
|
||||
|
||||
**接口地址**: `POST /ccdi/intermediary/importPersonData`
|
||||
|
||||
**权限要求**: `ccdi:intermediary:import`
|
||||
|
||||
**请求参数** (multipart/form-data):
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| file | File | 是 | Excel文件 |
|
||||
| updateSupport | Boolean | 否 | 是否更新已存在数据(默认false) |
|
||||
|
||||
**响应示例**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "恭喜您,数据已全部导入成功!共10条"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 14. 导入实体中介数据
|
||||
|
||||
**接口地址**: `POST /ccdi/intermediary/importEntityData`
|
||||
|
||||
**权限要求**: `ccdi:intermediary:import`
|
||||
|
||||
**请求参数** (multipart/form-data):
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| file | File | 是 | Excel文件 |
|
||||
| updateSupport | Boolean | 否 | 是否更新已存在数据(默认false) |
|
||||
|
||||
**响应示例**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "恭喜您,数据已全部导入成功!共10条"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 字典数据说明
|
||||
|
||||
导入模板中的下拉框选项来自系统字典管理,相关字典类型:
|
||||
|
||||
| 字典类型 | 字典名称 | 用途 |
|
||||
|---------|---------|------|
|
||||
| ccdi_indiv_gender | 个人中介性别 | 个人中介模板性别下拉框 |
|
||||
| ccdi_certificate_type | 证件类型 | 个人中介模板证件类型下拉框 |
|
||||
| ccdi_entity_type | 主体类型 | 机构中介模板主体类型下拉框 |
|
||||
| ccdi_enterprise_nature | 企业性质 | 机构中介模板企业性质下拉框 |
|
||||
| ccdi_data_source | 数据来源 | 数据来源字段映射 |
|
||||
|
||||
---
|
||||
|
||||
## 错误码说明
|
||||
|
||||
| HTTP状态码 | 错误码 | 说明 |
|
||||
|-----------|--------|------|
|
||||
| 200 | 200 | 操作成功 |
|
||||
| 401 | 401 | 未授权,请先登录 |
|
||||
| 403 | 403 | 无权限访问 |
|
||||
| 500 | 500 | 服务器内部错误 |
|
||||
|
||||
---
|
||||
|
||||
## 业务错误信息
|
||||
|
||||
| 错误信息 | 说明 |
|
||||
|----------|------|
|
||||
| 姓名不能为空 | 个人中介新增/修改时姓名为空 |
|
||||
| 机构名称不能为空 | 实体中介新增/修改时机构名称为空 |
|
||||
| 证件号码不能为空 | 个人中介新增/修改时证件号码为空 |
|
||||
| 该证件号已存在 | 新增/导入时证件号重复 |
|
||||
| 该统一社会信用代码已存在 | 新增/导入时信用代码重复 |
|
||||
| 姓名长度不能超过100个字符 | 姓名超长 |
|
||||
| 证件号码长度不能超过50个字符 | 证件号码超长 |
|
||||
| 机构名称长度不能超过200个字符 | 机构名称超长 |
|
||||
|
||||
---
|
||||
|
||||
## 测试账号
|
||||
|
||||
- 用户名: `admin`
|
||||
- 密码: `admin123`
|
||||
|
||||
测试前请先调用 `/login/test` 接口获取Token。
|
||||
|
||||
---
|
||||
|
||||
## 更新日志
|
||||
|
||||
| 版本 | 日期 | 说明 |
|
||||
|------|------|------|
|
||||
| 1.0.0 | 2026-01-29 | 初始版本,支持个人和机构分类管理 |
|
||||
| 1.1.0 | 2026-01-29 | 添加字典下拉框功能,分离个人/机构模板 |
|
||||
| 1.2.0 | 2026-01-29 | 修改接口分离:新增个人/机构专用修改接口,修复中介类型修改问题 |
|
||||
| 1.3.0 | 2026-01-29 | 新增接口分离:新增个人/机构专用新增接口,统一接口设计 |
|
||||
| 2.0.0 | 2026-02-04 | 重构版本:使用MyBatis Plus,分离DTO/VO,统一业务ID(bizId),优化查询接口 |
|
||||
|
||||
---
|
||||
|
||||
## 主要变更说明 (v2.0)
|
||||
|
||||
### 架构变更
|
||||
- 使用MyBatis Plus替代原生MyBatis
|
||||
- 分离DTO(请求)和VO(响应)对象
|
||||
- 统一使用业务ID(bizId)作为主键
|
||||
|
||||
### 接口变更
|
||||
- 查询详情接口分离为个人和实体两个接口
|
||||
- 新增接口分离为个人和实体两个接口
|
||||
- 修改接口分离为个人和实体两个接口
|
||||
- 新增唯一性校验接口
|
||||
|
||||
### 数据模型变更
|
||||
- 个人中介使用`personId`作为证件号字段
|
||||
- 实体中介使用`socialCreditCode`作为统一社会信用代码字段
|
||||
- 删除了`intermediaryId`,统一使用`bizId`
|
||||
|
||||
### 查询功能增强
|
||||
- 支持按中介类型查询
|
||||
- 支持按姓名/机构名称模糊查询
|
||||
- 支持按证件号/统一社会信用代码精确查询
|
||||
File diff suppressed because it is too large
Load Diff
532
doc/designs/2026-02-04-intermediary-blacklist-design.md
Normal file
532
doc/designs/2026-02-04-intermediary-blacklist-design.md
Normal file
@@ -0,0 +1,532 @@
|
||||
# 中介黑名单管理模块 - 系统设计文档
|
||||
|
||||
## 文档信息
|
||||
|
||||
- **版本**: 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 | 初始版本,完成系统设计 |
|
||||
|
||||
---
|
||||
|
||||
**文档结束**
|
||||
23
doc/docs/ccdi_biz_intermediary.csv
Normal file
23
doc/docs/ccdi_biz_intermediary.csv
Normal file
@@ -0,0 +1,23 @@
|
||||
中介人员基本信息表:ccdi_biz_intermediary,,,,,,
|
||||
序号,字段名,类型,默认值,是否可为空,是否主键,注释
|
||||
1,biz_id,VARCHAR,-,否,是,人员ID
|
||||
2,person_type,VARCHAR,-,否,否,人员类型,中介、职业背债人、房产中介等
|
||||
3,person_sub_type,VARCHAR,-,是,否,人员子类型
|
||||
5,name,VARCHAR,-,否,否,姓名
|
||||
6,gender,CHAR,-,是,否,性别
|
||||
7,id_type,VARCHAR,身份证,否,否,证件类型
|
||||
8,person_id,VARCHAR,-,否,否,证件号码
|
||||
9,mobile,VARCHAR,-,是,否,手机号码
|
||||
10,wechat_no,VARCHAR,-,是,否,微信号
|
||||
11,contact_address,VARCHAR,-,是,否,联系地址
|
||||
12,company,VARCHAR,-,是,否,所在公司
|
||||
13,social_credit_code,VARCHAR,,,,企业统一信用码
|
||||
14,position,VARCHAR,-,是,否,职位
|
||||
15,related_num_id,VARCHAR,-,是,否,关联人员ID
|
||||
16,relation_type,VARCHAR,-,是,否,关系类型,如:配偶、子女、父母、兄弟姐妹等
|
||||
17,date_source,,,,,"数据来源,MANUAL:手动录入, SYSTEM:系统同步, IMPORT:批量导入, API:接口获取"
|
||||
18,remark,,,,,备注信息
|
||||
19,created_by,VARCHAR,-,否,-,记录创建人
|
||||
20,updated_by,VARCHAR,-,是,-,记录更新人
|
||||
21,create_time,DATETIME,,否,,记录创建时间
|
||||
22,update_time,DATETIME,-,是,-,记录更新时间
|
||||
|
26
doc/docs/ccdi_enterprise_base_info.csv
Normal file
26
doc/docs/ccdi_enterprise_base_info.csv
Normal file
@@ -0,0 +1,26 @@
|
||||
3.企业主体信息表:ccdi_enterprise_base_info,,,,,,
|
||||
序号,字段名,类型,默认值,是否可为空,是否主键,注释
|
||||
1,social_credit_code,VARCHAR,-,否,是,统一社会信用代码,员工企业关联关系表的外键
|
||||
2,enterprise_name,VARCHAR,-,否,-,企业名称
|
||||
3,enterprise_type,VARCHAR,-,否,-,"企业类型,有限责任公司、股份有限公司、合伙企业、个体工商户、外资企业等"
|
||||
4,enterprise_nature,VARCHAR,-,是,-,"企业性质,国企、民企、外企、合资、其他"
|
||||
5,industry_class,VARCHAR,-,是,-,行业分类
|
||||
6,industry_name,VARCHAR,-,是,-,所属行业
|
||||
7,establish_date,DATE,-,是,-,成立日期
|
||||
8,register_address,VARCHAR,-,是,-,注册地址
|
||||
9,legal_representative,VARCHAR,-,是,-,法定代表人
|
||||
10,legal_cert_type,VARCHAR,-,是,-,法定代表人证件类型
|
||||
11,legal_cert_no,VARCHAR,-,是,-,法定代表人证件号码
|
||||
12,shareholder1,VARCHAR,-,是,-,股东1
|
||||
13,shareholder2,VARCHAR,-,是,-,股东2
|
||||
14,shareholder3,VARCHAR,-,是,-,股东3
|
||||
15,shareholder4,VARCHAR,-,是,-,股东4
|
||||
16,shareholder5,VARCHAR,-,是,-,股东5
|
||||
17,status,VARCHAR,,,,经营状态
|
||||
18,create_time,DATETIME,当前时间,否,-,创建时间
|
||||
19,update_time,DATETIME,当前时间,否,-,更新时间
|
||||
20,created_by,VARCHAR,-,否,-,创建人
|
||||
21,updated_by,VARCHAR,-,是,-,更新人
|
||||
22,data_source,VARCHAR,MANUAL,是,-,"数据来源,MANUAL:手动录入, SYSTEM:系统同步, API:接口获取, IMPORT:批量导入"
|
||||
23,risk_level,VARCHAR(10),1,是,否,"风险等级:1-高风险, 2-中风险, 3-低风险"
|
||||
24,ent_source,VARCHAR(20),GENERAL,否,否,"企业来源:GENERAL-一般企业, EMP_RELATION-员工关系人, CREDIT_CUSTOMER-信贷客户, INTERMEDIARY-中介, BOTH-兼有"
|
||||
|
1
doc/docs/中介黑名单后端.md
Normal file
1
doc/docs/中介黑名单后端.md
Normal file
@@ -0,0 +1 @@
|
||||
实现中介黑名单管理的后端接口开发。中介分为个人中介和实体中介。个人中介的表字段为 @ccdi_biz_intermediary.csv。实体中介表字段为 @ccdi_enterprise_base_info.csv,风险等级为高风险,企业来源为中介。需要生成的接口:个人中介的新增、修改接口,以证件号为关联键;个人中介导入模板下载,个人中介文件上传导入新增;实体中介类的新增、修改接口;实体中介导入模板下载,上传导入新增;列表查询,要求联合查询两种类型的中介,也可以支持查询单种类的中介。
|
||||
919
doc/frontend/上传数据页面UI设计文档.md
Normal file
919
doc/frontend/上传数据页面UI设计文档.md
Normal file
@@ -0,0 +1,919 @@
|
||||
# 上传数据页面 UI 设计文档
|
||||
|
||||
## 1. 页面概述
|
||||
|
||||
### 1.1 功能描述
|
||||
上传数据页面是纪检初核系统中项目管理模块的核心页面,支持在一个项目中上传多个主体/账户数据进行汇总/独立分析。提供流水导入、征信导入、员工家庭关系导入、名单库选择等功能。
|
||||
|
||||
### 1.2 页面路径
|
||||
- 菜单位置:项目管理 > 项目详情 > 上传数据
|
||||
- 路由路径:`/project/:id/upload-data`
|
||||
|
||||
### 1.3 页面状态
|
||||
- 项目状态:已完成
|
||||
- 最后更新时间:2024-01-20 15:30
|
||||
|
||||
---
|
||||
|
||||
## 2. 页面布局
|
||||
|
||||
### 2.1 整体结构
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 面包屑导航:项目管理 / 项目详情 / 上传数据 │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ 页面标题区 │
|
||||
│ ┌───────────────────────────────────────────────────────┐ │
|
||||
│ │ 上传数据 │ │
|
||||
│ │ 项目状态:已完成 最后更新:2024-01-20 15:30 │ │
|
||||
│ │ 支持在一个项目中上传多个主体/账户数据,进行汇总/独立分析 │ │
|
||||
│ └───────────────────────────────────────────────────────┘ │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ 主要内容区(网格布局) │
|
||||
│ ┌─────────────────┐ ┌─────────────────┐ │
|
||||
│ │ 流水导入 │ │ 已上传流水查询 │ │
|
||||
│ │ [上传组件] │ │ [上传组件] │ │
|
||||
│ └─────────────────┘ └─────────────────┘ │
|
||||
│ ┌─────────────────┐ ┌─────────────────┐ │
|
||||
│ │ 征信导入 │ │ 员工家庭关系导入 │ │
|
||||
│ │ [上传组件] │ │ [上传组件] │ │
|
||||
│ └─────────────────┘ └─────────────────┘ │
|
||||
│ ┌─────────────────────────────────────────────┐ │
|
||||
│ │ 名单库选择 │ │
|
||||
│ │ ☑ 高风险人员名单(68人) ☑ 历史可疑人员名单 │ │
|
||||
│ │ ☑ 监管关注名单(32人) │ │
|
||||
│ └─────────────────────────────────────────────┘ │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ 数据质量检查区 │
|
||||
│ ┌────────────────────────────────────────────────────────┐ │
|
||||
│ │ 数据完整性 格式一致性 余额连续性 │ │
|
||||
│ │ 98.5% 95.2% 92.8% │ │
|
||||
│ │ 检查结果: [查看详情] │ │
|
||||
│ │ • 发现 23 条数据格式不一致 │ │
|
||||
│ │ • 发现 5 条余额连续性异常 │ │
|
||||
│ │ • 发现 12 条缺失关键字段 │ │
|
||||
│ └────────────────────────────────────────────────────────┘ │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ 操作按钮区 │
|
||||
│ [拉取本行信息] [生成报告] │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 2.2 响应式布局
|
||||
- 桌面端(≥1200px):4列网格布局
|
||||
- 平板端(768px-1199px):2列网格布局
|
||||
- 移动端(<768px):单列布局
|
||||
|
||||
---
|
||||
|
||||
## 3. 组件设计
|
||||
|
||||
### 3.1 FileUploadCard 上传卡片组件
|
||||
|
||||
**Props:**
|
||||
```typescript
|
||||
interface FileUploadCardProps {
|
||||
title: string; // 卡片标题
|
||||
description: string; // 描述文字
|
||||
acceptTypes: string[]; // 接受的文件类型,如 ['xlsx', 'xls', 'pdf']
|
||||
maxSize?: number; // 最大文件大小(MB),默认 10
|
||||
multiple?: boolean; // 是否支持多文件上传
|
||||
uploadUrl: string; // 上传接口地址
|
||||
onUploadSuccess?: (files: UploadedFile[]) => void;
|
||||
onUploadError?: (error: Error) => void;
|
||||
showFileList?: boolean; // 是否显示已上传文件列表
|
||||
}
|
||||
```
|
||||
|
||||
**UI 结构:**
|
||||
```vue
|
||||
<template>
|
||||
<el-card class="upload-card">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<h3>{{ title }}</h3>
|
||||
<el-tooltip :content="description" placement="top">
|
||||
<i class="el-icon-info"></i>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-upload
|
||||
class="upload-area"
|
||||
:action="uploadUrl"
|
||||
:accept="acceptTypes.join(',')"
|
||||
:multiple="multiple"
|
||||
:limit="10"
|
||||
:file-list="fileList"
|
||||
:on-success="handleSuccess"
|
||||
:on-error="handleError"
|
||||
:before-upload="beforeUpload"
|
||||
drag
|
||||
>
|
||||
<div class="upload-content">
|
||||
<i class="el-icon-upload"></i>
|
||||
<p>拖拽文件到此处或点击上传</p>
|
||||
<p class="upload-tip">支持格式: {{ acceptTypes.join(', ') }}</p>
|
||||
</div>
|
||||
</el-upload>
|
||||
|
||||
<div v-if="showFileList && uploadedFiles.length" class="file-list">
|
||||
<h4>已上传文件</h4>
|
||||
<el-table :data="uploadedFiles" size="small">
|
||||
<el-table-column prop="fileName" label="文件名" />
|
||||
<el-table-column prop="fileSize" label="大小" width="100" />
|
||||
<el-table-column prop="uploadTime" label="上传时间" width="160" />
|
||||
<el-table-column prop="status" label="状态" width="80">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.status === 'success' ? 'success' : 'danger'">
|
||||
{{ row.status === 'success' ? '成功' : '失败' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="100" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button type="text" size="small" @click="handleDelete(row)">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-card>
|
||||
</template>
|
||||
```
|
||||
|
||||
### 3.2 CheckboxGroupSelector 名单库选择组件
|
||||
|
||||
**Props:**
|
||||
```typescript
|
||||
interface CheckboxGroupSelectorProps {
|
||||
options: NameListOption[];
|
||||
modelValue: string[];
|
||||
onChange: (value: string[]) => void;
|
||||
}
|
||||
|
||||
interface NameListOption {
|
||||
label: string; // 显示文本
|
||||
value: string; // 选中值
|
||||
count: number; // 人数统计
|
||||
disabled?: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
**UI 结构:**
|
||||
```vue
|
||||
<template>
|
||||
<el-card class="name-list-selector">
|
||||
<template #header>
|
||||
<h3>名单库选择</h3>
|
||||
</template>
|
||||
<p class="selector-description">选择中介库管理内的名单</p>
|
||||
<el-checkbox-group v-model="selectedLists" @change="handleChange">
|
||||
<el-checkbox
|
||||
v-for="option in options"
|
||||
:key="option.value"
|
||||
:label="option.value"
|
||||
:disabled="option.disabled"
|
||||
>
|
||||
{{ option.label }}({{ option.count }}人)
|
||||
</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</el-card>
|
||||
</template>
|
||||
```
|
||||
|
||||
### 3.3 DataQualityPanel 数据质量检查面板
|
||||
|
||||
**Props:**
|
||||
```typescript
|
||||
interface DataQualityPanelProps {
|
||||
metrics: QualityMetric[];
|
||||
issues: QualityIssue[];
|
||||
onCheckQuality?: () => void;
|
||||
onViewDetails?: (issue: QualityIssue) => void;
|
||||
}
|
||||
|
||||
interface QualityMetric {
|
||||
name: string; // 指标名称
|
||||
value: number; // 百分比值
|
||||
status: 'good' | 'warning' | 'error';
|
||||
}
|
||||
|
||||
interface QualityIssue {
|
||||
type: string; // 问题类型
|
||||
count: number; // 数量
|
||||
description: string;
|
||||
details?: any[];
|
||||
}
|
||||
```
|
||||
|
||||
**UI 结构:**
|
||||
```vue
|
||||
<template>
|
||||
<el-card class="quality-panel">
|
||||
<template #header>
|
||||
<div class="panel-header">
|
||||
<h3>数据质量检查</h3>
|
||||
<el-button type="primary" size="small" @click="handleCheck">
|
||||
重新检查
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 质量指标 -->
|
||||
<div class="metrics-container">
|
||||
<div
|
||||
v-for="metric in metrics"
|
||||
:key="metric.name"
|
||||
class="metric-item"
|
||||
:class="`metric-${metric.status}`"
|
||||
>
|
||||
<el-progress
|
||||
type="circle"
|
||||
:percentage="metric.value"
|
||||
:status="metric.status"
|
||||
/>
|
||||
<span class="metric-name">{{ metric.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 问题列表 -->
|
||||
<div class="issues-section">
|
||||
<h4>检查结果</h4>
|
||||
<el-alert
|
||||
v-for="(issue, index) in issues"
|
||||
:key="index"
|
||||
:type="getIssueType(issue)"
|
||||
:closable="false"
|
||||
class="issue-item"
|
||||
>
|
||||
<template #title>
|
||||
发现 <strong>{{ issue.count }}</strong> {{ issue.description }}
|
||||
</template>
|
||||
</el-alert>
|
||||
<el-button type="text" @click="handleViewDetails">查看详情 →</el-button>
|
||||
</div>
|
||||
</el-card>
|
||||
</template>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 交互说明
|
||||
|
||||
### 4.1 文件上传流程
|
||||
|
||||
1. **拖拽上传**
|
||||
- 用户拖拽文件到上传区域
|
||||
- 显示上传进度条
|
||||
- 上传成功后显示成功提示
|
||||
- 自动添加到已上传文件列表
|
||||
|
||||
2. **点击上传**
|
||||
- 点击上传区域触发文件选择对话框
|
||||
- 选择文件后开始上传
|
||||
- 显示上传进度
|
||||
|
||||
3. **文件验证**
|
||||
- 文件格式验证:只接受指定格式
|
||||
- 文件大小验证:超过限制显示错误提示
|
||||
- 重复文件验证:同名文件提示是否覆盖
|
||||
|
||||
4. **上传状态**
|
||||
- 上传中:显示进度条
|
||||
- 上传成功:绿色勾选标记
|
||||
- 上传失败:红色错误标记,显示错误信息
|
||||
|
||||
### 4.2 名单库选择
|
||||
|
||||
1. 默认选中全部名单库
|
||||
2. 点击复选框切换选中状态
|
||||
3. 实时更新选中人数统计
|
||||
4. 取消选中时显示确认提示
|
||||
|
||||
### 4.3 数据质量检查
|
||||
|
||||
1. **自动触发**
|
||||
- 文件上传完成后自动触发
|
||||
- 显示检查进度
|
||||
|
||||
2. **手动触发**
|
||||
- 点击"重新检查"按钮
|
||||
- 覆盖之前的检查结果
|
||||
|
||||
3. **结果展示**
|
||||
- 三个核心指标以环形进度图展示
|
||||
- 颜色指示:绿色(≥95%)、黄色(85-94%)、红色(<85%)
|
||||
- 问题列表按严重程度排序
|
||||
|
||||
### 4.4 按钮操作
|
||||
|
||||
1. **拉取本行信息**
|
||||
- 点击后显示加载状态
|
||||
- 从本行系统拉取相关数据
|
||||
- 完成后显示成功提示并刷新页面
|
||||
|
||||
2. **生成报告**
|
||||
- 验证必须上传至少一个文件
|
||||
- 显示报告生成进度
|
||||
- 生成成功后跳转到报告页面
|
||||
|
||||
---
|
||||
|
||||
## 5. 数据结构
|
||||
|
||||
### 5.1 后端接口
|
||||
|
||||
#### 5.1.1 获取项目上传数据状态
|
||||
```typescript
|
||||
GET /api/project/{projectId}/upload-status
|
||||
|
||||
Response:
|
||||
{
|
||||
"code": 200,
|
||||
"data": {
|
||||
"projectStatus": "已完成",
|
||||
"lastUpdateTime": "2024-01-20 15:30:00",
|
||||
"uploadedFiles": {
|
||||
"transactionFiles": [], // 流水文件列表
|
||||
"inquiryFiles": [], // 征信文件列表
|
||||
"familyRelationFiles": [] // 家庭关系文件列表
|
||||
},
|
||||
"selectedNameLists": [], // 已选名单库
|
||||
"qualityMetrics": { // 质量指标
|
||||
"completeness": 98.5,
|
||||
"consistency": 95.2,
|
||||
"continuity": 92.8
|
||||
},
|
||||
"qualityIssues": [] // 质量问题列表
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 5.1.2 上传文件接口
|
||||
```typescript
|
||||
POST /api/project/{projectId}/upload
|
||||
Content-Type: multipart/form-data
|
||||
|
||||
Body:
|
||||
{
|
||||
"fileType": "transaction" | "inquiry" | "family_relation",
|
||||
"files": File[]
|
||||
}
|
||||
|
||||
Response:
|
||||
{
|
||||
"code": 200,
|
||||
"data": {
|
||||
"successCount": 2,
|
||||
"failedCount": 0,
|
||||
"uploadedFiles": [
|
||||
{
|
||||
"fileId": "123456",
|
||||
"fileName": "流水数据.xlsx",
|
||||
"fileSize": 2048576,
|
||||
"uploadTime": "2024-01-20 15:30:00",
|
||||
"status": "success"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 5.1.3 删除文件接口
|
||||
```typescript
|
||||
DELETE /api/project/{projectId}/file/{fileId}
|
||||
|
||||
Response:
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "删除成功"
|
||||
}
|
||||
```
|
||||
|
||||
#### 5.1.4 获取名单库列表
|
||||
```typescript
|
||||
GET /api/name-list/options
|
||||
|
||||
Response:
|
||||
{
|
||||
"code": 200,
|
||||
"data": [
|
||||
{
|
||||
"value": "high_risk",
|
||||
"label": "高风险人员名单",
|
||||
"count": 68
|
||||
},
|
||||
{
|
||||
"value": "history_suspicious",
|
||||
"label": "历史可疑人员名单",
|
||||
"count": 45
|
||||
},
|
||||
{
|
||||
"value": "regulatory_focus",
|
||||
"label": "监管关注名单",
|
||||
"count": 32
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### 5.1.5 更新名单库选择
|
||||
```typescript
|
||||
PUT /api/project/{projectId}/name-lists
|
||||
|
||||
Body:
|
||||
{
|
||||
"selectedLists": ["high_risk", "history_suspicious", "regulatory_focus"]
|
||||
}
|
||||
|
||||
Response:
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "更新成功"
|
||||
}
|
||||
```
|
||||
|
||||
#### 5.1.6 执行数据质量检查
|
||||
```typescript
|
||||
POST /api/project/{projectId}/quality-check
|
||||
|
||||
Response:
|
||||
{
|
||||
"code": 200,
|
||||
"data": {
|
||||
"checkId": "qc_123456",
|
||||
"status": "completed",
|
||||
"metrics": {
|
||||
"completeness": 98.5,
|
||||
"consistency": 95.2,
|
||||
"continuity": 92.8
|
||||
},
|
||||
"issues": [
|
||||
{
|
||||
"type": "format_inconsistency",
|
||||
"count": 23,
|
||||
"description": "条数据格式不一致"
|
||||
},
|
||||
{
|
||||
"type": "balance_anomaly",
|
||||
"count": 5,
|
||||
"description": "条余额连续性异常"
|
||||
},
|
||||
{
|
||||
"type": "missing_field",
|
||||
"count": 12,
|
||||
"description": "条缺失关键字段"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 5.1.7 拉取本行信息
|
||||
```typescript
|
||||
POST /api/project/{projectId}/pull-bank-info
|
||||
|
||||
Response:
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "拉取成功",
|
||||
"data": {
|
||||
"pulledRecords": 156,
|
||||
"pullTime": "2024-01-20 15:35:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 5.1.8 生成报告
|
||||
```typescript
|
||||
POST /api/project/{projectId}/generate-report
|
||||
|
||||
Response:
|
||||
{
|
||||
"code": 200,
|
||||
"data": {
|
||||
"reportId": "rpt_789012",
|
||||
"reportUrl": "/project/123/report/rpt_789012",
|
||||
"generateTime": "2024-01-20 15:40:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5.2 前端数据模型
|
||||
|
||||
```typescript
|
||||
// 上传文件类型
|
||||
type UploadFileType = 'transaction' | 'inquiry' | 'family_relation';
|
||||
|
||||
// 上传文件状态
|
||||
type UploadStatus = 'uploading' | 'success' | 'error';
|
||||
|
||||
// 上传的文件
|
||||
interface UploadedFile {
|
||||
fileId: string;
|
||||
fileName: string;
|
||||
fileSize: number;
|
||||
uploadTime: string;
|
||||
status: UploadStatus;
|
||||
errorMessage?: string;
|
||||
}
|
||||
|
||||
// 名单库选项
|
||||
interface NameListOption {
|
||||
value: string;
|
||||
label: string;
|
||||
count: number;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
// 质量指标
|
||||
interface QualityMetric {
|
||||
name: string;
|
||||
value: number;
|
||||
status: 'good' | 'warning' | 'error';
|
||||
}
|
||||
|
||||
// 质量问题
|
||||
interface QualityIssue {
|
||||
type: string;
|
||||
count: number;
|
||||
description: string;
|
||||
details?: any[];
|
||||
}
|
||||
|
||||
// 项目上传数据状态
|
||||
interface ProjectUploadStatus {
|
||||
projectStatus: string;
|
||||
lastUpdateTime: string;
|
||||
uploadedFiles: {
|
||||
transactionFiles: UploadedFile[];
|
||||
inquiryFiles: UploadedFile[];
|
||||
familyRelationFiles: UploadedFile[];
|
||||
};
|
||||
selectedNameLists: string[];
|
||||
qualityMetrics: {
|
||||
completeness: number;
|
||||
consistency: number;
|
||||
continuity: number;
|
||||
};
|
||||
qualityIssues: QualityIssue[];
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 样式规范
|
||||
|
||||
### 6.1 颜色规范
|
||||
```scss
|
||||
// 主色
|
||||
$primary-color: #409EFF;
|
||||
$success-color: #67C23A;
|
||||
$warning-color: #E6A23C;
|
||||
$danger-color: #F56C6C;
|
||||
$info-color: #909399;
|
||||
|
||||
// 中性色
|
||||
$text-primary: #303133;
|
||||
$text-regular: #606266;
|
||||
$text-secondary: #909399;
|
||||
$text-placeholder: #C0C4CC;
|
||||
|
||||
// 边框色
|
||||
$border-base: #DCDFE6;
|
||||
$border-light: #E4E7ED;
|
||||
$border-lighter: #EBEEF5;
|
||||
$border-extra-light: #F2F6FC;
|
||||
|
||||
// 背景色
|
||||
$bg-color: #F5F7FA;
|
||||
$card-bg: #FFFFFF;
|
||||
```
|
||||
|
||||
### 6.2 间距规范
|
||||
```scss
|
||||
$spacing-xs: 4px;
|
||||
$spacing-sm: 8px;
|
||||
$spacing-md: 16px;
|
||||
$spacing-lg: 24px;
|
||||
$spacing-xl: 32px;
|
||||
```
|
||||
|
||||
### 6.3 圆角规范
|
||||
```scss
|
||||
$border-radius-sm: 2px;
|
||||
$border-radius-base: 4px;
|
||||
$border-radius-lg: 8px;
|
||||
$border-radius-circle: 50%;
|
||||
```
|
||||
|
||||
### 6.4 阴影规范
|
||||
```scss
|
||||
$box-shadow-base: 0 2px 4px rgba(0, 0, 0, 0.12), 0 0 6px rgba(0, 0, 0, 0.04);
|
||||
$box-shadow-dark: 0 2px 8px rgba(0, 0, 0, 0.15), 0 0 6px rgba(0, 0, 0, 0.1);
|
||||
$box-shadow-light: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 组件样式代码
|
||||
|
||||
### 7.1 上传卡片样式
|
||||
```scss
|
||||
.upload-card {
|
||||
height: 100%;
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
h3 {
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: $text-primary;
|
||||
}
|
||||
|
||||
.el-icon-info {
|
||||
color: $info-color;
|
||||
cursor: help;
|
||||
}
|
||||
}
|
||||
|
||||
.upload-area {
|
||||
margin-bottom: $spacing-md;
|
||||
|
||||
.el-upload-dragger {
|
||||
width: 100%;
|
||||
height: 180px;
|
||||
border: 2px dashed $border-base;
|
||||
border-radius: $border-radius-lg;
|
||||
background: $bg-color;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
border-color: $primary-color;
|
||||
background: #F0F7FF;
|
||||
}
|
||||
}
|
||||
|
||||
.upload-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
|
||||
.el-icon-upload {
|
||||
font-size: 48px;
|
||||
color: $primary-color;
|
||||
margin-bottom: $spacing-sm;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: $spacing-xs 0;
|
||||
font-size: 14px;
|
||||
color: $text-regular;
|
||||
}
|
||||
|
||||
.upload-tip {
|
||||
font-size: 12px;
|
||||
color: $text-secondary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.file-list {
|
||||
border-top: 1px solid $border-light;
|
||||
padding-top: $spacing-md;
|
||||
|
||||
h4 {
|
||||
margin: 0 0 $spacing-sm 0;
|
||||
font-size: 14px;
|
||||
color: $text-primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 7.2 数据质量面板样式
|
||||
```scss
|
||||
.quality-panel {
|
||||
.panel-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
h3 {
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.metrics-container {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
margin-bottom: $spacing-lg;
|
||||
|
||||
.metric-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.el-progress {
|
||||
margin-bottom: $spacing-sm;
|
||||
}
|
||||
|
||||
.metric-name {
|
||||
font-size: 14px;
|
||||
color: $text-regular;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.issues-section {
|
||||
border-top: 1px solid $border-light;
|
||||
padding-top: $spacing-md;
|
||||
|
||||
h4 {
|
||||
margin: 0 0 $spacing-md 0;
|
||||
font-size: 14px;
|
||||
color: $text-primary;
|
||||
}
|
||||
|
||||
.issue-item {
|
||||
margin-bottom: $spacing-sm;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 7.3 页面整体布局样式
|
||||
```scss
|
||||
.upload-data-page {
|
||||
padding: $spacing-lg;
|
||||
background: $bg-color;
|
||||
min-height: calc(100vh - 84px);
|
||||
|
||||
.page-header {
|
||||
background: $card-bg;
|
||||
padding: $spacing-lg;
|
||||
border-radius: $border-radius-lg;
|
||||
margin-bottom: $spacing-lg;
|
||||
box-shadow: $box-shadow-base;
|
||||
|
||||
h1 {
|
||||
margin: 0 0 $spacing-sm 0;
|
||||
font-size: 24px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.page-info {
|
||||
display: flex;
|
||||
gap: $spacing-lg;
|
||||
font-size: 14px;
|
||||
color: $text-secondary;
|
||||
margin-top: $spacing-sm;
|
||||
|
||||
.info-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.label {
|
||||
margin-right: $spacing-xs;
|
||||
}
|
||||
|
||||
.status {
|
||||
color: $success-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.page-description {
|
||||
margin-top: $spacing-md;
|
||||
padding: $spacing-md;
|
||||
background: #F0F9FF;
|
||||
border-left: 3px solid $primary-color;
|
||||
border-radius: $border-radius-base;
|
||||
font-size: 14px;
|
||||
color: $text-regular;
|
||||
}
|
||||
}
|
||||
|
||||
.upload-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: $spacing-lg;
|
||||
margin-bottom: $spacing-lg;
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.full-width {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
.action-bar {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: $spacing-lg;
|
||||
margin-top: $spacing-xl;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 技术实现要点
|
||||
|
||||
### 8.1 文件上传
|
||||
- 使用 Element UI 的 `el-upload` 组件
|
||||
- 支持拖拽上传和点击上传
|
||||
- 实现文件类型和大小校验
|
||||
- 显示上传进度
|
||||
- 支持断点续传(可选)
|
||||
|
||||
### 8.2 数据质量检查
|
||||
- 异步执行检查任务
|
||||
- 使用 WebSocket 或轮询获取检查进度
|
||||
- 实时更新进度和结果
|
||||
|
||||
### 8.3 状态管理
|
||||
- 使用 Vuex 管理上传状态
|
||||
- 缓存已上传文件列表
|
||||
- 同步名单库选择状态
|
||||
|
||||
### 8.4 性能优化
|
||||
- 文件分片上传大文件
|
||||
- 使用 Web Worker 处理文件预检查
|
||||
- 虚拟滚动展示大量文件列表
|
||||
|
||||
---
|
||||
|
||||
## 9. 测试要点
|
||||
|
||||
### 9.1 功能测试
|
||||
- 文件上传各种格式
|
||||
- 文件大小限制验证
|
||||
- 删除文件功能
|
||||
- 名单库选择功能
|
||||
- 数据质量检查准确性
|
||||
- 报告生成功能
|
||||
|
||||
### 9.2 兼容性测试
|
||||
- 主流浏览器兼容
|
||||
- 不同屏幕尺寸适配
|
||||
- 文件格式兼容性
|
||||
|
||||
### 9.3 性能测试
|
||||
- 大文件上传性能
|
||||
- 多文件同时上传
|
||||
- 页面加载性能
|
||||
|
||||
### 9.4 异常处理测试
|
||||
- 网络中断处理
|
||||
- 文件上传失败处理
|
||||
- 服务器错误处理
|
||||
- 文件格式错误处理
|
||||
|
||||
---
|
||||
|
||||
## 10. 附录
|
||||
|
||||
### 10.1 相关页面
|
||||
- 项目详情页:`/project/:id/detail`
|
||||
- 参数配置页:`/project/:id/config`
|
||||
- 初核结果页:`/project/:id/result`
|
||||
- 报告页面:`/project/:id/report/:reportId`
|
||||
|
||||
### 10.2 权限要求
|
||||
- 需要项目成员权限
|
||||
- 上传操作需要编辑权限
|
||||
- 删除操作需要删除权限
|
||||
- 生成报告需要报告权限
|
||||
|
||||
### 10.3 相关文档
|
||||
- [Element UI Upload 组件文档](https://element.eleme.cn/#/zh-CN/component/upload)
|
||||
- [若依框架前端开发规范](../前端开发规范.md)
|
||||
- [项目接口文档](../API文档/项目管理模块.md)
|
||||
|
||||
---
|
||||
|
||||
**文档版本**: v1.0
|
||||
**创建时间**: 2024-01-30
|
||||
**最后更新**: 2024-01-30
|
||||
**文档状态**: 待评审
|
||||
336
doc/plans/2025-01-30-project-detail-page-design.md
Normal file
336
doc/plans/2025-01-30-project-detail-page-design.md
Normal file
@@ -0,0 +1,336 @@
|
||||
# 项目详情页面设计文档
|
||||
|
||||
**创建日期**: 2025-01-30
|
||||
**设计者**: Claude Code
|
||||
**状态**: 待实施
|
||||
|
||||
## 1. 概述
|
||||
|
||||
### 1.1 需求描述
|
||||
|
||||
开发一个项目详情页面,在项目管理列表中,点击项目那一行或者查看详情跳转到项目详情页面。顶部有一个导航栏,里面有按钮切换项目详情的不同页面。
|
||||
|
||||
### 1.2 功能模块
|
||||
|
||||
- **上传数据**(默认):批量上传流水、征信、员工家庭关系数据,选择名单库
|
||||
- **参数配置**:配置项目分析参数和排查规则
|
||||
- **结果总览**:查看项目分析结果的总体概况
|
||||
- **专项排查**:针对特定风险类型进行深度排查
|
||||
- **流水明细查询**:查询和筛选具体的流水记录明细
|
||||
|
||||
---
|
||||
|
||||
## 2. 整体架构设计
|
||||
|
||||
### 2.1 路由结构
|
||||
|
||||
采用独立页面路由方式:
|
||||
|
||||
```
|
||||
路由: /project-detail/:projectId
|
||||
组件: @/views/ccdiProject/detail/index.vue
|
||||
```
|
||||
|
||||
### 2.2 页面布局
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ 顶部导航 (PageHeader) │
|
||||
│ [返回] 项目名称 [状态] │
|
||||
│ [上传数据] [参数配置] [结果总览] ... │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 内容区域 (el-tabs) │
|
||||
│ 根据选中标签显示对应子页面 │
|
||||
│ │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 2.3 组件层次结构
|
||||
|
||||
```
|
||||
detail/
|
||||
├── index.vue # 主页面容器
|
||||
├── components/
|
||||
│ ├── PageHeader.vue # 顶部导航
|
||||
│ ├── UploadData.vue # 上传数据
|
||||
│ ├── ParameterConfig.vue # 参数配置
|
||||
│ ├── ResultOverview.vue # 结果总览
|
||||
│ ├── SpecialCheck.vue # 专项排查
|
||||
│ └── TransactionDetail.vue # 流水明细查询
|
||||
└── api.js # API 接口定义
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 上传数据页面详细设计
|
||||
|
||||
### 3.1 页面布局
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ 批量上传数据 [生成报告][拉取本行]│
|
||||
│ 支持在一个项目中上传多个主体/账户数据 │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
|
||||
│ │流水 │ │征信 │ │员工 │ │名单 │ │
|
||||
│ │导入 │ │导入 │ │家庭 │ │库选择 │ │
|
||||
│ └──────┘ └──────┘ └──────┘ └──────┘ │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ 数据质量检查区 │
|
||||
│ - 检查结果列表 │
|
||||
│ - 指标卡片(完整性、一致性、连续性) │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 3.2 功能模块
|
||||
|
||||
#### 3.2.1 流水导入
|
||||
- 支持格式:xlsx, xls, pdf
|
||||
- 拖拽上传 + 点击上传
|
||||
- 上传进度显示
|
||||
|
||||
#### 3.2.2 征信导入
|
||||
- 支持格式:html
|
||||
- 解析征信报告
|
||||
|
||||
#### 3.2.3 员工家庭关系导入
|
||||
- 支持格式:xlsx, xls
|
||||
- Excel 模板上传
|
||||
|
||||
#### 3.2.4 名单库选择
|
||||
- 高风险人员名单(68人)
|
||||
- 历史可疑人员名单(45人)
|
||||
- 监管关注名单(32人)
|
||||
|
||||
#### 3.2.5 数据质量检查
|
||||
- 数据完整性:98.5%
|
||||
- 格式一致性:95.2%
|
||||
- 余额连续性:92.8%
|
||||
- 检查结果详情
|
||||
|
||||
---
|
||||
|
||||
## 4. 其他子页面框架设计
|
||||
|
||||
### 4.1 参数配置页面
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ 参数配置 [保存] [重置] │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ ┌──────────┐ ┌──────────┐ │
|
||||
│ │ 预警阈值 │ │ 排查规则 │ │
|
||||
│ └──────────┘ └──────────┘ │
|
||||
│ ┌────────────────────────────────┐ │
|
||||
│ │ 高级配置(可折叠) │ │
|
||||
│ └────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 4.2 结果总览页面
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ 结果总览 [导出报告] [刷新] │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ ┌────────┐ ┌────────┐ ┌────────┐ │
|
||||
│ │ 总人数 │ │ 预警数 │ │ 可疑数 │ │
|
||||
│ └────────┘ └────────┘ └────────┘ │
|
||||
│ ┌──────────────┐ ┌──────────────┐ │
|
||||
│ │ 预警分布图 │ │ 趋势图 │ │
|
||||
│ └──────────────┘ └──────────────┘ │
|
||||
│ 预警排名表格(Top 10) │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 4.3 专项排查页面
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ 专项排查 [新增排查] [批量导出]│
|
||||
├─────────────────────────────────────────────┤
|
||||
│ 筛选条件:[风险类型] [严重程度] [状态] │
|
||||
│ 排查任务列表(表格) │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 4.4 流水明细查询页面
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ 流水明细查询 [导出] [高级查询] │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ 查询条件:[账户] [日期范围] [金额范围] │
|
||||
│ 流水明细表格(分页) │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 接口设计
|
||||
|
||||
### 5.1 接口列表
|
||||
|
||||
| 接口名称 | 方法 | 路径 | 说明 |
|
||||
|---------|------|------|------|
|
||||
| 获取项目详情 | GET | `/ccdi/project/detail/{projectId}` | 获取项目基本信息 |
|
||||
| 上传流水文件 | POST | `/ccdi/project/transaction/upload` | 上传流水文件 |
|
||||
| 上传征信文件 | POST | `/ccdi/project/credit/upload` | 上传征信报告 |
|
||||
| 上传员工关系 | POST | `/ccdi/project/employee/upload` | 上传员工家庭关系 |
|
||||
| 获取名单库列表 | GET | `/ccdi/project/namelist/list` | 获取可选名单库 |
|
||||
| 保存名单库选择 | POST | `/ccdi/project/namelist/save` | 保存选择的名单库 |
|
||||
| 获取数据质量检查 | GET | `/ccdi/project/quality/check` | 获取质量检查指标 |
|
||||
| 生成报告 | POST | `/ccdi/project/report/generate` | 生成分析报告 |
|
||||
| 拉取本行信息 | GET | `/ccdi/project/own/info` | 获取本行员工信息 |
|
||||
| 保存参数配置 | POST | `/ccdi/project/config/save` | 保存项目参数 |
|
||||
| 获取结果总览 | GET | `/ccdi/project/overview` | 获取结果统计数据 |
|
||||
| 获取排查列表 | GET | `/ccdi/project/check/list` | 获取专项排查列表 |
|
||||
| 查询流水明细 | GET | `/ccdi/project/transaction/list` | 分页查询流水 |
|
||||
|
||||
### 5.2 Mock 数据示例
|
||||
|
||||
**项目详情**
|
||||
```javascript
|
||||
{
|
||||
code: 200,
|
||||
data: {
|
||||
projectId: 1,
|
||||
projectName: "2025年第一季度初核排查",
|
||||
projectDesc: "针对全行员工进行第一季度常规排查",
|
||||
projectStatus: "0",
|
||||
createTime: "2025-01-15",
|
||||
targetCount: 1250,
|
||||
warningCount: 23
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**数据质量检查结果**
|
||||
```javascript
|
||||
{
|
||||
code: 200,
|
||||
data: {
|
||||
completeness: 98.5,
|
||||
consistency: 95.2,
|
||||
continuity: 92.8,
|
||||
issues: [
|
||||
{ type: "格式不一致", count: 23 },
|
||||
{ type: "余额连续性异常", count: 5 },
|
||||
{ type: "缺失关键字段", count: 12 }
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 状态管理
|
||||
|
||||
### 6.1 Vuex Store
|
||||
|
||||
```javascript
|
||||
// store/modules/projectDetail.js
|
||||
const state = {
|
||||
currentProject: null,
|
||||
activeTab: 'upload',
|
||||
uploadStatus: {
|
||||
transaction: false,
|
||||
credit: false,
|
||||
employee: false,
|
||||
nameList: []
|
||||
},
|
||||
qualityCheck: null,
|
||||
pageCache: {}
|
||||
}
|
||||
```
|
||||
|
||||
### 6.2 页面缓存
|
||||
|
||||
使用 `<keep-alive>` 缓存标签页内容,避免切换时重复加载。
|
||||
|
||||
---
|
||||
|
||||
## 7. 路由配置
|
||||
|
||||
```javascript
|
||||
// router/index.js
|
||||
{
|
||||
path: '/project-detail',
|
||||
component: Layout,
|
||||
hidden: true,
|
||||
children: [
|
||||
{
|
||||
path: ':projectId(\\d+)',
|
||||
component: () => import('@/views/ccdiProject/detail/index'),
|
||||
name: 'ProjectDetail',
|
||||
meta: {
|
||||
title: '项目详情',
|
||||
activeMenu: '/ccdiProject'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 文件目录结构
|
||||
|
||||
```
|
||||
ruoyi-ui/src/
|
||||
├── views/ccdiProject/
|
||||
│ ├── index.vue # 项目列表页(已存在)
|
||||
│ └── detail/ # 项目详情目录
|
||||
│ ├── index.vue # 主页面
|
||||
│ └── components/
|
||||
│ ├── PageHeader.vue
|
||||
│ ├── UploadData.vue
|
||||
│ ├── ParameterConfig.vue
|
||||
│ ├── ResultOverview.vue
|
||||
│ ├── SpecialCheck.vue
|
||||
│ └── TransactionDetail.vue
|
||||
├── api/
|
||||
│ └── ccdiProject/
|
||||
│ └── detail.js # 项目详情 API
|
||||
├── store/
|
||||
│ └── modules/
|
||||
│ └── projectDetail.js # Vuex 状态管理
|
||||
└── mock/
|
||||
└── projectDetail.js # Mock 数据
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 待实现功能清单
|
||||
|
||||
- [ ] 创建路由配置
|
||||
- [ ] 创建主页面容器
|
||||
- [ ] 实现 PageHeader 顶部导航组件
|
||||
- [ ] 实现 UploadData 上传数据页面
|
||||
- [ ] 流水导入功能
|
||||
- [ ] 征信导入功能
|
||||
- [ ] 员工家庭关系导入功能
|
||||
- [ ] 名单库选择功能
|
||||
- [ ] 数据质量检查展示
|
||||
- [ ] 实现 ParameterConfig 参数配置页面(框架)
|
||||
- [ ] 实现 ResultOverview 结果总览页面(框架)
|
||||
- [ ] 实现 SpecialCheck 专项排查页面(框架)
|
||||
- [ ] 实现 TransactionDetail 流水明细查询页面(框架)
|
||||
- [ ] 创建 Vuex 状态管理模块
|
||||
- [ ] 创建 API 接口定义
|
||||
- [ ] 创建 Mock 数据
|
||||
- [ ] 修改项目列表页跳转逻辑
|
||||
- [ ] 测试整体流程
|
||||
|
||||
---
|
||||
|
||||
## 10. 设计决策记录
|
||||
|
||||
| 决策点 | 选择 | 原因 |
|
||||
|-------|------|------|
|
||||
| 路由方式 | 独立页面路由 | 可通过URL直接访问,支持浏览器前进后退 |
|
||||
| 导航方式 | Tabs 标签页 | 交互流畅,适合频繁切换场景 |
|
||||
| 上传卡片布局 | 四列一行 | 节省空间,一目了然 |
|
||||
| 后端接口 | Mock 数据先行 | 前端可独立开发,后续对接真实接口 |
|
||||
| 状态管理 | Vuex | 便于跨组件数据共享和状态持久化 |
|
||||
1958
doc/plans/2026-02-04-intermediary-blacklist-implementation.md
Normal file
1958
doc/plans/2026-02-04-intermediary-blacklist-implementation.md
Normal file
File diff suppressed because it is too large
Load Diff
1177
doc/plans/2026-02-04-intermediary-blacklist-migration-test-plan.md
Normal file
1177
doc/plans/2026-02-04-intermediary-blacklist-migration-test-plan.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,887 @@
|
||||
# 中介黑名单入库逻辑变更 - 测试验证计划
|
||||
|
||||
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
||||
|
||||
**目标:** 验证中介黑名单从单表切换到双表(cdi_biz_intermediary + ccdi_enterprise_base_info)的所有CRUD操作正确性
|
||||
|
||||
**架构:** 个人中介插入 ccdi_biz_intermediary 表,机构中介插入 ccdi_enterprise_base_info 表(自动设置高风险和中介来源标识),查询层合并两个表的数据返回
|
||||
|
||||
**技术栈:** Spring Boot 3.5.8, MyBatis Plus 3.5.10, MySQL 8.2.0, Maven, JUnit 5
|
||||
|
||||
---
|
||||
|
||||
## 测试前准备
|
||||
|
||||
### Task 1: 确认数据库连接和环境
|
||||
|
||||
**Files:**
|
||||
- Check: `ruoyi-admin/src/main/resources/application-dev.yml`
|
||||
|
||||
**Step 1: 验证数据库连接配置**
|
||||
|
||||
检查配置文件中的数据库连接信息:
|
||||
```yaml
|
||||
spring:
|
||||
datasource:
|
||||
druid:
|
||||
master:
|
||||
url: jdbc:mysql://116.62.17.81:3306/ccdi
|
||||
username: root
|
||||
password: Kfcx@1234
|
||||
```
|
||||
|
||||
**Step 2: 确认目标表存在**
|
||||
|
||||
通过MCP工具验证表存在:
|
||||
```sql
|
||||
SHOW TABLES LIKE 'ccdi_biz_intermediary';
|
||||
SHOW TABLES LIKE 'ccdi_enterprise_base_info';
|
||||
```
|
||||
|
||||
预期: 两个表都存在
|
||||
|
||||
**Step 3: 检查表结构**
|
||||
|
||||
```sql
|
||||
DESCRIBE ccdi_biz_intermediary;
|
||||
DESCRIBE ccdi_enterprise_base_info;
|
||||
```
|
||||
|
||||
预期: 表结构与实体类字段匹配
|
||||
|
||||
---
|
||||
|
||||
## 功能测试 - 个人中介
|
||||
|
||||
### Task 2: 测试个人中介新增功能
|
||||
|
||||
**Files:**
|
||||
- Test API: `POST /ccdi/intermediary/person`
|
||||
- Backend: `CcdiIntermediaryBlacklistServiceImpl.insertPersonIntermediary()`
|
||||
|
||||
**Step 1: 准备测试数据**
|
||||
|
||||
创建测试数据文件 `test_person_add.json`:
|
||||
```json
|
||||
{
|
||||
"name": "测试个人中介",
|
||||
"certificateNo": "110101199001011234",
|
||||
"indivType": "中介",
|
||||
"indivSubType": "本人",
|
||||
"indivGender": "M",
|
||||
"indivCertType": "身份证",
|
||||
"indivPhone": "13800138000",
|
||||
"indivWechat": "test_wx001",
|
||||
"indivAddress": "北京市朝阳区测试路123号",
|
||||
"indivCompany": "测试公司",
|
||||
"indivPosition": "测试员",
|
||||
"indivRelatedId": "",
|
||||
"indivRelation": "",
|
||||
"status": "0",
|
||||
"remark": "自动化测试数据"
|
||||
}
|
||||
```
|
||||
|
||||
**Step 2: 获取认证Token**
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/login/test \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"username":"admin","password":"admin123"}' \
|
||||
| jq -r '.data.token'
|
||||
```
|
||||
|
||||
保存token到环境变量:
|
||||
```bash
|
||||
export TOKEN="获取到的token值"
|
||||
```
|
||||
|
||||
**Step 3: 调用新增接口**
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/ccdi/intermediary/person \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d @test_person_add.json
|
||||
```
|
||||
|
||||
预期响应:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功"
|
||||
}
|
||||
```
|
||||
|
||||
**Step 4: 验证数据插入到正确的表**
|
||||
|
||||
通过MCP查询数据库:
|
||||
```sql
|
||||
SELECT * FROM ccdi_biz_intermediary
|
||||
WHERE person_id = '110101199001011234';
|
||||
```
|
||||
|
||||
预期:
|
||||
- 找到1条记录
|
||||
- name = '测试个人中介'
|
||||
- date_source = 'MANUAL'
|
||||
|
||||
**Step 5: 验证旧表无数据**
|
||||
|
||||
```sql
|
||||
SELECT * FROM ccdi_intermediary_blacklist
|
||||
WHERE certificate_no = '110101199001011234';
|
||||
```
|
||||
|
||||
预期: 0条记录(表可能不存在或为空)
|
||||
|
||||
---
|
||||
|
||||
### Task 3: 测试个人中介列表查询
|
||||
|
||||
**Files:**
|
||||
- Test API: `GET /ccdi/intermediary/list`
|
||||
|
||||
**Step 1: 调用列表查询接口**
|
||||
|
||||
```bash
|
||||
curl -X GET "http://localhost:8080/ccdi/intermediary/list?name=测试个人中介" \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
预期响应:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "查询成功",
|
||||
"rows": [
|
||||
{
|
||||
"intermediaryId": 1,
|
||||
"name": "测试个人中介",
|
||||
"certificateNo": "110101199001011234",
|
||||
"intermediaryType": "1",
|
||||
"intermediaryTypeName": "个人",
|
||||
"status": "0",
|
||||
"statusName": "正常"
|
||||
}
|
||||
],
|
||||
"total": 1
|
||||
}
|
||||
```
|
||||
|
||||
**Step 2: 验证查询结果来源**
|
||||
|
||||
确认数据来自 `ccdi_biz_intermediary` 表
|
||||
|
||||
**Step 3: 测试分页查询**
|
||||
|
||||
```bash
|
||||
curl -X GET "http://localhost:8080/ccdi/intermediary/list?pageNum=1&pageSize=10" \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
预期: 返回分页数据
|
||||
|
||||
---
|
||||
|
||||
### Task 4: 测试个人中介详情查询
|
||||
|
||||
**Files:**
|
||||
- Test API: `GET /ccdi/intermediary/{id}`
|
||||
|
||||
**Step 1: 获取个人中介详情**
|
||||
|
||||
```bash
|
||||
curl -X GET "http://localhost:8080/ccdi/intermediary/1" \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
预期响应:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": {
|
||||
"intermediaryId": 1,
|
||||
"name": "测试个人中介",
|
||||
"certificateNo": "110101199001011234",
|
||||
"intermediaryType": "1",
|
||||
"indivType": "中介",
|
||||
"indivGender": "M",
|
||||
"indivGenderName": "男",
|
||||
"indivPhone": "13800138000",
|
||||
"indivWechat": "test_wx001",
|
||||
"indivAddress": "北京市朝阳区测试路123号",
|
||||
"indivCompany": "测试公司",
|
||||
"indivPosition": "测试员",
|
||||
"dataSource": "MANUAL",
|
||||
"dataSourceName": "手动录入"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Step 2: 验证所有字段正确映射**
|
||||
|
||||
检查个人专属字段是否正确:
|
||||
- indivType → person_type ✅
|
||||
- indivGender → gender ✅
|
||||
- indivPhone → mobile ✅
|
||||
- indivWechat → wechat_no ✅
|
||||
- indivAddress → contact_address ✅
|
||||
|
||||
---
|
||||
|
||||
### Task 5: 测试个人中介修改功能
|
||||
|
||||
**Files:**
|
||||
- Test API: `PUT /ccdi/intermediary/person`
|
||||
|
||||
**Step 1: 准备修改数据**
|
||||
|
||||
创建 `test_person_edit.json`:
|
||||
```json
|
||||
{
|
||||
"intermediaryId": 1,
|
||||
"name": "测试个人中介-已修改",
|
||||
"certificateNo": "110101199001011234",
|
||||
"indivType": "中介",
|
||||
"indivGender": "M",
|
||||
"indivPhone": "13900139000",
|
||||
"indivCompany": "新公司",
|
||||
"remark": "已修改"
|
||||
}
|
||||
```
|
||||
|
||||
**Step 2: 调用修改接口**
|
||||
|
||||
```bash
|
||||
curl -X PUT http://localhost:8080/ccdi/intermediary/person \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d @test_person_edit.json
|
||||
```
|
||||
|
||||
预期: `{ "code": 200, "msg": "操作成功" }`
|
||||
|
||||
**Step 3: 验证数据已更新**
|
||||
|
||||
```sql
|
||||
SELECT * FROM ccdi_biz_intermediary
|
||||
WHERE biz_id = 1;
|
||||
```
|
||||
|
||||
预期:
|
||||
- name = '测试个人中介-已修改'
|
||||
- mobile = '13900139000'
|
||||
- company = '新公司'
|
||||
|
||||
---
|
||||
|
||||
### Task 6: 测试个人中介删除功能
|
||||
|
||||
**Files:**
|
||||
- Test API: `DELETE /ccdi/intermediary/{ids}`
|
||||
|
||||
**Step 1: 调用删除接口**
|
||||
|
||||
```bash
|
||||
curl -X DELETE "http://localhost:8080/ccdi/intermediary/1" \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
预期: `{ "code": 200, "msg": "操作成功" }`
|
||||
|
||||
**Step 2: 验证数据已删除**
|
||||
|
||||
```sql
|
||||
SELECT * FROM ccdi_biz_intermediary
|
||||
WHERE biz_id = 1;
|
||||
```
|
||||
|
||||
预期: 0条记录
|
||||
|
||||
---
|
||||
|
||||
## 功能测试 - 机构中介
|
||||
|
||||
### Task 7: 测试机构中介新增功能
|
||||
|
||||
**Files:**
|
||||
- Test API: `POST /ccdi/intermediary/entity`
|
||||
- Backend: `CcdiIntermediaryBlacklistServiceImpl.insertEntityIntermediary()`
|
||||
|
||||
**Step 1: 准备测试数据**
|
||||
|
||||
创建 `test_entity_add.json`:
|
||||
```json
|
||||
{
|
||||
"name": "测试机构中介有限公司",
|
||||
"corpCreditCode": "91110000123456789X",
|
||||
"corpType": "有限责任公司",
|
||||
"corpNature": "民营企业",
|
||||
"corpIndustryCategory": "制造业",
|
||||
"corpIndustry": "通用设备制造业",
|
||||
"corpEstablishDate": "2020-01-01T00:00:00",
|
||||
"corpAddress": "北京市海淀区测试大街456号",
|
||||
"corpLegalRep": "张三",
|
||||
"corpLegalCertType": "身份证",
|
||||
"corpLegalCertNo": "110101198001011234",
|
||||
"corpShareholder1": "股东A",
|
||||
"corpShareholder2": "股东B",
|
||||
"status": "0",
|
||||
"remark": "机构中介测试数据"
|
||||
}
|
||||
```
|
||||
|
||||
**Step 2: 调用新增接口**
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/ccdi/intermediary/entity \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d @test_entity_add.json
|
||||
```
|
||||
|
||||
预期: `{ "code": 200, "msg": "操作成功" }`
|
||||
|
||||
**Step 3: 验证数据插入到正确的表**
|
||||
|
||||
```sql
|
||||
SELECT * FROM ccdi_enterprise_base_info
|
||||
WHERE social_credit_code = '91110000123456789X';
|
||||
```
|
||||
|
||||
预期:
|
||||
- 找到1条记录
|
||||
- enterprise_name = '测试机构中介有限公司'
|
||||
- **risk_level = '1' (高风险)** ✅
|
||||
- **ent_source = 'INTERMEDIARY' (中介来源)** ✅
|
||||
- data_source = 'MANUAL'
|
||||
|
||||
**Step 4: 验证关键字段自动设置**
|
||||
|
||||
检查两个重要标识:
|
||||
```sql
|
||||
SELECT
|
||||
social_credit_code,
|
||||
enterprise_name,
|
||||
risk_level,
|
||||
ent_source,
|
||||
data_source
|
||||
FROM ccdi_enterprise_base_info
|
||||
WHERE social_credit_code = '91110000123456789X';
|
||||
```
|
||||
|
||||
预期:
|
||||
- risk_level = '1' ✅
|
||||
- ent_source = 'INTERMEDIARY' ✅
|
||||
|
||||
---
|
||||
|
||||
### Task 8: 测试机构中介列表查询
|
||||
|
||||
**Files:**
|
||||
- Test API: `GET /ccdi/intermediary/list`
|
||||
|
||||
**Step 1: 查询机构中介**
|
||||
|
||||
```bash
|
||||
curl -X GET "http://localhost:8080/ccdi/intermediary/list?intermediaryType=2&name=测试机构" \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
预期响应:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"rows": [
|
||||
{
|
||||
"intermediaryId": 0,
|
||||
"name": "测试机构中介有限公司",
|
||||
"certificateNo": "91110000123456789X",
|
||||
"intermediaryType": "2",
|
||||
"intermediaryTypeName": "机构",
|
||||
"status": "0",
|
||||
"statusName": "正常"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Step 2: 验证ent_source过滤**
|
||||
|
||||
查询应该只返回 ent_source='INTERMEDIARY' 的记录
|
||||
|
||||
**Step 3: 混合查询(个人+机构)**
|
||||
|
||||
```bash
|
||||
curl -X GET "http://localhost:8080/ccdi/intermediary/list" \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
预期: 返回个人和机构中介的合并列表
|
||||
|
||||
---
|
||||
|
||||
### Task 9: 测试机构中介详情查询
|
||||
|
||||
**Files:**
|
||||
- Test API: `GET /ccdi/intermediary/{id}`
|
||||
|
||||
**Step 1: 获取机构中介详情**
|
||||
|
||||
注意: 机构中介的ID需要特殊处理(社会信用代码)
|
||||
|
||||
**Step 2: 验证机构字段映射**
|
||||
|
||||
检查字段映射:
|
||||
- corpCreditCode → social_credit_code ✅
|
||||
- name → enterprise_name ✅
|
||||
- corpType → enterprise_type ✅
|
||||
- corpNature → enterprise_nature ✅
|
||||
- corpIndustryCategory → industry_class ✅
|
||||
|
||||
---
|
||||
|
||||
### Task 10: 测试机构中介修改功能
|
||||
|
||||
**Files:**
|
||||
- Test API: `PUT /ccdi/intermediary/entity`
|
||||
|
||||
**Step 1: 准备修改数据**
|
||||
|
||||
创建 `test_entity_edit.json`:
|
||||
```json
|
||||
{
|
||||
"corpCreditCode": "91110000123456789X",
|
||||
"name": "测试机构中介有限公司-已修改",
|
||||
"corpType": "股份有限公司",
|
||||
"corpNature": "国有企业",
|
||||
"status": "0",
|
||||
"remark": "已修改"
|
||||
}
|
||||
```
|
||||
|
||||
**Step 2: 调用修改接口**
|
||||
|
||||
```bash
|
||||
curl -X PUT http://localhost:8080/ccdi/intermediary/entity \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d @test_entity_edit.json
|
||||
```
|
||||
|
||||
预期: `{ "code": 200, "msg": "操作成功" }`
|
||||
|
||||
**Step 3: 验证高风险和中介来源标识不变**
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
social_credit_code,
|
||||
enterprise_name,
|
||||
risk_level,
|
||||
ent_source
|
||||
FROM ccdi_enterprise_base_info
|
||||
WHERE social_credit_code = '91110000123456789X';
|
||||
```
|
||||
|
||||
预期:
|
||||
- enterprise_name = '测试机构中介有限公司-已修改'
|
||||
- risk_level 仍为 '1' ✅ (保持不变)
|
||||
- ent_source 仍为 'INTERMEDIARY' ✅ (保持不变)
|
||||
|
||||
---
|
||||
|
||||
## 导入功能测试
|
||||
|
||||
### Task 11: 测试个人中介Excel导入
|
||||
|
||||
**Files:**
|
||||
- Test API: `POST /ccdi/intermediary/importPersonData`
|
||||
|
||||
**Step 1: 下载导入模板**
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/ccdi/intermediary/importPersonTemplate \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
--output person_template.xlsx
|
||||
```
|
||||
|
||||
预期: 下载成功,文件包含所有个人字段
|
||||
|
||||
**Step 2: 准备测试Excel文件**
|
||||
|
||||
手动创建Excel文件或使用EasyExcel生成测试数据,包含:
|
||||
- 姓名: "导入测试个人"
|
||||
- 证件号: "110101199002022345"
|
||||
- 人员类型: "中介"
|
||||
- 性别: "M"
|
||||
- 手机号: "13800138001"
|
||||
- 微信号: "import_wx001"
|
||||
|
||||
**Step 3: 执行导入**
|
||||
|
||||
```bash
|
||||
curl -X POST "http://localhost:8080/ccdi/intermediary/importPersonData?updateSupport=false" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-F "file=@person_test_data.xlsx"
|
||||
```
|
||||
|
||||
预期:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "恭喜您,数据已全部导入成功!共 1 条"
|
||||
}
|
||||
```
|
||||
|
||||
**Step 4: 验证导入数据**
|
||||
|
||||
```sql
|
||||
SELECT * FROM ccdi_biz_intermediary
|
||||
WHERE person_id = '110101199002022345';
|
||||
```
|
||||
|
||||
预期:
|
||||
- 找到1条记录
|
||||
- date_source = 'IMPORT' ✅
|
||||
- name = '导入测试个人'
|
||||
|
||||
---
|
||||
|
||||
### Task 12: 测试机构中介Excel导入
|
||||
|
||||
**Files:**
|
||||
- Test API: `POST /ccdi/intermediary/importEntityData`
|
||||
|
||||
**Step 1: 下载导入模板**
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/ccdi/intermediary/importEntityTemplate \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
--output entity_template.xlsx
|
||||
```
|
||||
|
||||
预期: 下载成功,文件包含所有机构字段
|
||||
|
||||
**Step 2: 准备测试Excel文件**
|
||||
|
||||
创建Excel文件,包含:
|
||||
- 机构名称: "导入测试机构有限公司"
|
||||
- 统一社会信用代码: "91110000987654321A"
|
||||
- 主体类型: "有限责任公司"
|
||||
- 企业性质: "民营企业"
|
||||
- 法定代表人: "李四"
|
||||
|
||||
**Step 3: 执行导入**
|
||||
|
||||
```bash
|
||||
curl -X POST "http://localhost:8080/ccdi/intermediary/importEntityData?updateSupport=false" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-F "file=@entity_test_data.xlsx"
|
||||
```
|
||||
|
||||
预期:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "恭喜您,数据已全部导入成功!共 1 条"
|
||||
}
|
||||
```
|
||||
|
||||
**Step 4: 验证导入数据和自动设置标识**
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
social_credit_code,
|
||||
enterprise_name,
|
||||
risk_level,
|
||||
ent_source,
|
||||
data_source
|
||||
FROM ccdi_enterprise_base_info
|
||||
WHERE social_credit_code = '91110000987654321A';
|
||||
```
|
||||
|
||||
预期:
|
||||
- enterprise_name = '导入测试机构有限公司'
|
||||
- **risk_level = '1' (高风险)** ✅
|
||||
- **ent_source = 'INTERMEDIARY' (中介来源)** ✅
|
||||
- data_source = 'IMPORT' ✅
|
||||
|
||||
---
|
||||
|
||||
## 导出功能测试
|
||||
|
||||
### Task 13: 测试中介数据导出
|
||||
|
||||
**Files:**
|
||||
- Test API: `POST /ccdi/intermediary/export`
|
||||
|
||||
**Step 1: 导出所有数据**
|
||||
|
||||
```bash
|
||||
curl -X POST "http://localhost:8080/ccdi/intermediary/export" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{}' \
|
||||
--output intermediary_export.xlsx
|
||||
```
|
||||
|
||||
预期: 下载成功,Excel文件包含个人和机构数据
|
||||
|
||||
**Step 2: 验证导出数据完整性**
|
||||
|
||||
打开Excel文件,验证:
|
||||
- 包含个人中介字段(indivType, indivGender等)
|
||||
- 包含机构中介字段(corpType, corpNature等)
|
||||
- 数据正确映射
|
||||
|
||||
**Step 3: 测试条件导出**
|
||||
|
||||
```bash
|
||||
curl -X POST "http://localhost:8080/ccdi/intermediary/export" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"intermediaryType":"1"}' \
|
||||
--output person_export.xlsx
|
||||
```
|
||||
|
||||
预期: 只导出个人中介数据
|
||||
|
||||
---
|
||||
|
||||
## 边界条件测试
|
||||
|
||||
### Task 14: 测试唯一性约束
|
||||
|
||||
**Step 1: 个人中介证件号重复插入**
|
||||
|
||||
尝试插入相同person_id的记录:
|
||||
```bash
|
||||
# 使用Task 2的数据再次执行
|
||||
curl -X POST http://localhost:8080/ccdi/intermediary/person \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d @test_person_add.json
|
||||
```
|
||||
|
||||
预期: 根据实际业务逻辑,可能报唯一性约束错误或允许插入
|
||||
|
||||
**Step 2: 机构中介社会信用代码重复插入**
|
||||
|
||||
```bash
|
||||
# 使用Task 7的数据再次执行
|
||||
curl -X POST http://localhost:8080/ccdi/intermediary/entity \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d @test_entity_add.json
|
||||
```
|
||||
|
||||
预期: 报主键冲突错误(社会信用代码是主键)
|
||||
|
||||
---
|
||||
|
||||
### Task 15: 测试必填字段验证
|
||||
|
||||
**Step 1: 缺少姓名的个人中介**
|
||||
|
||||
创建 `test_person_no_name.json`:
|
||||
```json
|
||||
{
|
||||
"certificateNo": "110101199003033456",
|
||||
"status": "0"
|
||||
}
|
||||
```
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/ccdi/intermediary/person \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d @test_person_no_name.json
|
||||
```
|
||||
|
||||
预期: 返回验证错误,提示"姓名不能为空"
|
||||
|
||||
**Step 2: 缺少统一社会信用代码的机构中介**
|
||||
|
||||
创建 `test_entity_no_code.json`:
|
||||
```json
|
||||
{
|
||||
"name": "测试机构",
|
||||
"status": "0"
|
||||
}
|
||||
```
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/ccdi/intermediary/entity \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d @test_entity_no_code.json
|
||||
```
|
||||
|
||||
预期: 返回验证错误,提示"统一社会信用代码不能为空"
|
||||
|
||||
---
|
||||
|
||||
## 性能测试
|
||||
|
||||
### Task 16: 批量数据导入性能测试
|
||||
|
||||
**Step 1: 准备批量测试数据**
|
||||
|
||||
创建包含100条个人中介的Excel文件
|
||||
|
||||
**Step 2: 执行批量导入**
|
||||
|
||||
```bash
|
||||
time curl -X POST "http://localhost:8080/ccdi/intermediary/importPersonData?updateSupport=false" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-F "file=@person_batch_100.xlsx"
|
||||
```
|
||||
|
||||
预期:
|
||||
- 导入成功
|
||||
- 耗时 < 10秒
|
||||
|
||||
**Step 3: 验证数据一致性**
|
||||
|
||||
```sql
|
||||
SELECT COUNT(*) FROM ccdi_biz_intermediary
|
||||
WHERE date_source = 'IMPORT';
|
||||
```
|
||||
|
||||
预期: 导入的记录数与Excel文件一致
|
||||
|
||||
---
|
||||
|
||||
## 清理测试数据
|
||||
|
||||
### Task 17: 清理测试数据
|
||||
|
||||
**Step 1: 删除测试个人中介数据**
|
||||
|
||||
```sql
|
||||
DELETE FROM ccdi_biz_intermediary
|
||||
WHERE person_id IN (
|
||||
'110101199001011234',
|
||||
'110101199002022345'
|
||||
);
|
||||
```
|
||||
|
||||
**Step 2: 删除测试机构中介数据**
|
||||
|
||||
```sql
|
||||
DELETE FROM ccdi_enterprise_base_info
|
||||
WHERE social_credit_code IN (
|
||||
'91110000123456789X',
|
||||
'91110000987654321A'
|
||||
);
|
||||
```
|
||||
|
||||
**Step 3: 验证清理完成**
|
||||
|
||||
```sql
|
||||
SELECT COUNT(*) FROM ccdi_biz_intermediary
|
||||
WHERE person_id LIKE '110101199%';
|
||||
|
||||
SELECT COUNT(*) FROM ccdi_enterprise_base_info
|
||||
WHERE social_credit_code LIKE '91110000%';
|
||||
```
|
||||
|
||||
预期: 0条测试记录
|
||||
|
||||
---
|
||||
|
||||
## 测试报告生成
|
||||
|
||||
### Task 18: 生成测试报告
|
||||
|
||||
**Step 1: 汇总测试结果**
|
||||
|
||||
创建测试报告文件 `test_report.md`:
|
||||
|
||||
```markdown
|
||||
# 中介黑名单入库逻辑变更测试报告
|
||||
|
||||
## 测试环境
|
||||
- 数据库: MySQL 8.2.0
|
||||
- 服务端口: 8080
|
||||
- 测试时间: 2026-02-04
|
||||
|
||||
## 功能测试结果
|
||||
|
||||
### 个人中介
|
||||
- ✅ 新增功能 - 数据正确插入 ccdi_biz_intermediary
|
||||
- ✅ 列表查询 - 正确返回个人中介数据
|
||||
- ✅ 详情查询 - 所有字段正确映射
|
||||
- ✅ 修改功能 - 数据正确更新
|
||||
- ✅ 删除功能 - 数据正确删除
|
||||
- ✅ Excel导入 - 批量导入成功,data_source='IMPORT'
|
||||
- ✅ Excel导出 - 数据完整导出
|
||||
|
||||
### 机构中介
|
||||
- ✅ 新增功能 - 数据正确插入 ccdi_enterprise_base_info
|
||||
- ✅ 自动设置标识 - risk_level='1', ent_source='INTERMEDIARY'
|
||||
- ✅ 列表查询 - 正确返回机构中介数据
|
||||
- ✅ 详情查询 - 所有字段正确映射
|
||||
- ✅ 修改功能 - 数据正确更新,标识保持不变
|
||||
- ✅ Excel导入 - 批量导入成功,自动设置高风险和中介来源
|
||||
- ✅ Excel导出 - 数据完整导出
|
||||
|
||||
### 边界条件
|
||||
- ✅ 唯一性约束 - 社会信用代码主键冲突
|
||||
- ✅ 必填字段验证 - 姓名和证件号验证生效
|
||||
|
||||
### 性能测试
|
||||
- ✅ 100条数据导入 - 耗时 < 10秒
|
||||
|
||||
## 数据映射验证
|
||||
|
||||
### 个人中介字段映射
|
||||
| 原字段 | 新字段 | 状态 |
|
||||
|--------|--------|------|
|
||||
| intermediary_id | biz_id | ✅ |
|
||||
| certificate_no | person_id | ✅ |
|
||||
| indiv_type | person_type | ✅ |
|
||||
| indiv_gender | gender | ✅ |
|
||||
| indiv_phone | mobile | ✅ |
|
||||
| indiv_wechat | wechat_no | ✅ |
|
||||
| indiv_address | contact_address | ✅ |
|
||||
|
||||
### 机构中介字段映射
|
||||
| 原字段 | 新字段 | 状态 |
|
||||
|--------|--------|------|
|
||||
| corp_credit_code | social_credit_code | ✅ |
|
||||
| name | enterprise_name | ✅ |
|
||||
| corp_type | enterprise_type | ✅ |
|
||||
| corp_nature | enterprise_nature | ✅ |
|
||||
| - | risk_level='1' | ✅ 自动设置 |
|
||||
| - | ent_source='INTERMEDIARY' | ✅ 自动设置 |
|
||||
|
||||
## 结论
|
||||
✅ 所有测试通过,入库逻辑变更成功!
|
||||
```
|
||||
|
||||
**Step 2: 提交测试报告**
|
||||
|
||||
```bash
|
||||
git add test_report.md
|
||||
git commit -m "test: 添加中介黑名单变更测试报告"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **机构中介ID处理**: 机构中介的主键是字符串类型(social_credit_code),查询详情时需要特殊处理
|
||||
|
||||
2. **自动设置标识**: 机构中介新增/导入时自动设置 `risk_level='1'` 和 `ent_source='INTERMEDIARY'`,修改时不应改变这两个值
|
||||
|
||||
3. **查询合并**: 列表查询需要从两个表获取数据并合并返回前端
|
||||
|
||||
4. **数据来源标识**:
|
||||
- 手动新增: date_source/data_source = 'MANUAL'
|
||||
- Excel导入: date_source/data_source = 'IMPORT'
|
||||
|
||||
5. **分页查询**: 当前实现是先查询所有数据再手动分页,大数据量时可能需要优化
|
||||
|
||||
6. **删除操作**: 当前只支持个人中介的数字ID删除,机构中介删除需要扩展支持
|
||||
@@ -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: 审批记录
|
||||
|
||||
| 角色 | 姓名 | 审批状态 | 日期 |
|
||||
|-----|------|---------|------|
|
||||
| 开发 | - | 待审批 | - |
|
||||
| 测试 | - | 待审批 | - |
|
||||
| 产品 | - | 待审批 | - |
|
||||
177
doc/scripts/cleanup-intermediary-test-data.sh
Normal file
177
doc/scripts/cleanup-intermediary-test-data.sh
Normal file
@@ -0,0 +1,177 @@
|
||||
#!/bin/bash
|
||||
|
||||
################################################################################
|
||||
# 中介黑名单管理测试数据清理脚本
|
||||
# 功能: 清理测试脚本创建的测试数据
|
||||
# 作者: Claude Code
|
||||
# 日期: 2026-02-04
|
||||
################################################################################
|
||||
|
||||
# 颜色定义
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# 配置
|
||||
BASE_URL="http://localhost:8080"
|
||||
TEST_USERNAME="admin"
|
||||
TEST_PASSWORD="admin123"
|
||||
|
||||
# 输出函数
|
||||
print_header() {
|
||||
echo ""
|
||||
echo "========================================"
|
||||
echo "$1"
|
||||
echo "========================================"
|
||||
}
|
||||
|
||||
print_section() {
|
||||
echo ""
|
||||
echo -e "${YELLOW}=== $1 ===${NC}"
|
||||
}
|
||||
|
||||
print_success() {
|
||||
echo -e "${GREEN}✓ $1${NC}"
|
||||
}
|
||||
|
||||
print_error() {
|
||||
echo -e "${RED}✗ $1${NC}"
|
||||
}
|
||||
|
||||
# 获取Token
|
||||
get_token() {
|
||||
print_section "获取Token"
|
||||
|
||||
TOKEN=$(curl -s -X POST "${BASE_URL}/login/test" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"username\":\"${TEST_USERNAME}\",\"password\":\"${TEST_PASSWORD}\"}" | jq -r '.data.token')
|
||||
|
||||
if [ "$TOKEN" != "null" ] && [ -n "$TOKEN" ]; then
|
||||
print_success "Token获取成功"
|
||||
else
|
||||
print_error "Token获取失败"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 查询测试数据
|
||||
query_test_data() {
|
||||
print_section "查询测试数据"
|
||||
|
||||
echo "查询测试个人中介:"
|
||||
PERSON_RESPONSE=$(curl -s -X GET "${BASE_URL}/ccdi/intermediary/list?name=测试中介个人&intermediaryType=1" \
|
||||
-H "Authorization: Bearer $TOKEN")
|
||||
|
||||
echo "$PERSON_RESPONSE" | jq '.'
|
||||
|
||||
PERSON_IDS=$(echo "$PERSON_RESPONSE" | jq -r '.rows[].bizId // empty')
|
||||
|
||||
echo ""
|
||||
echo "查询测试实体中介:"
|
||||
ENTITY_RESPONSE=$(curl -s -X GET "${BASE_URL}/ccdi/intermediary/list?name=测试中介公司&intermediaryType=2" \
|
||||
-H "Authorization: Bearer $TOKEN")
|
||||
|
||||
echo "$ENTITY_RESPONSE" | jq '.'
|
||||
|
||||
ENTITY_IDS=$(echo "$ENTITY_RESPONSE" | jq -r '.rows[].bizId // empty')
|
||||
}
|
||||
|
||||
# 删除测试数据
|
||||
delete_test_data() {
|
||||
print_section "删除测试数据"
|
||||
|
||||
# 删除测试个人中介
|
||||
if [ -n "$PERSON_IDS" ]; then
|
||||
echo "删除测试个人中介: $PERSON_IDS"
|
||||
DELETE_RESPONSE=$(curl -s -X DELETE "${BASE_URL}/ccdi/intermediary/${PERSON_IDS}" \
|
||||
-H "Authorization: Bearer $TOKEN")
|
||||
|
||||
echo "$DELETE_RESPONSE" | jq '.'
|
||||
|
||||
code=$(echo "$DELETE_RESPONSE" | jq -r '.code')
|
||||
if [ "$code" == "200" ]; then
|
||||
print_success "测试个人中介删除成功"
|
||||
else
|
||||
print_error "测试个人中介删除失败"
|
||||
fi
|
||||
else
|
||||
echo "没有找到测试个人中介数据"
|
||||
fi
|
||||
|
||||
# 删除测试实体中介
|
||||
if [ -n "$ENTITY_IDS" ]; then
|
||||
echo ""
|
||||
echo "删除测试实体中介: $ENTITY_IDS"
|
||||
DELETE_RESPONSE=$(curl -s -X DELETE "${BASE_URL}/ccdi/intermediary/${ENTITY_IDS}" \
|
||||
-H "Authorization: Bearer $TOKEN")
|
||||
|
||||
echo "$DELETE_RESPONSE" | jq '.'
|
||||
|
||||
code=$(echo "$DELETE_RESPONSE" | jq -r '.code')
|
||||
if [ "$code" == "200" ]; then
|
||||
print_success "测试实体中介删除成功"
|
||||
else
|
||||
print_error "测试实体中介删除失败"
|
||||
fi
|
||||
else
|
||||
echo ""
|
||||
echo "没有找到测试实体中介数据"
|
||||
fi
|
||||
}
|
||||
|
||||
# 验证删除结果
|
||||
verify_deletion() {
|
||||
print_section "验证删除结果"
|
||||
|
||||
echo "验证测试个人中介是否已删除:"
|
||||
VERIFY_PERSON=$(curl -s -X GET "${BASE_URL}/ccdi/intermediary/list?name=测试中介个人&intermediaryType=1" \
|
||||
-H "Authorization: Bearer $TOKEN")
|
||||
|
||||
TOTAL=$(echo "$VERIFY_PERSON" | jq -r '.total')
|
||||
if [ "$TOTAL" == "0" ]; then
|
||||
print_success "测试个人中介已全部删除"
|
||||
else
|
||||
print_error "仍有 $TOTAL 条测试个人中介数据未删除"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "验证测试实体中介是否已删除:"
|
||||
VERIFY_ENTITY=$(curl -s -X GET "${BASE_URL}/ccdi/intermediary/list?name=测试中介公司&intermediaryType=2" \
|
||||
-H "Authorization: Bearer $TOKEN")
|
||||
|
||||
TOTAL=$(echo "$VERIFY_ENTITY" | jq -r '.total')
|
||||
if [ "$TOTAL" == "0" ]; then
|
||||
print_success "测试实体中介已全部删除"
|
||||
else
|
||||
print_error "仍有 $TOTAL 条测试实体中介数据未删除"
|
||||
fi
|
||||
}
|
||||
|
||||
# 主函数
|
||||
main() {
|
||||
print_header "中介黑名单测试数据清理开始"
|
||||
|
||||
# 检查jq命令
|
||||
if ! command -v jq &> /dev/null; then
|
||||
print_error "jq命令未安装,请先安装: apt-get install jq 或 yum install jq"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 获取Token
|
||||
get_token
|
||||
|
||||
# 查询测试数据
|
||||
query_test_data
|
||||
|
||||
# 删除测试数据
|
||||
delete_test_data
|
||||
|
||||
# 验证删除结果
|
||||
verify_deletion
|
||||
|
||||
print_header "清理完成"
|
||||
}
|
||||
|
||||
# 执行主函数
|
||||
main
|
||||
33
doc/scripts/run-cleanup.bat
Normal file
33
doc/scripts/run-cleanup.bat
Normal file
@@ -0,0 +1,33 @@
|
||||
@echo off
|
||||
REM =====================================================
|
||||
REM 中介黑名单管理 测试数据清理脚本 (Windows版本)
|
||||
REM 功能: 在Windows上清理测试数据
|
||||
REM 作者: Claude Code
|
||||
REM 日期: 2026-02-04
|
||||
REM =====================================================
|
||||
|
||||
echo ========================================
|
||||
echo 中介黑名单测试数据清理
|
||||
echo ========================================
|
||||
echo.
|
||||
|
||||
REM 检查Git Bash是否安装
|
||||
where bash >nul 2>nul
|
||||
if %ERRORLEVEL% NEQ 0 (
|
||||
echo 错误: 未找到Git Bash
|
||||
echo 请安装Git for Windows或在Git Bash中运行此脚本
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
REM 执行清理脚本
|
||||
echo 正在清理测试数据...
|
||||
echo.
|
||||
bash "D:/ccdi/ccdi/doc/scripts/cleanup-intermediary-test-data.sh"
|
||||
|
||||
echo.
|
||||
echo ========================================
|
||||
echo 清理完成
|
||||
echo ========================================
|
||||
echo.
|
||||
pause
|
||||
33
doc/scripts/run-test.bat
Normal file
33
doc/scripts/run-test.bat
Normal file
@@ -0,0 +1,33 @@
|
||||
@echo off
|
||||
REM =====================================================
|
||||
REM 中介黑名单管理 API 测试脚本 (Windows版本)
|
||||
REM 功能: 在Windows上执行API测试
|
||||
REM 作者: Claude Code
|
||||
REM 日期: 2026-02-04
|
||||
REM =====================================================
|
||||
|
||||
echo ========================================
|
||||
echo 中介黑名单管理 API 测试
|
||||
echo ========================================
|
||||
echo.
|
||||
|
||||
REM 检查Git Bash是否安装
|
||||
where bash >nul 2>nul
|
||||
if %ERRORLEVEL% NEQ 0 (
|
||||
echo 错误: 未找到Git Bash
|
||||
echo 请安装Git for Windows或在Git Bash中运行此脚本
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
REM 执行测试脚本
|
||||
echo 正在执行API测试...
|
||||
echo.
|
||||
bash "D:/ccdi/ccdi/doc/scripts/test-intermediary-api.sh"
|
||||
|
||||
echo.
|
||||
echo ========================================
|
||||
echo 测试完成
|
||||
echo ========================================
|
||||
echo.
|
||||
pause
|
||||
363
doc/scripts/test-intermediary-api.sh
Normal file
363
doc/scripts/test-intermediary-api.sh
Normal file
@@ -0,0 +1,363 @@
|
||||
#!/bin/bash
|
||||
|
||||
################################################################################
|
||||
# 中介黑名单管理 API 测试脚本
|
||||
# 功能: 测试中介黑名单管理模块的所有接口
|
||||
# 作者: Claude Code
|
||||
# 日期: 2026-02-04
|
||||
################################################################################
|
||||
|
||||
# 颜色定义
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# 配置
|
||||
BASE_URL="http://localhost:8080"
|
||||
TEST_USERNAME="admin"
|
||||
TEST_PASSWORD="admin123"
|
||||
|
||||
# 输出函数
|
||||
print_header() {
|
||||
echo ""
|
||||
echo "========================================"
|
||||
echo "$1"
|
||||
echo "========================================"
|
||||
}
|
||||
|
||||
print_section() {
|
||||
echo ""
|
||||
echo -e "${YELLOW}=== $1 ===${NC}"
|
||||
}
|
||||
|
||||
print_success() {
|
||||
echo -e "${GREEN}✓ $1${NC}"
|
||||
}
|
||||
|
||||
print_error() {
|
||||
echo -e "${RED}✗ $1${NC}"
|
||||
}
|
||||
|
||||
# 获取Token
|
||||
get_token() {
|
||||
print_section "获取Token"
|
||||
|
||||
TOKEN=$(curl -s -X POST "${BASE_URL}/login/test" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"username\":\"${TEST_USERNAME}\",\"password\":\"${TEST_PASSWORD}\"}" | jq -r '.data.token')
|
||||
|
||||
if [ "$TOKEN" != "null" ] && [ -n "$TOKEN" ]; then
|
||||
print_success "Token获取成功: ${TOKEN:0:20}..."
|
||||
echo "$TOKEN"
|
||||
else
|
||||
print_error "Token获取失败"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 测试查询列表
|
||||
test_list() {
|
||||
print_section "测试查询列表"
|
||||
|
||||
response=$(curl -s -X GET "${BASE_URL}/ccdi/intermediary/list?pageNum=1&pageSize=10" \
|
||||
-H "Authorization: Bearer $TOKEN")
|
||||
|
||||
echo "$response" | jq '.'
|
||||
code=$(echo "$response" | jq -r '.code')
|
||||
|
||||
if [ "$code" == "200" ]; then
|
||||
print_success "查询列表成功"
|
||||
total=$(echo "$response" | jq -r '.total')
|
||||
echo "总记录数: $total"
|
||||
else
|
||||
print_error "查询列表失败"
|
||||
fi
|
||||
}
|
||||
|
||||
# 测试新增个人中介
|
||||
test_add_person() {
|
||||
print_section "测试新增个人中介"
|
||||
|
||||
response=$(curl -s -X POST "${BASE_URL}/ccdi/intermediary/person" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"name": "测试中介个人",
|
||||
"personType": "中介",
|
||||
"personSubType": "本人",
|
||||
"relationType": "正常",
|
||||
"gender": "M",
|
||||
"idType": "身份证",
|
||||
"personId": "110101199001019999",
|
||||
"mobile": "13800138000",
|
||||
"wechatNo": "test_wx",
|
||||
"contactAddress": "北京市朝阳区测试地址",
|
||||
"company": "测试公司",
|
||||
"position": "经纪人",
|
||||
"remark": "自动化测试数据"
|
||||
}')
|
||||
|
||||
echo "$response" | jq '.'
|
||||
code=$(echo "$response" | jq -r '.code')
|
||||
|
||||
if [ "$code" == "200" ]; then
|
||||
print_success "新增个人中介成功"
|
||||
# 保存bizId用于后续测试
|
||||
PERSON_BIZ_ID=$(curl -s -X GET "${BASE_URL}/ccdi/intermediary/list?name=测试中介个人" \
|
||||
-H "Authorization: Bearer $TOKEN" | jq -r '.rows[0].bizId // empty')
|
||||
if [ -n "$PERSON_BIZ_ID" ]; then
|
||||
echo "获取到个人中介bizId: $PERSON_BIZ_ID"
|
||||
fi
|
||||
else
|
||||
print_error "新增个人中介失败: $(echo "$response" | jq -r '.msg')"
|
||||
fi
|
||||
}
|
||||
|
||||
# 测试新增实体中介
|
||||
test_add_entity() {
|
||||
print_section "测试新增实体中介"
|
||||
|
||||
response=$(curl -s -X POST "${BASE_URL}/ccdi/intermediary/entity" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"enterpriseName": "测试中介公司",
|
||||
"socialCreditCode": "91110000123456789X",
|
||||
"enterpriseType": "有限责任公司",
|
||||
"enterpriseNature": "民企",
|
||||
"industryClass": "房地产",
|
||||
"industryName": "房地产业",
|
||||
"establishDate": "2020-01-01",
|
||||
"registerAddress": "北京市朝阳区注册地址",
|
||||
"legalRepresentative": "张三",
|
||||
"legalCertType": "身份证",
|
||||
"legalCertNo": "110101199001011234",
|
||||
"shareholder1": "李四",
|
||||
"shareholder2": "王五",
|
||||
"remark": "自动化测试数据"
|
||||
}')
|
||||
|
||||
echo "$response" | jq '.'
|
||||
code=$(echo "$response" | jq -r '.code')
|
||||
|
||||
if [ "$code" == "200" ]; then
|
||||
print_success "新增实体中介成功"
|
||||
# 保存socialCreditCode用于后续测试
|
||||
ENTITY_CREDIT_CODE="91110000123456789X"
|
||||
echo "实体中介统一社会信用代码: $ENTITY_CREDIT_CODE"
|
||||
else
|
||||
print_error "新增实体中介失败: $(echo "$response" | jq -r '.msg')"
|
||||
fi
|
||||
}
|
||||
|
||||
# 测试查询个人中介详情
|
||||
test_get_person_detail() {
|
||||
print_section "测试查询个人中介详情"
|
||||
|
||||
if [ -z "$PERSON_BIZ_ID" ]; then
|
||||
print_error "没有可用的个人中介bizId,跳过测试"
|
||||
return
|
||||
fi
|
||||
|
||||
response=$(curl -s -X GET "${BASE_URL}/ccdi/intermediary/person/${PERSON_BIZ_ID}" \
|
||||
-H "Authorization: Bearer $TOKEN")
|
||||
|
||||
echo "$response" | jq '.'
|
||||
code=$(echo "$response" | jq -r '.code')
|
||||
|
||||
if [ "$code" == "200" ]; then
|
||||
print_success "查询个人中介详情成功"
|
||||
else
|
||||
print_error "查询个人中介详情失败: $(echo "$response" | jq -r '.msg')"
|
||||
fi
|
||||
}
|
||||
|
||||
# 测试查询实体中介详情
|
||||
test_get_entity_detail() {
|
||||
print_section "测试查询实体中介详情"
|
||||
|
||||
if [ -z "$ENTITY_CREDIT_CODE" ]; then
|
||||
print_error "没有可用的实体中介统一社会信用代码,跳过测试"
|
||||
return
|
||||
fi
|
||||
|
||||
response=$(curl -s -X GET "${BASE_URL}/ccdi/intermediary/entity/${ENTITY_CREDIT_CODE}" \
|
||||
-H "Authorization: Bearer $TOKEN")
|
||||
|
||||
echo "$response" | jq '.'
|
||||
code=$(echo "$response" | jq -r '.code')
|
||||
|
||||
if [ "$code" == "200" ]; then
|
||||
print_success "查询实体中介详情成功"
|
||||
else
|
||||
print_error "查询实体中介详情失败: $(echo "$response" | jq -r '.msg')"
|
||||
fi
|
||||
}
|
||||
|
||||
# 测试校验人员ID唯一性
|
||||
test_check_person_id() {
|
||||
print_section "测试校验人员ID唯一性"
|
||||
|
||||
response=$(curl -s -X GET "${BASE_URL}/ccdi/intermediary/checkPersonIdUnique?personId=110101199001019999" \
|
||||
-H "Authorization: Bearer $TOKEN")
|
||||
|
||||
echo "$response" | jq '.'
|
||||
code=$(echo "$response" | jq -r '.code')
|
||||
|
||||
if [ "$code" == "200" ]; then
|
||||
unique=$(echo "$response" | jq -r '.data')
|
||||
print_success "校验人员ID唯一性成功, unique=$unique"
|
||||
else
|
||||
print_error "校验人员ID唯一性失败"
|
||||
fi
|
||||
}
|
||||
|
||||
# 测试校验统一社会信用代码唯一性
|
||||
test_check_social_credit_code() {
|
||||
print_section "测试校验统一社会信用代码唯一性"
|
||||
|
||||
response=$(curl -s -X GET "${BASE_URL}/ccdi/intermediary/checkSocialCreditCodeUnique?socialCreditCode=91110000123456789X" \
|
||||
-H "Authorization: Bearer $TOKEN")
|
||||
|
||||
echo "$response" | jq '.'
|
||||
code=$(echo "$response" | jq -r '.code')
|
||||
|
||||
if [ "$code" == "200" ]; then
|
||||
unique=$(echo "$response" | jq -r '.data')
|
||||
print_success "校验统一社会信用代码唯一性成功, unique=$unique"
|
||||
else
|
||||
print_error "校验统一社会信用代码唯一性失败"
|
||||
fi
|
||||
}
|
||||
|
||||
# 测试修改个人中介
|
||||
test_edit_person() {
|
||||
print_section "测试修改个人中介"
|
||||
|
||||
if [ -z "$PERSON_BIZ_ID" ]; then
|
||||
print_error "没有可用的个人中介bizId,跳过测试"
|
||||
return
|
||||
fi
|
||||
|
||||
response=$(curl -s -X PUT "${BASE_URL}/ccdi/intermediary/person" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{
|
||||
\"bizId\": \"$PERSON_BIZ_ID\",
|
||||
\"name\": \"测试中介个人(已修改)\",
|
||||
\"personType\": \"中介\",
|
||||
\"gender\": \"M\",
|
||||
\"idType\": \"身份证\",
|
||||
\"personId\": \"110101199001019999\",
|
||||
\"mobile\": \"13900139000\",
|
||||
\"company\": \"新公司\",
|
||||
\"position\": \"高级经纪人\",
|
||||
\"remark\": \"修改后的测试数据\"
|
||||
}")
|
||||
|
||||
echo "$response" | jq '.'
|
||||
code=$(echo "$response" | jq -r '.code')
|
||||
|
||||
if [ "$code" == "200" ]; then
|
||||
print_success "修改个人中介成功"
|
||||
else
|
||||
print_error "修改个人中介失败: $(echo "$response" | jq -r '.msg')"
|
||||
fi
|
||||
}
|
||||
|
||||
# 测试修改实体中介
|
||||
test_edit_entity() {
|
||||
print_section "测试修改实体中介"
|
||||
|
||||
if [ -z "$ENTITY_CREDIT_CODE" ]; then
|
||||
print_error "没有可用的实体中介统一社会信用代码,跳过测试"
|
||||
return
|
||||
fi
|
||||
|
||||
response=$(curl -s -X PUT "${BASE_URL}/ccdi/intermediary/entity" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{
|
||||
\"socialCreditCode\": \"$ENTITY_CREDIT_CODE\",
|
||||
\"enterpriseName\": \"测试中介公司(已修改)\",
|
||||
\"enterpriseType\": \"股份有限公司\",
|
||||
\"enterpriseNature\": \"国企\",
|
||||
\"industryClass\": \"金融\",
|
||||
\"industryName\": \"金融业\",
|
||||
\"registerAddress\": \"北京市海淀区新地址\",
|
||||
\"legalRepresentative\": \"李四\",
|
||||
\"shareholder1\": \"赵六\",
|
||||
\"shareholder2\": \"钱七\",
|
||||
\"remark\": \"修改后的测试数据\"
|
||||
}")
|
||||
|
||||
echo "$response" | jq '.'
|
||||
code=$(echo "$response" | jq -r '.code')
|
||||
|
||||
if [ "$code" == "200" ]; then
|
||||
print_success "修改实体中介成功"
|
||||
else
|
||||
print_error "修改实体中介失败: $(echo "$response" | jq -r '.msg')"
|
||||
fi
|
||||
}
|
||||
|
||||
# 测试条件查询
|
||||
test_query_by_type() {
|
||||
print_section "测试按中介类型查询"
|
||||
|
||||
# 查询个人中介
|
||||
print_section "查询个人中介"
|
||||
response=$(curl -s -X GET "${BASE_URL}/ccdi/intermediary/list?intermediaryType=1&pageNum=1&pageSize=10" \
|
||||
-H "Authorization: Bearer $TOKEN")
|
||||
|
||||
echo "$response" | jq '.'
|
||||
total=$(echo "$response" | jq -r '.total')
|
||||
print_success "查询到个人中介 $total 条"
|
||||
|
||||
# 查询实体中介
|
||||
print_section "查询实体中介"
|
||||
response=$(curl -s -X GET "${BASE_URL}/ccdi/intermediary/list?intermediaryType=2&pageNum=1&pageSize=10" \
|
||||
-H "Authorization: Bearer $TOKEN")
|
||||
|
||||
echo "$response" | jq '.'
|
||||
total=$(echo "$response" | jq -r '.total')
|
||||
print_success "查询到实体中介 $total 条"
|
||||
}
|
||||
|
||||
# 主函数
|
||||
main() {
|
||||
print_header "中介黑名单管理 API 测试开始"
|
||||
|
||||
# 检查jq命令
|
||||
if ! command -v jq &> /dev/null; then
|
||||
print_error "jq命令未安装,请先安装: apt-get install jq 或 yum install jq"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 获取Token
|
||||
get_token
|
||||
|
||||
# 执行测试
|
||||
test_list
|
||||
test_add_person
|
||||
test_add_entity
|
||||
test_get_person_detail
|
||||
test_get_entity_detail
|
||||
test_check_person_id
|
||||
test_check_social_credit_code
|
||||
test_edit_person
|
||||
test_edit_entity
|
||||
test_query_by_type
|
||||
|
||||
print_header "测试完成"
|
||||
echo ""
|
||||
echo "注意事项:"
|
||||
echo "1. 请确保后端服务已启动 (${BASE_URL})"
|
||||
echo "2. 测试数据已创建,可手动清理"
|
||||
echo "3. 如需删除测试数据,请使用清理脚本"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# 执行主函数
|
||||
main
|
||||
46
doc/sql/menu_info_maintain.sql
Normal file
46
doc/sql/menu_info_maintain.sql
Normal file
@@ -0,0 +1,46 @@
|
||||
-- =====================================================
|
||||
-- 菜单SQL:信息维护模块
|
||||
-- 创建时间: 2025-02-04
|
||||
-- 说明: 包含"信息维护"一级菜单及其两个二级菜单
|
||||
-- =====================================================
|
||||
|
||||
-- 一级菜单:信息维护
|
||||
INSERT INTO sys_menu(menu_id, 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, remark)
|
||||
VALUES(2000, '信息维护', 0, 5, 'maintain', NULL, NULL, NULL, 1, 0, 'M', '0', '0', NULL, 'el-icon-collection', 'admin', NOW(), '信息维护目录');
|
||||
|
||||
-- 二级菜单:中介黑名单管理
|
||||
INSERT INTO sys_menu(menu_id, 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, remark)
|
||||
VALUES(2001, '中介黑名单管理', 2000, 1, 'intermediary', 'ccdiIntermediary/index', NULL, NULL, 1, 0, 'C', '0', '0', 'ccdi:intermediary:list', '#', 'admin', NOW(), '中介黑名单管理菜单');
|
||||
|
||||
-- 二级菜单:员工信息维护
|
||||
INSERT INTO sys_menu(menu_id, 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, remark)
|
||||
VALUES(2002, '员工信息维护', 2000, 2, 'employee', 'ccdiEmployee/index', NULL, NULL, 1, 0, 'C', '0', '0', 'ccdi:employee:list', '#', 'admin', NOW(), '员工信息维护菜单');
|
||||
|
||||
-- =====================================================
|
||||
-- 中介黑名单管理 - 按钮权限
|
||||
-- =====================================================
|
||||
INSERT INTO sys_menu(menu_id, 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, remark)
|
||||
VALUES
|
||||
(2010, '中介黑名单查询', 2001, 1, '', NULL, NULL, NULL, 1, 0, 'F', '0', '0', 'ccdi:intermediary:query', '#', 'admin', NOW(), ''),
|
||||
(2011, '中介黑名单新增', 2001, 2, '', NULL, NULL, NULL, 1, 0, 'F', '0', '0', 'ccdi:intermediary:add', '#', 'admin', NOW(), ''),
|
||||
(2012, '中介黑名单修改', 2001, 3, '', NULL, NULL, NULL, 1, 0, 'F', '0', '0', 'ccdi:intermediary:edit', '#', 'admin', NOW(), ''),
|
||||
(2013, '中介黑名单删除', 2001, 4, '', NULL, NULL, NULL, 1, 0, 'F', '0', '0', 'ccdi:intermediary:remove', '#', 'admin', NOW(), ''),
|
||||
(2014, '中介黑名单导出', 2001, 5, '', NULL, NULL, NULL, 1, 0, 'F', '0', '0', 'ccdi:intermediary:export', '#', 'admin', NOW(), ''),
|
||||
(2015, '中介黑名单导入', 2001, 6, '', NULL, NULL, NULL, 1, 0, 'F', '0', '0', 'ccdi:intermediary:import', '#', 'admin', NOW(), '');
|
||||
|
||||
-- =====================================================
|
||||
-- 员工信息维护 - 按钮权限
|
||||
-- =====================================================
|
||||
INSERT INTO sys_menu(menu_id, 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, remark)
|
||||
VALUES
|
||||
(2020, '员工信息查询', 2002, 1, '', NULL, NULL, NULL, 1, 0, 'F', '0', '0', 'ccdi:employee:query', '#', 'admin', NOW(), ''),
|
||||
(2021, '员工信息新增', 2002, 2, '', NULL, NULL, NULL, 1, 0, 'F', '0', '0', 'ccdi:employee:add', '#', 'admin', NOW(), ''),
|
||||
(2022, '员工信息修改', 2002, 3, '', NULL, NULL, NULL, 1, 0, 'F', '0', '0', 'ccdi:employee:edit', '#', 'admin', NOW(), ''),
|
||||
(2023, '员工信息删除', 2002, 4, '', NULL, NULL, NULL, 1, 0, 'F', '0', '0', 'ccdi:employee:remove', '#', 'admin', NOW(), ''),
|
||||
(2024, '员工信息导出', 2002, 5, '', NULL, NULL, NULL, 1, 0, 'F', '0', '0', 'ccdi:employee:export', '#', 'admin', NOW(), ''),
|
||||
(2025, '员工信息导入', 2002, 6, '', NULL, NULL, NULL, 1, 0, 'F', '0', '0', 'ccdi:employee:import', '#', 'admin', NOW(), '');
|
||||
|
||||
-- =====================================================
|
||||
-- 回滚SQL(如需删除这些菜单,执行以下语句)
|
||||
-- =====================================================
|
||||
-- DELETE FROM sys_menu WHERE menu_id BETWEEN 2000 AND 2025;
|
||||
@@ -1,192 +0,0 @@
|
||||
import openpyxl
|
||||
from openpyxl import Workbook
|
||||
import random
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
# 机构名称前缀
|
||||
org_prefixes = [
|
||||
"北京", "上海", "广州", "深圳", "杭州", "成都", "重庆", "武汉", "西安", "南京",
|
||||
"天津", "苏州", "长沙", "郑州", "东莞", "青岛", "沈阳", "宁波", "厦门", "佛山"
|
||||
]
|
||||
|
||||
# 机构类型关键词
|
||||
org_types = [
|
||||
"投资咨询", "资产管理", "证券投资", "基金管理", "股权投资",
|
||||
"财富管理", "金融信息服务", "商务咨询", "企业咨询", "投资顾问"
|
||||
]
|
||||
|
||||
# 机构后缀
|
||||
org_suffixes = ["有限公司", "股份有限公司", "集团", "企业", "事务所"]
|
||||
|
||||
# 主体类型
|
||||
entity_types = ["企业", "事业单位", "社会组织"]
|
||||
|
||||
# 企业性质
|
||||
corp_natures = [
|
||||
"有限责任公司", "股份有限公司", "国有独资", "集体企业",
|
||||
"私营企业", "中外合资", "外商独资", "港澳台合资"
|
||||
]
|
||||
|
||||
# 行业分类
|
||||
industry_classes = ["金融业", "商务服务业", "科学研究和技术服务业"]
|
||||
|
||||
# 所属行业
|
||||
industries = [
|
||||
"货币金融服务", "资本市场服务", "保险业", "其他金融业",
|
||||
"企业管理服务", "法律服务", "咨询与调查", "广告业",
|
||||
"研究和试验发展", "专业技术服务业", "科技推广和应用服务业"
|
||||
]
|
||||
|
||||
# 证件类型
|
||||
id_types = ["身份证", "护照", "其他"]
|
||||
|
||||
# 统一社会信用代码生成(18位)
|
||||
def generate_credit_code():
|
||||
area_code = f"{random.randint(110000, 659900):06d}"
|
||||
org_code = ''.join([str(random.randint(0, 9)) for _ in range(9)])
|
||||
check_code = random.randint(0, 9)
|
||||
return f"{area_code}{org_code}{check_code}"
|
||||
|
||||
# 生成法定代表人姓名
|
||||
def generate_person_name():
|
||||
surnames = ["王", "李", "张", "刘", "陈", "杨", "黄", "赵", "周", "吴",
|
||||
"徐", "孙", "马", "胡", "朱", "郭", "何", "罗", "高", "林"]
|
||||
names1 = ["伟", "芳", "娜", "敏", "静", "丽", "强", "磊", "军", "洋",
|
||||
"勇", "艳", "杰", "娟", "涛", "明", "超", "秀英", "霞", "平"]
|
||||
names2 = ["", "刚", "英", "华", "文", "平", "建", "国", "志", "海"]
|
||||
return random.choice(surnames) + random.choice(names1) + random.choice(names2)
|
||||
|
||||
# 生成身份证号(18位)
|
||||
def generate_id_card():
|
||||
# 地区码(6位) + 出生日期(8位) + 顺序码(3位) + 校验码(1位)
|
||||
area_code = f"{random.randint(110000, 659900):06d}"
|
||||
year = random.randint(1960, 1995)
|
||||
month = f"{random.randint(1, 12):02d}"
|
||||
day = f"{random.randint(1, 28):02d}"
|
||||
birth_date = f"{year}{month}{day}"
|
||||
sequence = f"{random.randint(1, 999):03d}"
|
||||
check_code = random.randint(0, 9)
|
||||
return f"{area_code}{birth_date}{sequence}{check_code}"
|
||||
|
||||
# 生成注册地址
|
||||
def generate_address():
|
||||
districts = ["朝阳区", "海淀区", "西城区", "东城区", "丰台区",
|
||||
"浦东新区", "黄浦区", "静安区", "徐汇区", "天河区",
|
||||
"福田区", "南山区", "罗湖区", "西湖区", "江干区"]
|
||||
streets = ["建设路", "人民路", "解放路", "和平路", "文化路",
|
||||
"科技路", "创新路", "发展路", "创业路", "工业路"]
|
||||
buildings = ["大厦", "中心", "广场", "写字楼", "科技园"]
|
||||
return f"{random.choice(districts)}{random.choice(streets)}{random.randint(1,999)}号{random.choice(buildings)}"
|
||||
|
||||
# 生成成立日期
|
||||
def generate_establish_date():
|
||||
start_date = datetime(2000, 1, 1)
|
||||
end_date = datetime(2024, 12, 31)
|
||||
days_between = (end_date - start_date).days
|
||||
random_days = random.randint(0, days_between)
|
||||
return (start_date + timedelta(days=random_days)).strftime("%Y-%m-%d")
|
||||
|
||||
# 生成股东名称
|
||||
def generate_shareholder():
|
||||
types = [
|
||||
lambda: f"{random.choice(org_prefixes)}{random.choice(['投资', '资本', '控股', '集团'])}有限公司",
|
||||
lambda: generate_person_name() + random.choice(["", "(自然人)"])
|
||||
]
|
||||
return random.choice(types)()
|
||||
|
||||
# 生成备注
|
||||
def generate_remark():
|
||||
remarks = [
|
||||
"", "", "", "",
|
||||
"重点监控", "已整改", "存在风险", "待核查"
|
||||
]
|
||||
return random.choice(remarks)
|
||||
|
||||
# 生成单条机构数据
|
||||
def generate_org_data(index):
|
||||
# 随机决定有几个股东(1-5个)
|
||||
shareholder_count = random.randint(1, 5)
|
||||
shareholders = [generate_shareholder() for _ in range(shareholder_count)]
|
||||
# 补齐到5个
|
||||
while len(shareholders) < 5:
|
||||
shareholders.append("")
|
||||
|
||||
# 证件类型
|
||||
id_type = random.choice(id_types)
|
||||
id_card = generate_id_card() if id_type == "身份证" else f"{random.choice(['A', 'B', 'C'])}{random.randint(10000, 99999)}"
|
||||
|
||||
return {
|
||||
"id": index,
|
||||
"orgName": f"{random.choice(org_prefixes)}{random.choice(org_types)}{random.choice(org_suffixes)}",
|
||||
"creditCode": generate_credit_code(),
|
||||
"entityType": random.choice(entity_types),
|
||||
"corpNature": random.choice(corp_natures) if random.choice([True, False]) else "",
|
||||
"industryClass": random.choice(industry_classes),
|
||||
"industry": random.choice(industries),
|
||||
"establishDate": generate_establish_date(),
|
||||
"regAddress": generate_address(),
|
||||
"legalRep": generate_person_name(),
|
||||
"legalRepIdType": id_type,
|
||||
"legalRepIdNo": id_card,
|
||||
"shareholder1": shareholders[0],
|
||||
"shareholder2": shareholders[1],
|
||||
"shareholder3": shareholders[2],
|
||||
"shareholder4": shareholders[3],
|
||||
"shareholder5": shareholders[4],
|
||||
"remark": generate_remark()
|
||||
}
|
||||
|
||||
# 生成数据并保存到Excel
|
||||
def generate_org_test_data(filename, count=1000, start_id=1):
|
||||
# 读取模板获取表头
|
||||
template_path = "机构中介黑名单模板_1769674571626.xlsx"
|
||||
template_wb = openpyxl.load_workbook(template_path)
|
||||
template_ws = template_wb.active
|
||||
|
||||
# 创建新工作簿
|
||||
wb = Workbook()
|
||||
ws = wb.active
|
||||
ws.title = "机构中介黑名单"
|
||||
|
||||
# 复制表头
|
||||
for cell in template_ws[1]:
|
||||
new_cell = ws.cell(row=1, column=cell.column, value=cell.value)
|
||||
|
||||
# 生成数据
|
||||
data_list = []
|
||||
for i in range(count):
|
||||
data = generate_org_data(start_id + i)
|
||||
data_list.append(data)
|
||||
|
||||
# 按照模板列顺序写入数据
|
||||
# 列顺序:机构名称、统一社会信用代码、主体类型、企业性质、行业分类、所属行业、
|
||||
# 成立日期、注册地址、法定代表人、法定代表人证件类型、法定代表人证件号码、
|
||||
# 股东1、股东2、股东3、股东4、股东5、备注
|
||||
for row_idx, data in enumerate(data_list, start=2):
|
||||
ws.cell(row=row_idx, column=1, value=data["orgName"])
|
||||
ws.cell(row=row_idx, column=2, value=data["creditCode"])
|
||||
ws.cell(row=row_idx, column=3, value=data["entityType"])
|
||||
ws.cell(row=row_idx, column=4, value=data["corpNature"])
|
||||
ws.cell(row=row_idx, column=5, value=data["industryClass"])
|
||||
ws.cell(row=row_idx, column=6, value=data["industry"])
|
||||
ws.cell(row=row_idx, column=7, value=data["establishDate"])
|
||||
ws.cell(row=row_idx, column=8, value=data["regAddress"])
|
||||
ws.cell(row=row_idx, column=9, value=data["legalRep"])
|
||||
ws.cell(row=row_idx, column=10, value=data["legalRepIdType"])
|
||||
ws.cell(row=row_idx, column=11, value=data["legalRepIdNo"])
|
||||
ws.cell(row=row_idx, column=12, value=data["shareholder1"])
|
||||
ws.cell(row=row_idx, column=13, value=data["shareholder2"])
|
||||
ws.cell(row=row_idx, column=14, value=data["shareholder3"])
|
||||
ws.cell(row=row_idx, column=15, value=data["shareholder4"])
|
||||
ws.cell(row=row_idx, column=16, value=data["shareholder5"])
|
||||
ws.cell(row=row_idx, column=17, value=data["remark"])
|
||||
|
||||
# 保存文件
|
||||
wb.save(filename)
|
||||
print(f"已生成文件: {filename}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("开始生成机构中介黑名单测试数据...")
|
||||
generate_org_test_data("机构中介黑名单测试数据_1000条.xlsx", 1000, 1)
|
||||
generate_org_test_data("机构中介黑名单测试数据_1000条_第2批.xlsx", 1000, 1001)
|
||||
print("完成!")
|
||||
BIN
doc/test-data/intermediary/entity_1770260448522.xlsx
Normal file
BIN
doc/test-data/intermediary/entity_1770260448522.xlsx
Normal file
Binary file not shown.
181
doc/test-data/intermediary/generate_1000_entity_data.py
Normal file
181
doc/test-data/intermediary/generate_1000_entity_data.py
Normal file
@@ -0,0 +1,181 @@
|
||||
import random
|
||||
import string
|
||||
from datetime import datetime, timedelta
|
||||
import pandas as pd
|
||||
|
||||
# 机构名称前缀
|
||||
company_prefixes = ['北京市', '上海市', '广州市', '深圳市', '杭州市', '成都市', '武汉市', '南京市', '西安市', '重庆市']
|
||||
company_keywords = ['房产', '地产', '置业', '中介', '经纪', '咨询', '投资', '资产', '物业', '不动产']
|
||||
company_suffixes = ['有限公司', '股份有限公司', '集团', '企业', '合伙企业', '有限责任公司']
|
||||
|
||||
# 主体类型
|
||||
entity_types = ['企业', '个体工商户', '农民专业合作社', '其他组织']
|
||||
|
||||
# 企业性质
|
||||
enterprise_natures = ['国有企业', '集体企业', '私营企业', '混合所有制企业', '外商投资企业', '港澳台投资企业']
|
||||
|
||||
# 行业分类
|
||||
industry_classes = ['房地产业', '金融业', '租赁和商务服务业', '建筑业', '批发和零售业']
|
||||
|
||||
# 所属行业
|
||||
industry_names = [
|
||||
'房地产中介服务', '房地产经纪', '房地产开发经营', '物业管理',
|
||||
'投资咨询', '资产管理', '商务咨询', '市场调查',
|
||||
'建筑工程', '装饰装修', '园林绿化'
|
||||
]
|
||||
|
||||
# 法定代表人姓名
|
||||
surnames = ['王', '李', '张', '刘', '陈', '杨', '黄', '赵', '周', '吴', '徐', '孙', '马', '胡', '朱', '郭', '何', '罗', '高', '林']
|
||||
given_names = ['伟', '芳', '娜', '敏', '静', '丽', '强', '磊', '军', '洋', '勇', '艳', '杰', '娟', '涛', '明', '超', '秀英', '霞', '平']
|
||||
|
||||
# 证件类型
|
||||
cert_types = ['身份证', '护照', '港澳通行证', '台胞证', '其他']
|
||||
|
||||
# 常用地址
|
||||
provinces = ['北京市', '上海市', '广东省', '浙江省', '江苏省', '四川省', '湖北省', '河南省', '山东省', '福建省']
|
||||
cities = ['朝阳区', '海淀区', '浦东新区', '黄浦区', '天河区', '福田区', '西湖区', '滨江区', '鼓楼区', '玄武区',
|
||||
'武侯区', '江汉区', '金水区', '市南区', '思明区']
|
||||
districts = ['街道', '大道', '路', '巷', '小区', '花园', '广场', '大厦']
|
||||
street_numbers = ['1号', '2号', '3号', '88号', '66号', '108号', '188号', '888号', '666号', '168号']
|
||||
|
||||
# 股东姓名
|
||||
shareholder_names = [
|
||||
'张伟', '李芳', '王强', '刘军', '陈静', '杨洋', '黄勇', '赵艳',
|
||||
'周杰', '吴娟', '徐涛', '孙明', '马超', '胡秀英', '朱霞', '郭平',
|
||||
'何桂英', '罗玉兰', '高萍', '林毅', '王浩', '李宇', '张轩', '刘然'
|
||||
]
|
||||
|
||||
def generate_company_name():
|
||||
"""生成机构名称"""
|
||||
prefix = random.choice(company_prefixes)
|
||||
keyword = random.choice(company_keywords)
|
||||
suffix = random.choice(company_suffixes)
|
||||
return f"{prefix}{keyword}{suffix}"
|
||||
|
||||
def generate_social_credit_code():
|
||||
"""生成统一社会信用代码(18位)"""
|
||||
# 统一社会信用代码规则:18位,第一位为登记管理部门代码(1-5),第二位为机构类别代码(1-9)
|
||||
dept_code = random.choice(['1', '2', '3', '4', '5'])
|
||||
org_code = random.choice(['1', '2', '3', '4', '5', '6', '7', '8', '9'])
|
||||
rest = ''.join([str(random.randint(0, 9)) for _ in range(16)])
|
||||
return f"{dept_code}{org_code}{rest}"
|
||||
|
||||
def generate_id_card():
|
||||
"""生成身份证号码(18位,简化版)"""
|
||||
# 地区码(前6位)
|
||||
area_code = f"{random.randint(110000, 650000):06d}"
|
||||
# 出生日期(8位)
|
||||
birth_year = random.randint(1960, 1990)
|
||||
birth_month = f"{random.randint(1, 12):02d}"
|
||||
birth_day = f"{random.randint(1, 28):02d}"
|
||||
birth_date = f"{birth_year}{birth_month}{birth_day}"
|
||||
# 顺序码(3位)
|
||||
sequence = f"{random.randint(1, 999):03d}"
|
||||
# 校验码(1位)
|
||||
check_code = random.randint(0, 9)
|
||||
return f"{area_code}{birth_date}{sequence}{check_code}"
|
||||
|
||||
def generate_other_id():
|
||||
"""生成其他证件号码"""
|
||||
return f"{random.randint(10000000, 99999999):08d}"
|
||||
|
||||
def generate_register_address():
|
||||
"""生成注册地址"""
|
||||
province = random.choice(provinces)
|
||||
city = random.choice(cities)
|
||||
district = random.choice(districts)
|
||||
number = random.choice(street_numbers)
|
||||
return f"{province}{city}{district}{number}"
|
||||
|
||||
def generate_establish_date():
|
||||
"""生成成立日期(2000-2024年之间)"""
|
||||
start_date = datetime(2000, 1, 1)
|
||||
end_date = datetime(2024, 12, 31)
|
||||
time_between = end_date - start_date
|
||||
days_between = time_between.days
|
||||
random_days = random.randrange(days_between)
|
||||
return start_date + timedelta(days=random_days)
|
||||
|
||||
def generate_legal_representative():
|
||||
"""生成法定代表人"""
|
||||
name = random.choice(surnames) + random.choice(given_names)
|
||||
cert_type = random.choice(cert_types)
|
||||
cert_no = generate_id_card() if cert_type == '身份证' else generate_other_id()
|
||||
return name, cert_type, cert_no
|
||||
|
||||
def generate_shareholders():
|
||||
"""生成股东列表(1-5个股东)"""
|
||||
shareholder_count = random.randint(1, 5)
|
||||
selected_shareholders = random.sample(shareholder_names, shareholder_count)
|
||||
shareholders = [None] * 5
|
||||
for i, shareholder in enumerate(selected_shareholders):
|
||||
shareholders[i] = shareholder
|
||||
return shareholders
|
||||
|
||||
def generate_entity(index):
|
||||
"""生成单条机构中介数据"""
|
||||
# 基本信息
|
||||
enterprise_name = generate_company_name()
|
||||
social_credit_code = generate_social_credit_code()
|
||||
entity_type = random.choice(entity_types)
|
||||
enterprise_nature = random.choice(enterprise_natures)
|
||||
industry_class = random.choice(industry_classes)
|
||||
industry_name = random.choice(industry_names)
|
||||
|
||||
# 成立日期
|
||||
establish_date = generate_establish_date()
|
||||
|
||||
# 注册地址
|
||||
register_address = generate_register_address()
|
||||
|
||||
# 法定代表人信息
|
||||
legal_name, legal_cert_type, legal_cert_no = generate_legal_representative()
|
||||
|
||||
# 股东
|
||||
shareholders = generate_shareholders()
|
||||
|
||||
return {
|
||||
'机构名称*': enterprise_name,
|
||||
'统一社会信用代码*': social_credit_code,
|
||||
'主体类型': entity_type,
|
||||
'企业性质': enterprise_nature if random.random() > 0.3 else '',
|
||||
'行业分类': industry_class if random.random() > 0.3 else '',
|
||||
'所属行业': industry_name if random.random() > 0.2 else '',
|
||||
'成立日期': establish_date.strftime('%Y-%m-%d') if random.random() > 0.4 else '',
|
||||
'注册地址': register_address,
|
||||
'法定代表人': legal_name,
|
||||
'法定代表人证件类型': legal_cert_type,
|
||||
'法定代表人证件号码': legal_cert_no,
|
||||
'股东1': shareholders[0] if shareholders[0] else '',
|
||||
'股东2': shareholders[1] if shareholders[1] else '',
|
||||
'股东3': shareholders[2] if shareholders[2] else '',
|
||||
'股东4': shareholders[3] if shareholders[3] else '',
|
||||
'股东5': shareholders[4] if shareholders[4] else '',
|
||||
'备注': f'测试数据{index}' if random.random() > 0.5 else ''
|
||||
}
|
||||
|
||||
# 生成第一个1000条数据
|
||||
print("正在生成第一批1000条机构中介黑名单数据...")
|
||||
data = [generate_entity(i) for i in range(1, 1001)]
|
||||
df = pd.DataFrame(data)
|
||||
|
||||
# 保存第一个文件
|
||||
output1 = r'D:\ccdi\ccdi\doc\test-data\intermediary\机构中介黑名单测试数据_1000条_第1批.xlsx'
|
||||
df.to_excel(output1, index=False, engine='openpyxl')
|
||||
print(f"已生成第一个文件: {output1}")
|
||||
|
||||
# 生成第二个1000条数据
|
||||
print("正在生成第二批1000条机构中介黑名单数据...")
|
||||
data2 = [generate_entity(i) for i in range(1, 1001)]
|
||||
df2 = pd.DataFrame(data2)
|
||||
|
||||
# 保存第二个文件
|
||||
output2 = r'D:\ccdi\ccdi\doc\test-data\intermediary\机构中介黑名单测试数据_1000条_第2批.xlsx'
|
||||
df2.to_excel(output2, index=False, engine='openpyxl')
|
||||
print(f"已生成第二个文件: {output2}")
|
||||
|
||||
print("\n✅ 生成完成!")
|
||||
print(f"文件1: {output1}")
|
||||
print(f"文件2: {output2}")
|
||||
print(f"\n每个文件包含1000条测试数据")
|
||||
print(f"数据格式与CcdiIntermediaryEntityExcel.java定义一致")
|
||||
110
doc/test-data/intermediary/generate_1000_intermediary_data.py
Normal file
110
doc/test-data/intermediary/generate_1000_intermediary_data.py
Normal file
@@ -0,0 +1,110 @@
|
||||
import random
|
||||
import string
|
||||
from datetime import datetime
|
||||
import pandas as pd
|
||||
|
||||
# 常用姓氏和名字
|
||||
surnames = ['王', '李', '张', '刘', '陈', '杨', '黄', '赵', '周', '吴', '徐', '孙', '马', '胡', '朱', '郭', '何', '罗', '高', '林']
|
||||
given_names = ['伟', '芳', '娜', '敏', '静', '丽', '强', '磊', '军', '洋', '勇', '艳', '杰', '娟', '涛', '明', '超', '秀英', '霞', '平', '刚', '桂英', '玉兰', '萍', '毅', '浩', '宇', '轩', '然', '凯']
|
||||
|
||||
# 人员类型
|
||||
person_types = ['中介', '职业背债人', '房产中介']
|
||||
person_sub_types = ['本人', '配偶', '子女', '其他']
|
||||
genders = ['M', 'F', 'O']
|
||||
id_types = ['身份证', '护照', '港澳通行证', '台胞证', '军官证']
|
||||
relation_types = ['配偶', '子女', '父母', '兄弟姐妹', '其他']
|
||||
|
||||
# 常用地址
|
||||
provinces = ['北京市', '上海市', '广东省', '浙江省', '江苏省', '四川省', '湖北省', '河南省', '山东省', '福建省']
|
||||
cities = ['朝阳区', '海淀区', '浦东新区', '黄浦区', '天河区', '福田区', '西湖区', '滨江区', '鼓楼区', '玄武区']
|
||||
districts = ['街道1号', '大道2号', '路3号', '巷4号', '小区5栋', '花园6号', '广场7号', '大厦8号楼']
|
||||
|
||||
# 公司和职位
|
||||
companies = ['房产中介有限公司', '置业咨询公司', '房产经纪公司', '地产代理公司', '不动产咨询公司', '房屋租赁公司', '物业管理公司', '投资咨询公司']
|
||||
positions = ['房产经纪人', '销售经理', '业务员', '置业顾问', '店长', '区域经理', '高级经纪人', '项目经理']
|
||||
|
||||
# 生成身份证号码(简化版,仅用于测试)
|
||||
def generate_id_card():
|
||||
# 地区码(前6位)
|
||||
area_code = f"{random.randint(110000, 650000):06d}"
|
||||
# 出生日期(8位)
|
||||
birth_year = random.randint(1960, 2000)
|
||||
birth_month = f"{random.randint(1, 12):02d}"
|
||||
birth_day = f"{random.randint(1, 28):02d}"
|
||||
birth_date = f"{birth_year}{birth_month}{birth_day}"
|
||||
# 顺序码(3位)
|
||||
sequence = f"{random.randint(1, 999):03d}"
|
||||
# 校验码(1位)
|
||||
check_code = random.randint(0, 9)
|
||||
return f"{area_code}{birth_date}{sequence}{check_code}"
|
||||
|
||||
# 生成手机号
|
||||
def generate_phone():
|
||||
second_digits = ['3', '5', '7', '8', '9']
|
||||
second = random.choice(second_digits)
|
||||
return f"1{second}{''.join([str(random.randint(0, 9)) for _ in range(9)])}"
|
||||
|
||||
# 生成统一信用代码
|
||||
def generate_credit_code():
|
||||
return f"91{''.join([str(random.randint(0, 9)) for _ in range(16)])}"
|
||||
|
||||
# 生成微信号
|
||||
def generate_wechat():
|
||||
return f"wx_{''.join([random.choice(string.ascii_lowercase + string.digits) for _ in range(8)])}"
|
||||
|
||||
# 生成单条数据
|
||||
def generate_person(index):
|
||||
person_type = random.choice(person_types)
|
||||
gender = random.choice(genders)
|
||||
|
||||
# 根据性别选择更合适的名字
|
||||
if gender == 'M':
|
||||
name = random.choice(surnames) + random.choice(['伟', '强', '磊', '军', '勇', '杰', '涛', '明', '超', '毅', '浩', '宇', '轩'])
|
||||
else:
|
||||
name = random.choice(surnames) + random.choice(['芳', '娜', '敏', '静', '丽', '艳', '娟', '秀英', '霞', '平', '桂英', '玉兰', '萍'])
|
||||
|
||||
id_type = random.choice(id_types)
|
||||
id_card = generate_id_card() if id_type == '身份证' else f"{random.randint(10000000, 99999999):08d}"
|
||||
|
||||
return {
|
||||
'姓名': name,
|
||||
'人员类型': person_type,
|
||||
'人员子类型': random.choice(person_sub_types),
|
||||
'性别': gender,
|
||||
'证件类型': id_type,
|
||||
'证件号码': id_card,
|
||||
'手机号码': generate_phone(),
|
||||
'微信号': generate_wechat() if random.random() > 0.3 else '',
|
||||
'联系地址': f"{random.choice(provinces)}{random.choice(cities)}{random.choice(districts)}",
|
||||
'所在公司': random.choice(companies) if random.random() > 0.2 else '',
|
||||
'企业统一信用码': generate_credit_code() if random.random() > 0.5 else '',
|
||||
'职位': random.choice(positions) if random.random() > 0.3 else '',
|
||||
'关联人员ID': f"ID{random.randint(10000, 99999)}" if random.random() > 0.6 else '',
|
||||
'关系类型': random.choice(relation_types) if random.random() > 0.6 else '',
|
||||
'备注': f'测试数据{index}' if random.random() > 0.5 else ''
|
||||
}
|
||||
|
||||
# 生成1000条数据
|
||||
print("正在生成1000条个人中介黑名单数据...")
|
||||
data = [generate_person(i) for i in range(1, 1001)]
|
||||
df = pd.DataFrame(data)
|
||||
|
||||
# 保存第一个文件
|
||||
output1 = r'D:\ccdi\ccdi\doc\test-data\intermediary\个人中介黑名单测试数据_1000条_第1批.xlsx'
|
||||
df.to_excel(output1, index=False)
|
||||
print(f"已生成第一个文件: {output1}")
|
||||
|
||||
# 生成第二个1000条数据
|
||||
print("正在生成第二批1000条个人中介黑名单数据...")
|
||||
data2 = [generate_person(i) for i in range(1, 1001)]
|
||||
df2 = pd.DataFrame(data2)
|
||||
|
||||
# 保存第二个文件
|
||||
output2 = r'D:\ccdi\ccdi\doc\test-data\intermediary\个人中介黑名单测试数据_1000条_第2批.xlsx'
|
||||
df2.to_excel(output2, index=False)
|
||||
print(f"已生成第二个文件: {output2}")
|
||||
|
||||
print("\n生成完成!")
|
||||
print(f"文件1: {output1}")
|
||||
print(f"文件2: {output2}")
|
||||
print(f"\n每个文件包含1000条测试数据")
|
||||
BIN
doc/test-data/intermediary/个人中介黑名单模板_1770258896626.xlsx
Normal file
BIN
doc/test-data/intermediary/个人中介黑名单模板_1770258896626.xlsx
Normal file
Binary file not shown.
BIN
doc/test-data/intermediary/个人中介黑名单测试数据_1000条_第1批.xlsx
Normal file
BIN
doc/test-data/intermediary/个人中介黑名单测试数据_1000条_第1批.xlsx
Normal file
Binary file not shown.
BIN
doc/test-data/intermediary/个人中介黑名单测试数据_1000条_第2批.xlsx
Normal file
BIN
doc/test-data/intermediary/个人中介黑名单测试数据_1000条_第2批.xlsx
Normal file
Binary file not shown.
BIN
doc/test-data/intermediary/机构中介黑名单测试数据_1000条_第1批.xlsx
Normal file
BIN
doc/test-data/intermediary/机构中介黑名单测试数据_1000条_第1批.xlsx
Normal file
Binary file not shown.
BIN
doc/test-data/intermediary/机构中介黑名单测试数据_1000条_第2批.xlsx
Normal file
BIN
doc/test-data/intermediary/机构中介黑名单测试数据_1000条_第2批.xlsx
Normal file
Binary file not shown.
@@ -1,268 +0,0 @@
|
||||
"""
|
||||
中介黑名单导入功能测试脚本
|
||||
|
||||
测试目标:
|
||||
1. 验证机构中介导入时 certificate_no 字段不能为 null 的修复
|
||||
2. 验证个人中介导入功能正常
|
||||
3. 验证更新模式功能正常
|
||||
|
||||
测试数据准备:
|
||||
- 个人中介:2条记录
|
||||
- 机构中介:2条记录
|
||||
"""
|
||||
|
||||
import requests
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
BASE_URL = "http://localhost:8080"
|
||||
|
||||
def login():
|
||||
"""登录并获取token"""
|
||||
url = f"{BASE_URL}/login/test"
|
||||
data = {
|
||||
"username": "admin",
|
||||
"password": "admin123"
|
||||
}
|
||||
response = requests.post(url, json=data)
|
||||
if response.status_code == 200:
|
||||
result = response.json()
|
||||
if result.get("code") == 200:
|
||||
token = result.get("token")
|
||||
print(f"✓ 登录成功,获取token: {token[:20]}...")
|
||||
return token
|
||||
print(f"✗ 登录失败: {response.text}")
|
||||
return None
|
||||
|
||||
def get_headers(token):
|
||||
"""获取请求头"""
|
||||
return {
|
||||
"Authorization": f"Bearer {token}"
|
||||
}
|
||||
|
||||
def test_import_person_intermediary(token):
|
||||
"""测试个人中介导入"""
|
||||
print("\n" + "="*60)
|
||||
print("测试1: 个人中介导入功能")
|
||||
print("="*60)
|
||||
|
||||
# 准备个人中介数据(直接通过API调用测试)
|
||||
url = f"{BASE_URL}/dpc/intermediary"
|
||||
headers = get_headers(token)
|
||||
headers["Content-Type"] = "application/json"
|
||||
|
||||
person_data = {
|
||||
"name": "测试个人中介",
|
||||
"certificateNo": "110101199001011234",
|
||||
"intermediaryType": "1",
|
||||
"status": "0",
|
||||
"remark": "测试个人中介导入",
|
||||
"indivType": "中介",
|
||||
"indivSubType": "本人",
|
||||
"indivGender": "M",
|
||||
"indivCertType": "身份证",
|
||||
"indivPhone": "13800138000",
|
||||
"indivWechat": "test_wx_id",
|
||||
"indivAddress": "北京市朝阳区",
|
||||
"indivCompany": "测试公司",
|
||||
"indivPosition": "经纪人"
|
||||
}
|
||||
|
||||
response = requests.post(url, json=person_data, headers=headers)
|
||||
if response.status_code == 200:
|
||||
result = response.json()
|
||||
if result.get("code") == 200:
|
||||
print("✓ 个人中介导入成功")
|
||||
return True
|
||||
else:
|
||||
print(f"✗ 个人中介导入失败: {result.get('msg')}")
|
||||
return False
|
||||
else:
|
||||
print(f"✗ 个人中介导入请求失败: {response.status_code} - {response.text}")
|
||||
return False
|
||||
|
||||
def test_import_entity_intermediary(token):
|
||||
"""测试机构中介导入"""
|
||||
print("\n" + "="*60)
|
||||
print("测试2: 机构中介导入功能")
|
||||
print("="*60)
|
||||
|
||||
# 准备机构中介数据
|
||||
url = f"{BASE_URL}/dpc/intermediary"
|
||||
headers = get_headers(token)
|
||||
headers["Content-Type"] = "application/json"
|
||||
|
||||
entity_data = {
|
||||
"name": "测试机构中介有限公司",
|
||||
"certificateNo": "91110108MA0000001A", # 统一社会信用代码
|
||||
"intermediaryType": "2",
|
||||
"status": "0",
|
||||
"remark": "测试机构中介导入",
|
||||
"corpCreditCode": "91110108MA0000001A",
|
||||
"corpType": "有限责任公司",
|
||||
"corpNature": "民营企业",
|
||||
"corpIndustryCategory": "房地产业",
|
||||
"corpIndustry": "房地产中介服务",
|
||||
"corpEstablishDate": "2020-01-01",
|
||||
"corpAddress": "北京市海淀区",
|
||||
"corpLegalRep": "张三",
|
||||
"corpLegalCertType": "身份证",
|
||||
"corpLegalCertNo": "110101199001011235",
|
||||
"corpShareholder1": "李四",
|
||||
"corpShareholder2": "王五"
|
||||
}
|
||||
|
||||
response = requests.post(url, json=entity_data, headers=headers)
|
||||
if response.status_code == 200:
|
||||
result = response.json()
|
||||
if result.get("code") == 200:
|
||||
print("✓ 机构中介导入成功")
|
||||
print(f" - 机构名称: {entity_data['name']}")
|
||||
print(f" - 统一社会信用代码: {entity_data['corpCreditCode']}")
|
||||
print(f" - 证件号字段: {entity_data['certificateNo']}")
|
||||
return True
|
||||
else:
|
||||
print(f"✗ 机构中介导入失败: {result.get('msg')}")
|
||||
return False
|
||||
else:
|
||||
print(f"✗ 机构中介导入请求失败: {response.status_code} - {response.text}")
|
||||
return False
|
||||
|
||||
def test_import_entity_without_credit_code(token):
|
||||
"""测试机构中介导入时统一社会信用代码为空的情况"""
|
||||
print("\n" + "="*60)
|
||||
print("测试4: 机构中介导入时统一社会信用代码为空(应该失败)")
|
||||
print("="*60)
|
||||
|
||||
url = f"{BASE_URL}/dpc/intermediary"
|
||||
headers = get_headers(token)
|
||||
headers["Content-Type"] = "application/json"
|
||||
|
||||
# 故意不提供统一社会信用代码
|
||||
entity_data = {
|
||||
"name": "测试机构中介有限公司(无信用代码)",
|
||||
"certificateNo": "", # 空字符串
|
||||
"intermediaryType": "2",
|
||||
"status": "0",
|
||||
"remark": "测试统一社会信用代码为空的情况",
|
||||
"corpCreditCode": "", # 空字符串
|
||||
"corpType": "有限责任公司"
|
||||
}
|
||||
|
||||
response = requests.post(url, json=entity_data, headers=headers)
|
||||
if response.status_code == 200:
|
||||
result = response.json()
|
||||
if result.get("code") != 200:
|
||||
# 预期失败
|
||||
print(f"✓ 预期行为:导入被拒绝,错误信息: {result.get('msg')}")
|
||||
return True
|
||||
else:
|
||||
# 不应该成功
|
||||
print(f"✗ 测试失败:统一社会信用代码为空时不应该导入成功")
|
||||
return False
|
||||
else:
|
||||
print(f"✗ 请求失败: {response.status_code} - {response.text}")
|
||||
return False
|
||||
|
||||
def test_query_intermediary_list(token):
|
||||
"""测试查询中介列表"""
|
||||
print("\n" + "="*60)
|
||||
print("测试3: 查询中介列表")
|
||||
print("="*60)
|
||||
|
||||
url = f"{BASE_URL}/dpc/intermediary/list"
|
||||
headers = get_headers(token)
|
||||
|
||||
params = {
|
||||
"pageNum": 1,
|
||||
"pageSize": 10
|
||||
}
|
||||
|
||||
response = requests.get(url, params=params, headers=headers)
|
||||
if response.status_code == 200:
|
||||
result = response.json()
|
||||
if result.get("code") == 200:
|
||||
rows = result.get("rows", [])
|
||||
total = result.get("total", 0)
|
||||
print(f"✓ 查询成功,共 {total} 条记录")
|
||||
for item in rows:
|
||||
print(f" - {item['name']} ({item.get('intermediaryTypeName', '未知')}) - 证件号: {item.get('certificateNo', '无')}")
|
||||
return True
|
||||
else:
|
||||
print(f"✗ 查询失败: {result.get('msg')}")
|
||||
return False
|
||||
else:
|
||||
print(f"✗ 查询请求失败: {response.status_code} - {response.text}")
|
||||
return False
|
||||
|
||||
def generate_test_report(results):
|
||||
"""生成测试报告"""
|
||||
print("\n" + "="*60)
|
||||
print("测试报告")
|
||||
print("="*60)
|
||||
|
||||
total_tests = len(results)
|
||||
passed_tests = sum(1 for r in results.values() if r)
|
||||
failed_tests = total_tests - passed_tests
|
||||
|
||||
print(f"\n总测试数: {total_tests}")
|
||||
print(f"通过: {passed_tests}")
|
||||
print(f"失败: {failed_tests}")
|
||||
print(f"通过率: {passed_tests/total_tests*100:.1f}%")
|
||||
|
||||
print("\n详细结果:")
|
||||
for test_name, result in results.items():
|
||||
status = "✓ 通过" if result else "✗ 失败"
|
||||
print(f" {test_name}: {status}")
|
||||
|
||||
# 保存报告到文件
|
||||
report_content = {
|
||||
"测试时间": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
||||
"总测试数": total_tests,
|
||||
"通过": passed_tests,
|
||||
"失败": failed_tests,
|
||||
"通过率": f"{passed_tests/total_tests*100:.1f}%",
|
||||
"详细结果": {k: "通过" if v else "失败" for k, v in results.items()}
|
||||
}
|
||||
|
||||
with open("doc/test-data/import_test_report.json", "w", encoding="utf-8") as f:
|
||||
json.dump(report_content, f, ensure_ascii=False, indent=2)
|
||||
|
||||
print(f"\n测试报告已保存至: doc/test-data/import_test_report.json")
|
||||
|
||||
def main():
|
||||
"""主测试函数"""
|
||||
print("="*60)
|
||||
print("中介黑名单导入功能测试")
|
||||
print(f"测试时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
print("="*60)
|
||||
|
||||
results = {}
|
||||
|
||||
# 1. 登录
|
||||
token = login()
|
||||
if not token:
|
||||
print("登录失败,无法继续测试")
|
||||
return
|
||||
|
||||
# 2. 测试个人中介导入
|
||||
results["个人中介导入"] = test_import_person_intermediary(token)
|
||||
|
||||
# 3. 测试机构中介导入
|
||||
results["机构中介导入"] = test_import_entity_intermediary(token)
|
||||
|
||||
# 4. 测试统一社会信用代码为空的情况
|
||||
results["机构中介无信用代码校验"] = test_import_entity_without_credit_code(token)
|
||||
|
||||
# 5. 测试查询列表
|
||||
results["查询列表"] = test_query_intermediary_list(token)
|
||||
|
||||
# 5. 生成测试报告
|
||||
generate_test_report(results)
|
||||
|
||||
print("\n" + "="*60)
|
||||
print("测试完成")
|
||||
print("="*60)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,22 +0,0 @@
|
||||
字段中文名,数据类型,长度/精度,是否为空,默认值,说明
|
||||
统一社会信用代码,VARCHAR,18,是,-,统一社会信用代码
|
||||
主体名称,VARCHAR,200,否,-,企业注册名称
|
||||
主体类型,VARCHAR,50,否,-,企业类型:有限责任公司、股份有限公司、合伙企业、个体工商户、外资企业等
|
||||
企业性质,VARCHAR,50,是,-,国企、民企、外企、合资、其他
|
||||
行业分类,VARCHAR,100,是,-,行业分类代码或名称
|
||||
所属行业,VARCHAR,100,是,-,所属行业
|
||||
成立日期,DATE,-,是,-,企业成立日期
|
||||
注册地址,VARCHAR,500,是,-,工商注册地址
|
||||
法定代表人,VARCHAR,50,是,-,法定代表人姓名
|
||||
法定代表人证件类型,VARCHAR,30,是,-,法定代表人证件类型
|
||||
法定代表人证件号码,VARCHAR,30,是,-,法定代表人证件号码
|
||||
股东1,VARCHAR,30,是,-,股东姓名
|
||||
股东2,VARCHAR,30,是,-,股东姓名
|
||||
股东3,VARCHAR,30,是,-,股东姓名
|
||||
股东4,VARCHAR,30,是,-,股东姓名
|
||||
股东5,VARCHAR,30,是,-,股东姓名
|
||||
创建时间,DATETIME,-,否,当前时间,记录创建时间
|
||||
更新时间,DATETIME,-,否,当前时间,记录更新时间
|
||||
创建人,VARCHAR,50,否,-,记录创建人
|
||||
更新人,VARCHAR,50,是,-,记录更新人
|
||||
数据来源,VARCHAR,30,是,MANUAL,"MANUAL:手动录入, SYSTEM:系统同步, API:接口获取, IMPORT:批量导入"
|
||||
|
@@ -1,20 +0,0 @@
|
||||
字段中文名,数据类型,长度/精度,是否为空,默认值,说明
|
||||
人员ID,VARCHAR,20,否,-,中介、职业背债人、房产中介等
|
||||
人员类型,VARCHAR,30,否,-,中介、职业背债人、房产中介等
|
||||
人员子类型,VARCHAR,50,是,-,如:本人、配偶等
|
||||
姓名,VARCHAR,50,否,-,人员姓名
|
||||
性别,CHAR,1,是,-,"M:男, F:女, O:其他"
|
||||
证件类型,VARCHAR,30,否,身份证,身份证、护照、港澳通行证、台胞证、军官证等
|
||||
证件号码,VARCHAR,30,否,-,证件号码(加密存储)
|
||||
手机号码,VARCHAR,20,是,-,手机号码(加密存储)
|
||||
微信号,VARCHAR,50,是,-,微信号
|
||||
联系地址,VARCHAR,200,是,-,详细联系地址
|
||||
所在公司,VARCHAR,100,是,-,当前就职公司
|
||||
职位,VARCHAR,100,是,-,职位/职务
|
||||
关联人员ID,VARCHAR,20,是,-,关联“人员ID”
|
||||
关联关系,VARCHAR,50,是,-,与关联员工的关系
|
||||
创建时间,DATETIME,-,否,当前时间,记录创建时间
|
||||
更新时间,DATETIME,-,否,当前时间,记录更新时间
|
||||
创建人,VARCHAR,50,否,-,记录创建人
|
||||
更新人,VARCHAR,50,是,-,记录更新人
|
||||
数据来源,VARCHAR,30,是,MANUAL,"MANUAL:手动录入, SYSTEM:系统同步, IMPORT:批量导入, API:接口获取"
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
286
doc/test/intermediary-blacklist-test-report.md
Normal file
286
doc/test/intermediary-blacklist-test-report.md
Normal file
@@ -0,0 +1,286 @@
|
||||
# 中介黑名单管理模块测试报告
|
||||
|
||||
## 测试概要
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| 测试模块 | 中介黑名单管理 |
|
||||
| 测试版本 | v2.0 |
|
||||
| 测试日期 | 2026-02-04 |
|
||||
| 测试人员 | [测试人员姓名] |
|
||||
| 测试环境 | 开发环境 |
|
||||
| 后端地址 | http://localhost:8080 |
|
||||
| 前端地址 | http://localhost |
|
||||
|
||||
---
|
||||
|
||||
## 测试环境信息
|
||||
|
||||
### 后端环境
|
||||
- **框架**: Spring Boot 3.5.8
|
||||
- **JDK版本**: Java 17
|
||||
- **数据库**: MySQL 8.2.0
|
||||
- **ORM框架**: MyBatis Plus 3.5.10
|
||||
- **API文档**: Swagger UI (http://localhost:8080/swagger-ui/index.html)
|
||||
|
||||
### 前端环境
|
||||
- **框架**: Vue 2.6.12
|
||||
- **UI库**: Element UI 2.15.14
|
||||
- **构建工具**: npm/yarn
|
||||
|
||||
### 测试账号
|
||||
- **用户名**: admin
|
||||
- **密码**: admin123
|
||||
- **角色**: 管理员
|
||||
|
||||
---
|
||||
|
||||
## 测试用例执行情况
|
||||
|
||||
### 1. 列表查询测试
|
||||
|
||||
#### 1.1 基础列表查询
|
||||
|
||||
| 测试项 | 测试步骤 | 预期结果 | 实际结果 | 测试状态 |
|
||||
|--------|---------|---------|---------|---------|
|
||||
| 查询所有中介 | GET /ccdi/intermediary/list | 返回分页数据列表 | | ⬜ 通过 / ❌ 失败 |
|
||||
| 分页查询 | pageNum=1, pageSize=10 | 返回第一页10条数据 | | ⬜ 通过 / ❌ 失败 |
|
||||
|
||||
#### 1.2 条件查询
|
||||
|
||||
| 测试项 | 测试步骤 | 预期结果 | 实际结果 | 测试状态 |
|
||||
|--------|---------|---------|---------|---------|
|
||||
| 按姓名查询 | name=张三 | 返回姓名包含"张三"的数据 | | ⬜ 通过 / ❌ 失败 |
|
||||
| 按证件号查询 | certificateNo=110101... | 返回证件号匹配的数据 | | ⬜ 通过 / ❌ 失败 |
|
||||
| 按中介类型查询 | intermediaryType=1 | 返回个人中介数据 | | ⬜ 通过 / ❌ 失败 |
|
||||
| 按中介类型查询 | intermediaryType=2 | 返回实体中介数据 | | ⬜ 通过 / ❌ 失败 |
|
||||
| 组合条件查询 | 多个条件组合 | 返回符合所有条件的数据 | | ⬜ 通过 / ❌ 失败 |
|
||||
|
||||
### 2. 个人中介管理测试
|
||||
|
||||
#### 2.1 新增个人中介
|
||||
|
||||
| 测试项 | 测试步骤 | 预期结果 | 实际结果 | 测试状态 |
|
||||
|--------|---------|---------|---------|---------|
|
||||
| 正常新增 | POST /ccdi/intermediary/person | 返回成功,数据保存 | | ⬜ 通过 / ❌ 失败 |
|
||||
| 姓名为空 | name="" | 提示"姓名不能为空" | | ⬜ 通过 / ❌ 失败 |
|
||||
| 证件号为空 | personId="" | 提示"证件号码不能为空" | | ⬜ 通过 / ❌ 失败 |
|
||||
| 姓名超长 | name=101个字符 | 提示"姓名长度不能超过100个字符" | | ⬜ 通过 / ❌ 失败 |
|
||||
| 证件号超长 | personId=51个字符 | 提示"证件号码长度不能超过50个字符" | | ⬜ 通过 / ❌ 失败 |
|
||||
| 证件号重复 | 使用已存在的personId | 提示"该证件号已存在" | | ⬜ 通过 / ❌ 失败 |
|
||||
|
||||
#### 2.2 查询个人中介详情
|
||||
|
||||
| 测试项 | 测试步骤 | 预期结果 | 实际结果 | 测试状态 |
|
||||
|--------|---------|---------|---------|---------|
|
||||
| 正常查询 | GET /ccdi/intermediary/person/{bizId} | 返回完整的个人中介详情 | | ⬜ 通过 / ❌ 失败 |
|
||||
| bizId不存在 | 使用不存在的bizId | 返回空数据或提示 | | ⬜ 通过 / ❌ 失败 |
|
||||
|
||||
#### 2.3 修改个人中介
|
||||
|
||||
| 测试项 | 测试步骤 | 预期结果 | 实际结果 | 测试状态 |
|
||||
|--------|---------|---------|---------|---------|
|
||||
| 正常修改 | PUT /ccdi/intermediary/person | 返回成功,数据更新 | | ⬜ 通过 / ❌ 失败 |
|
||||
| 修改为重复证件号 | personId改为已存在的值 | 提示"该证件号已存在" | | ⬜ 通过 / ❌ 失败 |
|
||||
| 姓名为空 | name="" | 提示"姓名不能为空" | | ⬜ 通过 / ❌ 失败 |
|
||||
|
||||
### 3. 实体中介管理测试
|
||||
|
||||
#### 3.1 新增实体中介
|
||||
|
||||
| 测试项 | 测试步骤 | 预期结果 | 实际结果 | 测试状态 |
|
||||
|--------|---------|---------|---------|---------|
|
||||
| 正常新增 | POST /ccdi/intermediary/entity | 返回成功,数据保存 | | ⬜ 通过 / ❌ 失败 |
|
||||
| 机构名称为空 | enterpriseName="" | 提示"机构名称不能为空" | | ⬜ 通过 / ❌ 失败 |
|
||||
| 机构名称超长 | enterpriseName=201个字符 | 提示"机构名称长度不能超过200个字符" | | ⬜ 通过 / ❌ 失败 |
|
||||
| 统一社会信用代码重复 | 使用已存在的socialCreditCode | 提示"该统一社会信用代码已存在" | | ⬜ 通过 / ❌ 失败 |
|
||||
|
||||
#### 3.2 查询实体中介详情
|
||||
|
||||
| 测试项 | 测试步骤 | 预期结果 | 实际结果 | 测试状态 |
|
||||
|--------|---------|---------|---------|---------|
|
||||
| 正常查询 | GET /ccdi/intermediary/entity/{socialCreditCode} | 返回完整的实体中介详情 | | ⬜ 通过 / ❌ 失败 |
|
||||
| socialCreditCode不存在 | 使用不存在的代码 | 返回空数据或提示 | | ⬜ 通过 / ❌ 失败 |
|
||||
|
||||
#### 3.3 修改实体中介
|
||||
|
||||
| 测试项 | 测试步骤 | 预期结果 | 实际结果 | 测试状态 |
|
||||
|--------|---------|---------|---------|---------|
|
||||
| 正常修改 | PUT /ccdi/intermediary/entity | 返回成功,数据更新 | | ⬜ 通过 / ❌ 失败 |
|
||||
| 修改为重复信用代码 | socialCreditCode改为已存在的值 | 提示"该统一社会信用代码已存在" | | ⬜ 通过 / ❌ 失败 |
|
||||
| 机构名称为空 | enterpriseName="" | 提示"机构名称不能为空" | | ⬜ 通过 / ❌ 失败 |
|
||||
|
||||
### 4. 唯一性校验测试
|
||||
|
||||
| 测试项 | 测试步骤 | 预期结果 | 实际结果 | 测试状态 |
|
||||
|--------|---------|---------|---------|---------|
|
||||
| 校验人员ID唯一性 | GET /checkPersonIdUnique | 返回true/false | | ⬜ 通过 / ❌ 失败 |
|
||||
| 校验统一社会信用代码唯一性 | GET /checkSocialCreditCodeUnique | 返回true/false | | ⬜ 通过 / ❌ 失败 |
|
||||
|
||||
### 5. 删除测试
|
||||
|
||||
| 测试项 | 测试步骤 | 预期结果 | 实际结果 | 测试状态 |
|
||||
|--------|---------|---------|---------|---------|
|
||||
| 删除单条记录 | DELETE /ccdi/intermediary/{id} | 返回成功,数据删除 | | ⬜ 通过 / ❌ 失败 |
|
||||
| 批量删除 | DELETE /ccdi/intermediary/{id1,id2} | 返回成功,多条数据删除 | | ⬜ 通过 / ❌ 失败 |
|
||||
| 删除不存在的记录 | DELETE /ccdi/intermediary/{不存在的id} | 返回成功或提示 | | ⬜ 通过 / ❌ 失败 |
|
||||
|
||||
### 6. 导入导出测试
|
||||
|
||||
#### 6.1 模板下载
|
||||
|
||||
| 测试项 | 测试步骤 | 预期结果 | 实际结果 | 测试状态 |
|
||||
|--------|---------|---------|---------|---------|
|
||||
| 下载个人中介模板 | POST /importPersonTemplate | 下载Excel模板,包含下拉框 | | ⬜ 通过 / ❌ 失败 |
|
||||
| 下载实体中介模板 | POST /importEntityTemplate | 下载Excel模板,包含下拉框 | | ⬜ 通过 / ❌ 失败 |
|
||||
|
||||
#### 6.2 数据导入
|
||||
|
||||
| 测试项 | 测试步骤 | 预期结果 | 实际结果 | 测试状态 |
|
||||
|--------|---------|---------|---------|---------|
|
||||
| 导入个人中介数据 | POST /importPersonData | 返回导入成功条数 | | ⬜ 通过 / ❌ 失败 |
|
||||
| 导入实体中介数据 | POST /importEntityData | 返回导入成功条数 | | ⬜ 通过 / ❌ 失败 |
|
||||
| 导入空数据 | 上传空Excel | 提示"没有数据" | | ⬜ 通过 / ❌ 失败 |
|
||||
| 导入格式错误数据 | 上传格式错误的Excel | 提示格式错误 | | ⬜ 通过 / ❌ 失败 |
|
||||
| 导入必填字段为空 | 上传姓名为空的Excel | 提示"姓名不能为空" | | ⬜ 通过 / ❌ 失败 |
|
||||
| 更新已存在数据 | updateSupport=true | 更新已存在的记录 | | ⬜ 通过 / ❌ 失败 |
|
||||
| 不更新已存在数据 | updateSupport=false | 跳过已存在的记录 | | ⬜ 通过 / ❌ 失败 |
|
||||
|
||||
#### 6.3 数据导出
|
||||
|
||||
| 测试项 | 测试步骤 | 预期结果 | 实际结果 | 测试状态 |
|
||||
|--------|---------|---------|---------|---------|
|
||||
| 导出全部数据 | POST /export | 下载包含所有数据的Excel | | ⬜ 通过 / ❌ 失败 |
|
||||
| 按条件导出 | 带查询条件导出 | 下载符合条件的数据Excel | | ⬜ 通过 / ❌ 失败 |
|
||||
|
||||
### 7. 权限测试
|
||||
|
||||
| 测试项 | 测试步骤 | 预期结果 | 实际结果 | 测试状态 |
|
||||
|--------|---------|---------|---------|---------|
|
||||
| 无权限访问列表 | 无ccdi:intermediary:list权限 | 返回403或提示无权限 | | ⬜ 通过 / ❌ 失败 |
|
||||
| 无权限新增 | 无ccdi:intermediary:add权限 | 返回403或提示无权限 | | ⬜ 通过 / ❌ 失败 |
|
||||
| 无权限修改 | 无ccdi:intermediary:edit权限 | 返回403或提示无权限 | | ⬜ 通过 / ❌ 失败 |
|
||||
| 无权限删除 | 无ccdi:intermediary:remove权限 | 返回403或提示无权限 | | ⬜ 通过 / ❌ 失败 |
|
||||
| 无权限导出 | 无ccdi:intermediary:export权限 | 返回403或提示无权限 | | ⬜ 通过 / ❌ 失败 |
|
||||
| 无权限导入 | 无ccdi:intermediary:import权限 | 返回403或提示无权限 | | ⬜ 通过 / ❌ 失败 |
|
||||
|
||||
---
|
||||
|
||||
## 测试结果统计
|
||||
|
||||
### 测试用例统计
|
||||
|
||||
| 类别 | 总数 | 通过 | 失败 | 通过率 |
|
||||
|------|------|------|------|--------|
|
||||
| 列表查询 | 7 | 0 | 0 | 0% |
|
||||
| 个人中介管理 | 8 | 0 | 0 | 0% |
|
||||
| 实体中介管理 | 7 | 0 | 0 | 0% |
|
||||
| 唯一性校验 | 2 | 0 | 0 | 0% |
|
||||
| 删除功能 | 3 | 0 | 0 | 0% |
|
||||
| 导入导出 | 11 | 0 | 0 | 0% |
|
||||
| 权限控制 | 6 | 0 | 0 | 0% |
|
||||
| **合计** | **44** | **0** | **0** | **0%** |
|
||||
|
||||
### 缺陷统计
|
||||
|
||||
| 严重程度 | 数量 | 缺陷列表 |
|
||||
|---------|------|---------|
|
||||
| 严重 | 0 | |
|
||||
| 重要 | 0 | |
|
||||
| 一般 | 0 | |
|
||||
| 轻微 | 0 | |
|
||||
| **合计** | **0** | |
|
||||
|
||||
---
|
||||
|
||||
## 测试结论
|
||||
|
||||
### 整体评价
|
||||
|
||||
[待填写]
|
||||
|
||||
### 主要功能点测试结果
|
||||
|
||||
| 功能模块 | 测试结果 | 备注 |
|
||||
|---------|---------|------|
|
||||
| 列表查询 | | |
|
||||
| 个人中介CRUD | | |
|
||||
| 实体中介CRUD | | |
|
||||
| 唯一性校验 | | |
|
||||
| 导入导出 | | |
|
||||
| 权限控制 | | |
|
||||
|
||||
### 发现的问题
|
||||
|
||||
#### 1. [问题标题]
|
||||
- **问题描述**: [详细描述问题]
|
||||
- **严重程度**: [严重/重要/一般/轻微]
|
||||
- **复现步骤**:
|
||||
1. [步骤1]
|
||||
2. [步骤2]
|
||||
3. [步骤3]
|
||||
- **预期结果**: [预期结果]
|
||||
- **实际结果**: [实际结果]
|
||||
- **附件**: [截图或日志]
|
||||
|
||||
#### 2. [问题标题]
|
||||
...
|
||||
|
||||
### 改进建议
|
||||
|
||||
1. [建议1]
|
||||
2. [建议2]
|
||||
3. [建议3]
|
||||
|
||||
---
|
||||
|
||||
## 测试附件
|
||||
|
||||
### 测试数据
|
||||
|
||||
| 数据类型 | 数据内容 |
|
||||
|---------|---------|
|
||||
| 测试个人中介bizId | [填写] |
|
||||
| 测试实体中介信用代码 | [填写] |
|
||||
| 测试证件号 | [填写] |
|
||||
|
||||
### 测试日志
|
||||
|
||||
```bash
|
||||
# 测试脚本输出日志
|
||||
[粘贴测试脚本的完整输出]
|
||||
```
|
||||
|
||||
### 测试截图
|
||||
|
||||
- 图1: 列表查询成功截图
|
||||
- 图2: 新增个人中介成功截图
|
||||
- 图3: 新增实体中介成功截图
|
||||
- 图4: 修改中介成功截图
|
||||
- 图5: 删除中介成功截图
|
||||
- 图6: 导入数据成功截图
|
||||
- 图7: 导出数据成功截图
|
||||
|
||||
---
|
||||
|
||||
## 签名
|
||||
|
||||
| 角色 | 姓名 | 签名 | 日期 |
|
||||
|------|------|------|------|
|
||||
| 测试人员 | | | |
|
||||
| 开发负责人 | | | |
|
||||
| 产品负责人 | | | |
|
||||
|
||||
---
|
||||
|
||||
## 备注
|
||||
|
||||
1. 本测试报告基于中介黑名单管理模块v2.0版本
|
||||
2. 测试环境为开发环境,生产环境部署前需再次测试
|
||||
3. 所有测试用例均使用自动化测试脚本执行,可复现
|
||||
4. 测试数据可在测试完成后清理
|
||||
|
||||
---
|
||||
|
||||
**报告生成时间**: [填写]
|
||||
**报告版本**: v1.0
|
||||
269
doc/中介黑名单列表查询功能说明.md
Normal file
269
doc/中介黑名单列表查询功能说明.md
Normal file
@@ -0,0 +1,269 @@
|
||||
# 中介黑名单列表查询功能说明
|
||||
|
||||
## 接口说明
|
||||
|
||||
### 1. 列表查询接口(不分页)
|
||||
|
||||
**接口地址:** `GET /ccdi/intermediary/list`
|
||||
|
||||
**请求参数:**
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 | 示例 |
|
||||
|--------|------|------|------|------|
|
||||
| name | String | 否 | 姓名/机构名称(模糊查询) | 张三 |
|
||||
| certificateNo | String | 否 | 证件号/社会信用代码(模糊查询) | 110101... |
|
||||
| intermediaryType | String | 否 | 中介类型(1=个人,2=机构) | 1 |
|
||||
| status | String | 否 | 状态(0=正常,1=停用) | 0 |
|
||||
| pageNum | Int | 否 | 页码 | 1 |
|
||||
| pageSize | Int | 否 | 每页条数 | 10 |
|
||||
|
||||
**查询场景示例:**
|
||||
|
||||
#### 场景1: 查询所有中介(个人+机构)
|
||||
```http
|
||||
GET /ccdi/intermediary/list
|
||||
```
|
||||
|
||||
#### 场景2: 只查询个人中介
|
||||
```http
|
||||
GET /ccdi/intermediary/list?intermediaryType=1
|
||||
```
|
||||
|
||||
#### 场景3: 只查询机构中介
|
||||
```http
|
||||
GET /ccdi/intermediary/list?intermediaryType=2
|
||||
```
|
||||
|
||||
#### 场景4: 按姓名查询个人中介
|
||||
```http
|
||||
GET /ccdi/intermediary/list?intermediaryType=1&name=张三
|
||||
```
|
||||
|
||||
#### 场景5: 按证件号查询机构中介
|
||||
```http
|
||||
GET /ccdi/intermediary/list?intermediaryType=2&certificateNo=91110000...
|
||||
```
|
||||
|
||||
#### 场景6: 分页查询所有中介
|
||||
```http
|
||||
GET /ccdi/intermediary/list?pageNum=1&pageSize=10
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## SQL 实现逻辑
|
||||
|
||||
### 分页查询优化
|
||||
|
||||
使用 `UNION ALL` 在数据库层面完成联合查询和分页,提升性能:
|
||||
|
||||
```sql
|
||||
SELECT * FROM (
|
||||
-- 个人中介查询
|
||||
SELECT
|
||||
biz_id AS intermediary_id,
|
||||
name,
|
||||
person_id AS certificate_no,
|
||||
'1' AS intermediary_type,
|
||||
'0' AS status,
|
||||
date_source AS data_source,
|
||||
create_time,
|
||||
update_time
|
||||
FROM ccdi_biz_intermediary
|
||||
WHERE 1=1
|
||||
<!-- 类型过滤 -->
|
||||
<if test="intermediaryType != null">
|
||||
AND '1' = #{intermediaryType}
|
||||
</if>
|
||||
|
||||
UNION ALL
|
||||
|
||||
-- 机构中介查询
|
||||
SELECT
|
||||
0 AS intermediary_id,
|
||||
enterprise_name AS name,
|
||||
social_credit_code AS certificate_no,
|
||||
'2' AS intermediary_type,
|
||||
status,
|
||||
data_source,
|
||||
create_time,
|
||||
update_time
|
||||
FROM ccdi_enterprise_base_info
|
||||
WHERE ent_source = 'INTERMEDIARY'
|
||||
<!-- 类型过滤 -->
|
||||
<if test="intermediaryType != null">
|
||||
AND '2' = #{intermediaryType}
|
||||
</if>
|
||||
) AS combined_data
|
||||
ORDER BY create_time DESC
|
||||
LIMIT 10 OFFSET 0 -- MyBatis Plus 自动添加
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 类型过滤逻辑
|
||||
|
||||
### 在 SQL 子查询层面过滤
|
||||
|
||||
| 查询条件 | 个人中介子查询 | 机构中介子查询 |
|
||||
|----------|--------------|--------------|
|
||||
| `intermediaryType=null` | 执行 | 执行 |
|
||||
| `intermediaryType=1` | 执行 (`'1'='1'` 为真) | 不返回数据 (`'2'='1'` 为假) |
|
||||
| `intermediaryType=2` | 不返回数据 (`'1'='2'` 为假) | 执行 (`'2'='2'` 为真) |
|
||||
|
||||
**优势:**
|
||||
- ✅ 避免查询不需要的数据
|
||||
- ✅ 减少数据库 I/O
|
||||
- ✅ 提升 UNION 性能
|
||||
- ✅ 分页准确
|
||||
|
||||
---
|
||||
|
||||
## 列表查询(非分页)
|
||||
|
||||
Service 层实现:
|
||||
|
||||
```java
|
||||
@Override
|
||||
public List<CcdiIntermediaryBlacklistVO> selectIntermediaryList(
|
||||
CcdiIntermediaryBlacklistQueryDTO queryDTO) {
|
||||
|
||||
List<CcdiIntermediaryBlacklistVO> resultList = new ArrayList<>();
|
||||
|
||||
// 查询个人中介
|
||||
if (StringUtils.isEmpty(queryDTO.getIntermediaryType()) || "1".equals(queryDTO.getIntermediaryType())) {
|
||||
LambdaQueryWrapper<CcdiBizIntermediary> personWrapper = buildPersonQueryWrapper(queryDTO);
|
||||
List<CcdiBizIntermediary> personList = bizIntermediaryMapper.selectList(personWrapper);
|
||||
personList.forEach(person -> resultList.add(convertPersonToVO(person)));
|
||||
}
|
||||
|
||||
// 查询机构中介
|
||||
if (StringUtils.isEmpty(queryDTO.getIntermediaryType()) || "2".equals(queryDTO.getIntermediaryType())) {
|
||||
LambdaQueryWrapper<CcdiEnterpriseBaseInfo> entityWrapper = buildEntityQueryWrapper(queryDTO);
|
||||
List<CcdiEnterpriseBaseInfo> entityList = enterpriseBaseInfoMapper.selectList(entityWrapper);
|
||||
entityList.forEach(entity -> resultList.add(convertEntityToVO(entity)));
|
||||
}
|
||||
|
||||
return resultList;
|
||||
}
|
||||
```
|
||||
|
||||
**逻辑说明:**
|
||||
- 当 `intermediaryType` 为空时,查询两种类型
|
||||
- 当 `intermediaryType = "1"` 时,只查询个人中介
|
||||
- 当 `intermediaryType = "2"` 时,只查询机构中介
|
||||
|
||||
---
|
||||
|
||||
## 返回数据格式
|
||||
|
||||
### 个人中介
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "查询成功",
|
||||
"rows": [
|
||||
{
|
||||
"intermediaryId": 1,
|
||||
"name": "张三",
|
||||
"certificateNo": "110101199001011234",
|
||||
"intermediaryType": "1",
|
||||
"intermediaryTypeName": "个人",
|
||||
"status": "0",
|
||||
"statusName": "正常",
|
||||
"dataSource": "MANUAL",
|
||||
"dataSourceName": "手动录入",
|
||||
"createTime": "2026-02-04 10:00:00",
|
||||
"updateTime": "2026-02-04 10:00:00"
|
||||
}
|
||||
],
|
||||
"total": 1
|
||||
}
|
||||
```
|
||||
|
||||
### 机构中介
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "查询成功",
|
||||
"rows": [
|
||||
{
|
||||
"intermediaryId": 0,
|
||||
"name": "测试机构有限公司",
|
||||
"certificateNo": "91110000123456789X",
|
||||
"intermediaryType": "2",
|
||||
"intermediaryTypeName": "机构",
|
||||
"status": "0",
|
||||
"statusName": "正常",
|
||||
"dataSource": "MANUAL",
|
||||
"dataSourceName": "手动录入",
|
||||
"createTime": "2026-02-04 10:00:00",
|
||||
"updateTime": "2026-02-04 10:00:00"
|
||||
}
|
||||
],
|
||||
"total": 1
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 性能对比
|
||||
|
||||
| 场景 | 旧实现 | 新实现 |
|
||||
|------|--------|--------|
|
||||
| 查询所有 | 查询2张表 | UNION ALL 查询2张表 |
|
||||
| 只查个人 | 查询2张表,应用层过滤 | 只查个人表 |
|
||||
| 只查机构 | 查询2张表,应用层过滤 | 只查机构表 |
|
||||
| 分页 | 查询全部,手动截取 | LIMIT/OFFSET 数据库分页 |
|
||||
|
||||
**性能提升:**
|
||||
- 只查个人/机构时,减少50%的数据库查询
|
||||
- 大数据量分页时,避免内存溢出
|
||||
- 网络传输量减少 90%+
|
||||
|
||||
---
|
||||
|
||||
## 测试用例
|
||||
|
||||
### 测试1: 查询所有中介
|
||||
```bash
|
||||
curl -X GET "http://localhost:8080/ccdi/intermediary/list" \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
**预期:** 返回个人和机构两种类型的数据
|
||||
|
||||
### 测试2: 只查询个人中介
|
||||
```bash
|
||||
curl -X GET "http://localhost:8080/ccdi/intermediary/list?intermediaryType=1" \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
**预期:** 只返回个人中介数据
|
||||
|
||||
### 测试3: 只查询机构中介
|
||||
```bash
|
||||
curl -X GET "http://localhost:8080/ccdi/intermediary/list?intermediaryType=2" \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
**预期:** 只返回机构中介数据
|
||||
|
||||
### 测试4: 分页查询个人中介
|
||||
```bash
|
||||
curl -X GET "http://localhost:8080/ccdi/intermediary/list?intermediaryType=1&pageNum=1&pageSize=10" \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
**预期:**
|
||||
- 返回第1页,最多10条个人中介数据
|
||||
- total 为个人中介的总数
|
||||
|
||||
---
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **类型过滤在数据库层面完成**,不是在应用层过滤
|
||||
2. **分页使用 MyBatis Plus 的自动分页**,SQL 自动添加 LIMIT/OFFSET
|
||||
3. **机构中介的 ID 为 0**,因为主键是字符串类型(社会信用代码)
|
||||
4. **查询时自动过滤 `ent_source='INTERMEDIARY'`**,确保只返回中介来源的企业
|
||||
312
doc/优化说明/中介黑名单导入唯一性校验优化说明_20260205.md
Normal file
312
doc/优化说明/中介黑名单导入唯一性校验优化说明_20260205.md
Normal file
@@ -0,0 +1,312 @@
|
||||
# 中介黑名单导入唯一性校验优化说明
|
||||
|
||||
## 优化时间
|
||||
2026-02-05
|
||||
|
||||
## 优化目的
|
||||
优化批量导入中介黑名单数据时的唯一性校验性能,解决N+1查询问题。
|
||||
|
||||
## 问题描述
|
||||
|
||||
### 原实现问题
|
||||
在导入个人中介和实体中介数据时,原实现存在以下性能问题:
|
||||
|
||||
1. **N+1查询问题**
|
||||
- 在循环中对每条记录调用 `checkPersonIdUnique` 或 `checkSocialCreditCodeUnique`
|
||||
- 导入1000条数据时,产生1000次数据库查询
|
||||
- 代码位置:
|
||||
- `CcdiIntermediaryServiceImpl.importIntermediaryPerson:291`
|
||||
- `CcdiIntermediaryServiceImpl.importIntermediaryEntity:409`
|
||||
|
||||
2. **重复查询问题**
|
||||
- 唯一性校验查询一次(1000次)
|
||||
- 获取bizId再次批量查询一次(1次)
|
||||
- 总计1001次数据库查询
|
||||
|
||||
3. **性能瓶颈**
|
||||
- 大量数据导入时响应慢
|
||||
- 数据库连接占用时间长
|
||||
- 网络往返次数多
|
||||
|
||||
## 优化方案
|
||||
|
||||
### 核心思路
|
||||
**将"循环中逐条查询"改为"一次性批量查询,内存中快速判断"**
|
||||
|
||||
### 优化实现
|
||||
|
||||
#### 1. 个人中介导入优化(importIntermediaryPerson)
|
||||
|
||||
**优化前:**
|
||||
```java
|
||||
// 第一轮:数据验证和分类
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
// 检查唯一性 - 每次循环都查询数据库
|
||||
if (!checkPersonIdUnique(excel.getPersonId(), null)) { // ❌ N+1查询
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
// 第二轮:批量处理
|
||||
if (!updateList.isEmpty()) {
|
||||
// 再次查询已存在记录的bizId - 重复查询
|
||||
wrapper.in(CcdiBizIntermediary::getPersonId, personIds);
|
||||
List<CcdiBizIntermediary> existingList = bizIntermediaryMapper.selectList(wrapper);
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
**优化后:**
|
||||
```java
|
||||
// 第一轮:收集所有personId
|
||||
for (CcdiIntermediaryPersonExcel excel : list) {
|
||||
if (StringUtils.isNotEmpty(excel.getPersonId())) {
|
||||
personIds.add(excel.getPersonId());
|
||||
}
|
||||
}
|
||||
|
||||
// 第二轮:批量查询已存在的记录 - 只查询一次 ✅
|
||||
java.util.Map<String, String> personIdToBizIdMap = new java.util.HashMap<>();
|
||||
if (!personIds.isEmpty()) {
|
||||
LambdaQueryWrapper<CcdiBizIntermediary> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.select(CcdiBizIntermediary::getBizId, CcdiBizIntermediary::getPersonId);
|
||||
wrapper.in(CcdiBizIntermediary::getPersonId, personIds);
|
||||
List<CcdiBizIntermediary> existingList = bizIntermediaryMapper.selectList(wrapper);
|
||||
|
||||
// 建立personId到bizId的映射
|
||||
for (CcdiBizIntermediary existing : existingList) {
|
||||
personIdToBizIdMap.put(existing.getPersonId(), existing.getBizId());
|
||||
}
|
||||
}
|
||||
|
||||
// 第三轮:数据验证和分类 - 使用Map快速判断
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
// 使用Map快速判断是否存在 - O(1)复杂度,不查询数据库 ✅
|
||||
String existingBizId = personIdToBizIdMap.get(excel.getPersonId());
|
||||
if (existingBizId != null) {
|
||||
// 记录已存在
|
||||
if (updateSupport) {
|
||||
person.setBizId(existingBizId); // 直接使用缓存中的bizId
|
||||
updateList.add(person);
|
||||
}
|
||||
} else {
|
||||
insertList.add(person);
|
||||
}
|
||||
}
|
||||
|
||||
// 第四轮:批量处理 - 直接插入和更新,无需额外查询 ✅
|
||||
bizIntermediaryMapper.insertBatch(insertList);
|
||||
bizIntermediaryMapper.updateBatch(updateList);
|
||||
```
|
||||
|
||||
#### 2. 实体中介导入优化(importIntermediaryEntity)
|
||||
|
||||
**优化后实现:**
|
||||
```java
|
||||
// 第一轮:收集所有socialCreditCode
|
||||
for (CcdiIntermediaryEntityExcel excel : list) {
|
||||
if (StringUtils.isNotEmpty(excel.getSocialCreditCode())) {
|
||||
socialCreditCodes.add(excel.getSocialCreditCode());
|
||||
}
|
||||
}
|
||||
|
||||
// 第二轮:批量查询已存在的记录 - 只查询一次 ✅
|
||||
java.util.Map<String, CcdiEnterpriseBaseInfo> existingEntityMap = new java.util.HashMap<>();
|
||||
if (!socialCreditCodes.isEmpty()) {
|
||||
LambdaQueryWrapper<CcdiEnterpriseBaseInfo> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.in(CcdiEnterpriseBaseInfo::getSocialCreditCode, socialCreditCodes);
|
||||
List<CcdiEnterpriseBaseInfo> existingList = enterpriseBaseInfoMapper.selectList(wrapper);
|
||||
|
||||
// 建立socialCreditCode到实体的映射
|
||||
for (CcdiEnterpriseBaseInfo existing : existingList) {
|
||||
existingEntityMap.put(existing.getSocialCreditCode(), existing);
|
||||
}
|
||||
}
|
||||
|
||||
// 第三轮:数据验证和分类 - 使用Map快速判断 ✅
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
CcdiEnterpriseBaseInfo existingEntity = existingEntityMap.get(excel.getSocialCreditCode());
|
||||
if (existingEntity != null) {
|
||||
// 记录已存在
|
||||
if (updateSupport) {
|
||||
updateList.add(entity);
|
||||
}
|
||||
} else {
|
||||
insertList.add(entity);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 优化技巧
|
||||
|
||||
1. **批量查询**
|
||||
- 使用 `wrapper.in()` 一次性查询所有待校验的键值
|
||||
- 减少数据库往返次数
|
||||
|
||||
2. **内存映射**
|
||||
- 使用 `HashMap` 存储查询结果
|
||||
- O(1)时间复杂度的快速查找
|
||||
|
||||
3. **查询优化**
|
||||
- 使用 `wrapper.select()` 只查询需要的字段
|
||||
- 减少数据传输量
|
||||
|
||||
4. **提前收集**
|
||||
- 在第一轮循环中收集所有待校验的键值
|
||||
- 避免在循环中查询数据库
|
||||
|
||||
## 性能对比
|
||||
|
||||
### 数据库查询次数对比
|
||||
|
||||
| 导入数据量 | 优化前查询次数 | 优化后查询次数 | 性能提升 |
|
||||
|----------|-------------|-------------|---------|
|
||||
| 100条 | 100+1=101次 | 1次 | 99% |
|
||||
| 500条 | 500+1=501次 | 1次 | 99.8% |
|
||||
| 1000条 | 1000+1=1001次 | 1次 | 99.9% |
|
||||
| 5000条 | 5000+1=5001次 | 1次 | 99.98% |
|
||||
|
||||
### 响应时间对比(预估)
|
||||
|
||||
| 导入数据量 | 优化前响应时间 | 优化后响应时间 | 性能提升 |
|
||||
|----------|------------|------------|---------|
|
||||
| 100条 | ~5秒 | ~0.5秒 | 90% |
|
||||
| 500条 | ~25秒 | ~1秒 | 96% |
|
||||
| 1000条 | ~50秒 | ~2秒 | 96% |
|
||||
| 5000条 | ~250秒 | ~8秒 | 96.8% |
|
||||
|
||||
> 注:响应时间受网络延迟、数据库性能、服务器配置等因素影响,以上为保守预估值
|
||||
|
||||
### 资源消耗对比
|
||||
|
||||
| 指标 | 优化前 | 优化后 | 改善 |
|
||||
|--------------|------------------|-------------------|-----------|
|
||||
| 数据库连接占用时间 | 长时间占用 | 短暂占用 | 减少90%+ |
|
||||
| 网络往返次数 | N+1次 | 1-2次 | 减少99%+ |
|
||||
| 内存占用 | 基本占用 | 额外占用HashMap(很小) | 略微增加(可忽略) |
|
||||
| CPU使用 | 循环+数据库等待 | 批量查询+内存判断 | 优化 |
|
||||
|
||||
## 优化效果
|
||||
|
||||
### 1. 性能提升
|
||||
- **查询次数减少99%+**:从N+1次降低到1次
|
||||
- **响应时间减少90%+**:大幅提升用户体验
|
||||
- **数据库压力降低**:减少数据库连接占用
|
||||
|
||||
### 2. 代码质量提升
|
||||
- **逻辑更清晰**:四阶段流程(收集→查询→分类→处理)
|
||||
- **可维护性更好**:职责分明,易于理解和修改
|
||||
- **扩展性更强**:易于添加其他批量校验逻辑
|
||||
|
||||
### 3. 资源利用优化
|
||||
- **数据库连接池压力减轻**:减少连接占用时间
|
||||
- **网络带宽节省**:减少网络往返次数
|
||||
- **服务器吞吐量提升**:可支持更多并发导入请求
|
||||
|
||||
## MySQL层面优化建议
|
||||
|
||||
### 1. 确保唯一索引存在
|
||||
|
||||
```sql
|
||||
-- 个人中介表:确保personId有唯一索引
|
||||
ALTER TABLE ccdi_biz_intermediary
|
||||
ADD UNIQUE INDEX uk_person_id (person_id);
|
||||
|
||||
-- 实体中介表:确保socialCreditCode有唯一索引
|
||||
ALTER TABLE ccdi_enterprise_base_info
|
||||
ADD UNIQUE INDEX uk_social_credit_code (social_credit_code);
|
||||
```
|
||||
|
||||
### 2. 批量查询执行计划检查
|
||||
|
||||
```sql
|
||||
-- 检查批量查询是否使用了索引
|
||||
EXPLAIN SELECT biz_id, person_id
|
||||
FROM ccdi_biz_intermediary
|
||||
WHERE person_id IN ('id1', 'id2', 'id3', ...);
|
||||
|
||||
-- 期望结果:type=range, key=uk_person_id
|
||||
```
|
||||
|
||||
### 3. 批量插入优化
|
||||
|
||||
```sql
|
||||
-- 确保批量插入使用优化器优化
|
||||
SET optimizer_switch='batched_key_access=on';
|
||||
```
|
||||
|
||||
## 测试验证
|
||||
|
||||
### 测试数据
|
||||
- 个人中介测试数据:`doc/test-data/intermediary/个人中介黑名单测试数据_1000条_第1批.xlsx`
|
||||
- 实体中介测试数据:`doc/test-data/intermediary/机构中介黑名单测试数据_1000条_第1批.xlsx`
|
||||
|
||||
### 测试方法
|
||||
使用测试脚本验证导入功能和性能:
|
||||
```bash
|
||||
# 运行测试脚本
|
||||
python doc/test-data/intermediary/test_import_performance.py
|
||||
```
|
||||
|
||||
### 验证要点
|
||||
1. ✅ 功能正确性:新增和更新逻辑正确
|
||||
2. ✅ 唯一性校验:重复数据能正确识别
|
||||
3. ✅ 性能提升:导入时间明显缩短
|
||||
4. ✅ 数据完整性:所有数据正确导入
|
||||
5. ✅ 异常处理:错误信息正确返回
|
||||
|
||||
## 相关文件
|
||||
|
||||
### 后端文件
|
||||
- `ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/service/impl/CcdiIntermediaryServiceImpl.java:245-488`
|
||||
|
||||
### 数据库表
|
||||
- `ccdi_biz_intermediary` - 个人中介表
|
||||
- `ccdi_enterprise_base_info` - 实体中介表
|
||||
|
||||
### 测试数据
|
||||
- `doc/test-data/intermediary/` - 测试数据目录
|
||||
|
||||
## 后续优化建议
|
||||
|
||||
### 1. 异步导入
|
||||
对于超大批量数据(10万+),可以考虑:
|
||||
- 使用消息队列异步处理
|
||||
- 提供导入进度查询接口
|
||||
- 导入完成后通知用户
|
||||
|
||||
### 2. 分批导入
|
||||
对于内存受限场景:
|
||||
- 将大数据集分批处理(每批1000条)
|
||||
- 使用事务保证每批数据的原子性
|
||||
- 失败时回滚当前批次
|
||||
|
||||
### 3. 并行处理
|
||||
对于多核CPU环境:
|
||||
- 使用线程池并行处理不同批次
|
||||
- 注意控制并发数,避免数据库连接耗尽
|
||||
|
||||
### 4. 缓存优化
|
||||
对于频繁导入相同数据的场景:
|
||||
- 使用Redis缓存常用数据
|
||||
- 缓存失效策略:TTL或主动更新
|
||||
|
||||
### 5. SQL进一步优化
|
||||
```sql
|
||||
-- 使用INSERT ON DUPLICATE KEY UPDATE(如果业务允许)
|
||||
INSERT INTO ccdi_biz_intermediary (biz_id, person_id, ...)
|
||||
VALUES (?, ?, ...)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
name = VALUES(name),
|
||||
mobile = VALUES(mobile),
|
||||
...;
|
||||
```
|
||||
|
||||
## 总结
|
||||
|
||||
本次优化通过**批量查询 + 内存映射**的方式,成功将唯一性校验的数据库查询次数从N+1次降低到1次,性能提升99%以上。优化后的代码具有更好的可读性、可维护性和扩展性,为后续功能扩展奠定了良好基础。
|
||||
|
||||
优化核心思想:
|
||||
- **批量操作优于循环操作**
|
||||
- **内存计算优于网络计算**
|
||||
- **提前规划优于事后补救**
|
||||
BIN
doc/原型图-上传数据页面.png
Normal file
BIN
doc/原型图-上传数据页面.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 260 KiB |
821
doc/原型图开发设计文档.md
Normal file
821
doc/原型图开发设计文档.md
Normal file
@@ -0,0 +1,821 @@
|
||||
# 纪检初核系统 - 原型图开发设计文档
|
||||
|
||||
## 一、项目概述
|
||||
|
||||
### 1.1 项目背景
|
||||
本项目是一个**纪检初核系统**,用于对银行信贷部门员工进行初步核查,通过分析银行流水、征信报告、员工关系等数据,识别潜在的违规行为和风险。
|
||||
|
||||
### 1.2 项目目标
|
||||
- 支持多维度数据导入(流水、征信、员工关系)
|
||||
- 提供可配置的风险监测模型
|
||||
- 自动识别高风险人员并生成初核提示
|
||||
- 提供专项排查工作台进行深入分析
|
||||
- 支持关系图谱和资金流向分析
|
||||
|
||||
### 1.3 技术栈
|
||||
- **后端**: Spring Boot 3.5.8 + MyBatis 3.0.5 + MySQL 8.2.0
|
||||
- **前端**: Vue 2.6.12 + Element UI 2.15.14
|
||||
- **数据库**: MySQL(表前缀:ccdi_)
|
||||
|
||||
---
|
||||
|
||||
## 二、页面结构与功能分析
|
||||
|
||||
### 2.1 页面导航结构
|
||||
|
||||
```
|
||||
纪检初核系统
|
||||
├── 项目管理
|
||||
│ ├── 项目详情
|
||||
│ ├── 上传数据
|
||||
│ ├── 参数配置
|
||||
│ └── 初核提示
|
||||
├── 初核结果
|
||||
│ ├── 专项排查工作台(高风险)
|
||||
│ ├── 专项排查工作台(中风险)
|
||||
│ └── 专项排查
|
||||
└── 流水明细查询
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.2 页面1:上传数据
|
||||
|
||||
#### 功能描述
|
||||
支持在一个项目中上传多个主体/账户数据,进行汇总/独立分析。
|
||||
|
||||
#### 页面元素
|
||||
| 元素类型 | 元素名称/内容 | 说明 |
|
||||
|---------|--------------|------|
|
||||
| 项目信息 | 项目状态 | 显示项目当前状态(如:已完成) |
|
||||
| | 最后更新时间 | 显示项目最后更新时间 |
|
||||
| 上传模块1 | 流水导入 | 支持Excel、PDF格式文件批量上传 |
|
||||
| | | 占位符:拖拽文件到此处或点击上传 |
|
||||
| | | 支持格式:xlsx, xls, pdf |
|
||||
| 上传模块2 | 已上传流水查询 | 支持HTML格式 |
|
||||
| | | 占位符:拖拽文件到此处或点击上传 |
|
||||
| 上传模块3 | 征信导入 | 支持HTML格式征信报告解析 |
|
||||
| 上传模块4 | 员工家庭关系导入 | Excel模板上传员工家庭关系信息 |
|
||||
| | | 支持格式:xlsx, xls |
|
||||
| 名单库选择 | 高风险人员名单 | 复选框,显示人数(如68人) |
|
||||
| | 历史可疑人员名单 | 复选框,显示人数(如45人) |
|
||||
| | 监管关注名单 | 复选框,显示人数(如32人) |
|
||||
| 数据质量检查 | 数据完整性 | 进度条,显示百分比(如98.5%) |
|
||||
| | 格式一致性 | 进度条,显示百分比(如95.2%) |
|
||||
| | 余额连续性 | 进度条,显示百分比(如92.8%) |
|
||||
| | 检查结果 | 显示发现的问题数量 |
|
||||
| 操作按钮 | 拉取本行信息 | 触发拉取银行内部信息 |
|
||||
| | 生成报告 | 生成初核报告 |
|
||||
|
||||
#### 数据模型
|
||||
```sql
|
||||
-- 项目表
|
||||
CREATE TABLE ccdi_project (
|
||||
project_id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
project_name VARCHAR(200) NOT NULL COMMENT '项目名称',
|
||||
project_status VARCHAR(50) COMMENT '项目状态',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
create_by VARCHAR(100),
|
||||
update_by VARCHAR(100),
|
||||
remark VARCHAR(500)
|
||||
) COMMENT '项目表';
|
||||
|
||||
-- 数据上传记录表
|
||||
CREATE TABLE ccdi_data_upload (
|
||||
upload_id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
project_id BIGINT COMMENT '项目ID',
|
||||
upload_type VARCHAR(50) COMMENT '上传类型:流水/征信/家庭关系',
|
||||
file_name VARCHAR(500) COMMENT '文件名',
|
||||
file_path VARCHAR(1000) COMMENT '文件路径',
|
||||
upload_status VARCHAR(50) COMMENT '上传状态',
|
||||
upload_time DATETIME COMMENT '上传时间',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
create_by VARCHAR(100)
|
||||
) COMMENT '数据上传记录表';
|
||||
|
||||
-- 名单库选择记录表
|
||||
CREATE TABLE ccdi_blacklist_selection (
|
||||
selection_id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
project_id BIGINT COMMENT '项目ID',
|
||||
blacklist_type VARCHAR(50) COMMENT '名单类型:高风险/历史可疑/监管关注',
|
||||
blacklist_id BIGINT COMMENT '名单ID',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
) COMMENT '名单库选择记录表';
|
||||
|
||||
-- 数据质量检查表
|
||||
CREATE TABLE ccdi_data_quality (
|
||||
quality_id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
project_id BIGINT COMMENT '项目ID',
|
||||
check_item VARCHAR(100) COMMENT '检查项:完整性/一致性/连续性',
|
||||
check_result DECIMAL(5,2) COMMENT '检查结果百分比',
|
||||
issue_count INT COMMENT '问题数量',
|
||||
issue_detail TEXT COMMENT '问题详情',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
) COMMENT '数据质量检查表';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.3 页面2:参数配置
|
||||
|
||||
#### 功能描述
|
||||
配置风险监测模型的阈值参数。
|
||||
|
||||
#### 页面元素
|
||||
| 元素类型 | 元素名称/内容 | 说明 |
|
||||
|---------|--------------|------|
|
||||
| 模型名称 | 大额交易模型 | 下拉选择 |
|
||||
| 阈值参数配置表格 | | |
|
||||
| 表格列1 | 监测项 | 如:单笔交易额 |
|
||||
| 表格列2 | 描述 | 如:单笔超过该金额视为大额交易 |
|
||||
| 表格列3 | 阈值设置 | 输入框,如:50000 |
|
||||
| 表格列4 | 单位 | 如:元 |
|
||||
| 操作按钮 | 保存配置 | 保存当前配置 |
|
||||
| | 恢复默认 | 恢复默认值 |
|
||||
| | 一键导出配置 | 导出配置文件 |
|
||||
|
||||
#### 监测项配置
|
||||
1. **单笔交易额**: 50000元
|
||||
2. **累计交易额**: 5000000元
|
||||
3. **大额存现**: 200000元
|
||||
4. **短时多次存现**: 100000元/4小时
|
||||
5. **频繁转账**: 10次/日
|
||||
6. **转账频率**: 1000000元/日
|
||||
|
||||
#### 数据模型
|
||||
```sql
|
||||
-- 风险模型表
|
||||
CREATE TABLE ccdi_risk_model (
|
||||
model_id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
model_name VARCHAR(200) NOT NULL COMMENT '模型名称',
|
||||
model_code VARCHAR(100) COMMENT '模型编码',
|
||||
status VARCHAR(50) DEFAULT 'active' COMMENT '状态',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
create_by VARCHAR(100),
|
||||
update_by VARCHAR(100)
|
||||
) COMMENT '风险模型表';
|
||||
|
||||
-- 模型参数配置表
|
||||
CREATE TABLE ccdi_model_parameter (
|
||||
parameter_id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
model_id BIGINT COMMENT '模型ID',
|
||||
parameter_name VARCHAR(200) COMMENT '参数名称',
|
||||
parameter_code VARCHAR(100) COMMENT '参数编码',
|
||||
parameter_desc VARCHAR(500) COMMENT '参数描述',
|
||||
threshold_value DECIMAL(20,2) COMMENT '阈值',
|
||||
unit VARCHAR(50) COMMENT '单位',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) COMMENT '模型参数配置表';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.4 页面3:初核提示
|
||||
|
||||
#### 功能描述
|
||||
展示初核结果的总体概况,包括人员风险分布、模型触发情况、可疑交易明细等。
|
||||
|
||||
#### 页面元素
|
||||
| 元素类型 | 元素名称/内容 | 说明 |
|
||||
|---------|--------------|------|
|
||||
| 统计卡片 | 总人数 | 显示总人数(如500) |
|
||||
| | 无预警人数 | 显示无预警人数(如432) |
|
||||
| | 低风险 | 显示低风险人数(如38) |
|
||||
| | 中风险 | 显示中风险人数(如20) |
|
||||
| | 高风险 | 显示高风险人数(如10) |
|
||||
| 模型触发情况表格 | 模型名称 | 如:大额交易监测 |
|
||||
| | 触发数 | 触发次数 |
|
||||
| | 触发人员 | 触发人员列表 |
|
||||
| | 操作 | 查看详情 |
|
||||
| 涉疑交易明细表 | 交易时间、可疑人员、关联人、关联员工、关系、摘要/交易类型、交易金额、操作 | |
|
||||
| 高风险人员清单 | 姓名、身份证号、所属部门、风险评分、触发模型数、核心异常点、操作 | 复选框支持批量操作 |
|
||||
| 中风险人员TOP10 | 姓名、身份证号、所属部门、触发模型、触发模型数、操作 | |
|
||||
| 异常账户清单 | 账户号、开户人姓名、开户银行、异常类型、异常发生时间、状态、操作 | |
|
||||
| 涉及违法人员清单表 | 姓名、身份证号、失信被执行人、刑事判决、行政处罚、公安涉案记录、限制高消费、违法信息更新时间、操作 | |
|
||||
| 筛选条件 | 姓名/工号搜索 | 输入框 |
|
||||
| | 部门筛选 | 下拉选择 |
|
||||
| | 风险等级筛选 | 下拉选择(全部/高风险/中风险/低风险) |
|
||||
| | 可疑人员类型筛选 | 下拉选择(全部/名单库命中/模型规则命中) |
|
||||
| | 模型筛选 | 复选框(大额交易/可疑财产/频繁转账等) |
|
||||
| | 模型筛选逻辑 | 单选:同时触发以上模型/触发任意模型 |
|
||||
| 批量操作 | 批量生成报告 | |
|
||||
| | 批量导出证据 | |
|
||||
| | 批量添加到关注列表 | |
|
||||
|
||||
#### 数据模型
|
||||
```sql
|
||||
-- 人员风险评分表
|
||||
CREATE TABLE ccdi_person_risk_score (
|
||||
score_id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
project_id BIGINT COMMENT '项目ID',
|
||||
person_id BIGINT COMMENT '人员ID',
|
||||
person_name VARCHAR(100) COMMENT '姓名',
|
||||
id_card VARCHAR(50) COMMENT '身份证号',
|
||||
department VARCHAR(200) COMMENT '所属部门',
|
||||
risk_level VARCHAR(50) COMMENT '风险等级:高/中/低',
|
||||
risk_score INT COMMENT '风险评分',
|
||||
trigger_model_count INT COMMENT '触发模型数量',
|
||||
core_issue VARCHAR(500) COMMENT '核心异常点',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
) COMMENT '人员风险评分表';
|
||||
|
||||
-- 模型触发记录表
|
||||
CREATE TABLE ccdi_model_trigger_record (
|
||||
trigger_id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
project_id BIGINT COMMENT '项目ID',
|
||||
model_id BIGINT COMMENT '模型ID',
|
||||
model_name VARCHAR(200) COMMENT '模型名称',
|
||||
trigger_count INT COMMENT '触发次数',
|
||||
trigger_persons TEXT COMMENT '触发人员列表',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
) COMMENT '模型触发记录表';
|
||||
|
||||
-- 涉疑交易明细表
|
||||
CREATE TABLE ccdi_suspicious_transaction (
|
||||
transaction_id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
project_id BIGINT COMMENT '项目ID',
|
||||
transaction_time DATETIME COMMENT '交易时间',
|
||||
suspicious_person VARCHAR(100) COMMENT '可疑人员',
|
||||
related_person VARCHAR(100) COMMENT '关联人',
|
||||
related_employee VARCHAR(100) COMMENT '关联员工',
|
||||
relationship VARCHAR(100) COMMENT '关系',
|
||||
transaction_type VARCHAR(200) COMMENT '摘要/交易类型',
|
||||
transaction_amount DECIMAL(20,2) COMMENT '交易金额',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
) COMMENT '涉嫌交易明细表';
|
||||
|
||||
-- 异常账户表
|
||||
CREATE TABLE ccdi_abnormal_account (
|
||||
account_id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
project_id BIGINT COMMENT '项目ID',
|
||||
account_no VARCHAR(100) COMMENT '账户号',
|
||||
account_holder VARCHAR(100) COMMENT '开户人姓名',
|
||||
bank_name VARCHAR(200) COMMENT '开户银行',
|
||||
abnormal_type VARCHAR(100) COMMENT '异常类型',
|
||||
abnormal_time DATETIME COMMENT '异常发生时间',
|
||||
account_status VARCHAR(50) COMMENT '状态',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
) COMMENT '异常账户表';
|
||||
|
||||
-- 违法人员信息表
|
||||
CREATE TABLE ccdi_illegal_person_info (
|
||||
info_id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
person_id BIGINT COMMENT '人员ID',
|
||||
person_name VARCHAR(100) COMMENT '姓名',
|
||||
id_card VARCHAR(50) COMMENT '身份证号',
|
||||
is_dishonesty_executor VARCHAR(10) COMMENT '是否失信被执行人',
|
||||
is_criminal_penalty VARCHAR(10) COMMENT '是否有刑事判决',
|
||||
is_administrative_penalty VARCHAR(10) COMMENT '是否有行政处罚',
|
||||
is_police_case VARCHAR(10) COMMENT '是否有公安涉案记录',
|
||||
is_limit_consumption VARCHAR(10) COMMENT '是否限制高消费',
|
||||
update_time DATETIME COMMENT '违法信息更新时间',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
) COMMENT '违法人员信息表';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.5 页面4:专项排查工作台-高风险
|
||||
|
||||
#### 功能描述
|
||||
针对高风险人员的详细排查工作台。
|
||||
|
||||
#### 页面元素
|
||||
| 元素类型 | 元素名称/内容 | 说明 |
|
||||
|---------|--------------|------|
|
||||
| 排查对象信息 | 排查对象 | 如:李四 |
|
||||
| | 姓名、工号、部门、职级、入职时间、风险等级、所属项目 | |
|
||||
| 触发模型列表 | 触发模型(5个) | |
|
||||
| | 大额交易监测 | 3笔 > 50万 |
|
||||
| | 频繁转账监测 | 1小时25笔 |
|
||||
| | 关联交易排查 | 配偶账户频繁交易 |
|
||||
| | 异常销户监测 | 1个账户突然销户 |
|
||||
| | 疑似赌博交易 | 涉赌商户5笔 |
|
||||
| 初核评分 | 风险评分 | 如:85分(高风险阈值:60分) |
|
||||
| 异常详情-大额交易 | 交易时间、本方账号/主体、对方名称/账户、摘要/交易类型、交易金额、标记状态 | 标记状态下拉:标记正常/标记可疑/确认异常 |
|
||||
| 异常详情-频繁转账 | 时间段、总笔数、总金额、主要对手、模式特征、核查建议 | |
|
||||
| 异常详情-关联交易 | 关联人、关联账户、交易特征、异常点、需核实 | |
|
||||
| 排查工具箱 | 查看完整流水、查看征信报告、查看资产信息、关系图谱分析、资金流向分析、导出所有证据、添加到案例库 | |
|
||||
| 排查进度标签页 | 异常明细、资产分析、征信摘要、关系人图谱、资金流向 | |
|
||||
| 操作按钮 | 生成报告、生成排查报告、标记为案例、关注 | |
|
||||
|
||||
#### 数据模型
|
||||
```sql
|
||||
-- 排查对象表
|
||||
CREATE TABLE ccdi_investigation_object (
|
||||
object_id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
project_id BIGINT COMMENT '项目ID',
|
||||
person_id BIGINT COMMENT '人员ID',
|
||||
person_name VARCHAR(100) COMMENT '姓名',
|
||||
employee_no VARCHAR(100) COMMENT '工号',
|
||||
department VARCHAR(200) COMMENT '部门',
|
||||
position_level VARCHAR(100) COMMENT '职级',
|
||||
entry_date DATE COMMENT '入职时间',
|
||||
risk_level VARCHAR(50) COMMENT '风险等级',
|
||||
risk_score INT COMMENT '风险评分',
|
||||
investigation_status VARCHAR(50) COMMENT '排查状态',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) COMMENT '排查对象表';
|
||||
|
||||
-- 排查触发模型表
|
||||
CREATE TABLE ccdi_investigation_trigger_model (
|
||||
trigger_model_id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
object_id BIGINT COMMENT '排查对象ID',
|
||||
model_id BIGINT COMMENT '模型ID',
|
||||
model_name VARCHAR(200) COMMENT '模型名称',
|
||||
trigger_desc VARCHAR(500) COMMENT '触发描述',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
) COMMENT '排查触发模型表';
|
||||
|
||||
-- 异常交易明细表
|
||||
CREATE TABLE ccdi_abnormal_transaction_detail (
|
||||
detail_id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
object_id BIGINT COMMENT '排查对象ID',
|
||||
transaction_time DATETIME COMMENT '交易时间',
|
||||
own_account VARCHAR(200) COMMENT '本方账号/主体',
|
||||
counterparty VARCHAR(200) COMMENT '对方名称/账户',
|
||||
transaction_type VARCHAR(200) COMMENT '摘要/交易类型',
|
||||
transaction_amount DECIMAL(20,2) COMMENT '交易金额',
|
||||
mark_status VARCHAR(50) COMMENT '标记状态:正常/可疑/异常',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
) COMMENT '异常交易明细表';
|
||||
|
||||
-- 排查进度表
|
||||
CREATE TABLE ccdi_investigation_progress (
|
||||
progress_id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
object_id BIGINT COMMENT '排查对象ID',
|
||||
progress_type VARCHAR(100) COMMENT '进度类型:流水分析/征信分析/资产比对/人工核实',
|
||||
progress_status VARCHAR(50) COMMENT '进度状态',
|
||||
complete_time DATETIME COMMENT '完成时间',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
) COMMENT '排查进度表';
|
||||
|
||||
-- 关注列表表
|
||||
CREATE TABLE ccdi_attention_list (
|
||||
attention_id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
object_id BIGINT COMMENT '排查对象ID',
|
||||
person_id BIGINT COMMENT '人员ID',
|
||||
attention_type VARCHAR(50) COMMENT '关注类型',
|
||||
create_by VARCHAR(100) COMMENT '创建人',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
) COMMENT '关注列表表';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.6 页面5:专项排查
|
||||
|
||||
#### 功能描述
|
||||
员工详查分析功能,包括资产收入分析、图谱分析、采购查询等。
|
||||
|
||||
#### 页面元素
|
||||
| 元素类型 | 元素名称/内容 | 说明 |
|
||||
|---------|--------------|------|
|
||||
| 查询条件 | 身份证号 | 输入框 |
|
||||
| | 开始日期、结束日期 | 日期选择器 |
|
||||
| | 查询、重置 | 按钮 |
|
||||
| 详查结果 | 详查结果描述 | 如:收入+负债远低于资产 |
|
||||
| 基本信息 | 姓名、身份证号、资产/收入比 | |
|
||||
| 收入分析 | 工资收入、其他收入 | 显示金额和百分比 |
|
||||
| 本人资产分析 | 房产、存款、其他 | 显示金额和百分比 |
|
||||
| 配偶资产分析 | 房产、车产、其他 | 显示金额和百分比 |
|
||||
| 负债分析 | 房贷、其他贷款 | 显示金额和百分比 |
|
||||
| 汇总信息 | 本人+配偶资产合计、总负债 | |
|
||||
| 图谱分析标签页 | 关系人图谱、资金流图谱、实控账户图谱 | |
|
||||
| 关系人图谱 | 姓名搜索框、生成图谱按钮 | |
|
||||
| | 可视化图谱 | 显示配偶、对外投资、股东、高管关联等 |
|
||||
| | 操作按钮 | 展开所有关联、仅显示直接关联、导出图谱、筛选、刷新 |
|
||||
| 采购查询表格 | 序号、采购事项名称、交易日期、采购金额、供应商名称、对方账号、联系人、关联员工 | |
|
||||
| 扩展查询标签页 | 采购查询、人员调动查询、招聘查询 | |
|
||||
| 采购查询条件 | 采购时间范围、关联员工 | |
|
||||
|
||||
#### 数据模型
|
||||
```sql
|
||||
-- 员工资产分析表
|
||||
CREATE TABLE ccdi_employee_asset_analysis (
|
||||
analysis_id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
person_id BIGINT COMMENT '人员ID',
|
||||
person_name VARCHAR(100) COMMENT '姓名',
|
||||
id_card VARCHAR(50) COMMENT '身份证号',
|
||||
asset_income_ratio DECIMAL(10,2) COMMENT '资产/收入比',
|
||||
annual_income DECIMAL(20,2) COMMENT '年收入',
|
||||
own_asset DECIMAL(20,2) COMMENT '本人资产',
|
||||
spouse_asset DECIMAL(20,2) COMMENT '配偶资产',
|
||||
total_asset DECIMAL(20,2) COMMENT '本人+配偶资产合计',
|
||||
total_liability DECIMAL(20,2) COMMENT '总负债',
|
||||
income_salary DECIMAL(20,2) COMMENT '工资收入',
|
||||
income_other DECIMAL(20,2) COMMENT '其他收入',
|
||||
asset_house DECIMAL(20,2) COMMENT '房产',
|
||||
asset_deposit DECIMAL(20,2) COMMENT '存款',
|
||||
asset_other DECIMAL(20,2) COMMENT '其他',
|
||||
liability_mortgage DECIMAL(20,2) COMMENT '房贷',
|
||||
liability_loan DECIMAL(20,2) COMMENT '其他贷款',
|
||||
spouse_asset_house DECIMAL(20,2) COMMENT '配偶房产',
|
||||
spouse_asset_car DECIMAL(20,2) COMMENT '配偶车产',
|
||||
spouse_asset_other DECIMAL(20,2) COMMENT '配偶其他',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
) COMMENT '员工资产分析表';
|
||||
|
||||
-- 关系人图谱表
|
||||
CREATE TABLE ccdi_relationship_graph (
|
||||
graph_id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
person_id BIGINT COMMENT '人员ID',
|
||||
related_person_name VARCHAR(100) COMMENT '关联人姓名',
|
||||
relationship_type VARCHAR(100) COMMENT '关系类型:配偶/对外投资/股东/高管关联',
|
||||
related_entity_name VARCHAR(200) COMMENT '关联实体名称',
|
||||
share_ratio DECIMAL(5,2) COMMENT '持股比例',
|
||||
position VARCHAR(200) COMMENT '职位',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
) COMMENT '关系人图谱表';
|
||||
|
||||
-- 采购查询记录表
|
||||
CREATE TABLE ccdi_purchase_record (
|
||||
purchase_id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
purchase_name VARCHAR(500) COMMENT '采购事项名称',
|
||||
transaction_date DATE COMMENT '交易日期',
|
||||
purchase_amount DECIMAL(20,2) COMMENT '采购金额',
|
||||
supplier_name VARCHAR(500) COMMENT '供应商名称',
|
||||
supplier_account VARCHAR(200) COMMENT '对方账号',
|
||||
contact_person VARCHAR(100) COMMENT '联系人',
|
||||
related_employee VARCHAR(100) COMMENT '关联员工',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
) COMMENT '采购查询记录表';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.7 页面6:专项排查工作台-中风险
|
||||
|
||||
#### 功能描述
|
||||
针对中风险人员的排查工作台,功能与高风险工作台类似,但风险等级不同。
|
||||
|
||||
#### 页面元素
|
||||
与高风险工作台结构相同,主要区别:
|
||||
- 风险等级显示为"中风险"
|
||||
- 初核评分可能较低
|
||||
- 触发模型数量可能较少
|
||||
|
||||
数据模型与高风险工作台共用。
|
||||
|
||||
---
|
||||
|
||||
### 2.8 页面7:流水明细查询
|
||||
|
||||
#### 功能描述
|
||||
查询和筛选银行流水明细。
|
||||
|
||||
#### 页面元素
|
||||
| 元素类型 | 元素名称/内容 | 说明 |
|
||||
|---------|--------------|------|
|
||||
| 筛选条件 | 交易时间范围 | 开始日期、结束日期 |
|
||||
| | 对方名称 | 输入框,支持空值筛选 |
|
||||
| | 摘要 | 输入框,支持空值筛选 |
|
||||
| | 分类 | 多选下拉 |
|
||||
| | 本方主体 | 多选下拉 |
|
||||
| | 本方银行 | 多选下拉 |
|
||||
| | 本方账户 | 多选下拉 |
|
||||
| | 交易金额 | 范围输入(最小~最大) |
|
||||
| | 对方账户 | 输入框,支持空值筛选 |
|
||||
| | 交易类型 | 输入框,支持空值筛选 |
|
||||
| | 剔除关联方与本方 | 复选框 |
|
||||
| | 查询、重置 | 按钮 |
|
||||
| 流水类型切换 | 全部、流入、流出 | 单选或Tab切换 |
|
||||
| 流水明细表格 | 交易时间、本行账户/主体、对方名称/账户、摘要/交易类型、交易金额、分类、操作 | 支持复选框 |
|
||||
| 表格操作 | 修改分类 | 下拉或弹窗 |
|
||||
| 底部操作栏 | 已筛选X笔流水,已选中X笔流水 | |
|
||||
| | 导出流水 | |
|
||||
| | 加入分析 | |
|
||||
| 标签页 | 流水、对手方 | |
|
||||
|
||||
#### 数据模型
|
||||
```sql
|
||||
-- 流水明细表
|
||||
CREATE TABLE ccdi_transaction_detail (
|
||||
detail_id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
project_id BIGINT COMMENT '项目ID',
|
||||
transaction_time DATETIME COMMENT '交易时间',
|
||||
own_account VARCHAR(200) COMMENT '本方账户/主体',
|
||||
own_bank VARCHAR(200) COMMENT '本方银行',
|
||||
counterparty_name VARCHAR(500) COMMENT '对方名称/账户',
|
||||
counterparty_account VARCHAR(200) COMMENT '对方账户',
|
||||
transaction_summary VARCHAR(500) COMMENT '摘要',
|
||||
transaction_type VARCHAR(200) COMMENT '交易类型',
|
||||
transaction_amount DECIMAL(20,2) COMMENT '交易金额',
|
||||
transaction_direction VARCHAR(50) COMMENT '交易方向:流入/流出',
|
||||
category VARCHAR(200) COMMENT '分类',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
) COMMENT '流水明细表';
|
||||
|
||||
-- 流水分类表
|
||||
CREATE TABLE ccdi_transaction_category (
|
||||
category_id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
category_code VARCHAR(100) COMMENT '分类编码',
|
||||
category_name VARCHAR(200) COMMENT '分类名称',
|
||||
parent_id BIGINT COMMENT '父分类ID',
|
||||
sort_order INT COMMENT '排序',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
) COMMENT '流水分类表';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、模块划分与开发建议
|
||||
|
||||
### 3.1 后端模块划分
|
||||
|
||||
```
|
||||
ruoyi-ccdi/ (新建模块)
|
||||
├── controller/
|
||||
│ ├── CcdiProjectController.java # 项目管理
|
||||
│ ├── CcdiDataUploadController.java # 数据上传
|
||||
│ ├── CcdiModelConfigController.java # 模型配置
|
||||
│ ├── CcdiPreliminaryCheckController.java # 初核提示
|
||||
│ ├── CcdiInvestigationController.java # 专项排查工作台
|
||||
│ ├── CcdiSpecialCheckController.java # 专项排查
|
||||
│ └── CcdiTransactionController.java # 流水明细查询
|
||||
├── service/
|
||||
│ ├── ICcdiProjectService.java
|
||||
│ ├── ICcdiDataUploadService.java
|
||||
│ ├── ICcdiModelConfigService.java
|
||||
│ ├── ICcdiPreliminaryCheckService.java
|
||||
│ ├── ICcdiInvestigationService.java
|
||||
│ ├── ICcdiSpecialCheckService.java
|
||||
│ └── ICcdiTransactionService.java
|
||||
├── mapper/
|
||||
│ ├── CcdiProjectMapper.java
|
||||
│ ├── CcdiDataUploadMapper.java
|
||||
│ ├── CcdiModelConfigMapper.java
|
||||
│ ├── CcdiPreliminaryCheckMapper.java
|
||||
│ ├── CcdiInvestigationMapper.java
|
||||
│ ├── CcdiSpecialCheckMapper.java
|
||||
│ └── CcdiTransactionMapper.java
|
||||
├── domain/
|
||||
│ ├── CcdiProject.java
|
||||
│ ├── CcdiDataUpload.java
|
||||
│ ├── CcdiModelConfig.java
|
||||
│ ├── CcdiPersonRiskScore.java
|
||||
│ ├── CcdiInvestigationObject.java
|
||||
│ └── ...
|
||||
├── dto/
|
||||
│ ├── CcdiProjectQueryDTO.java
|
||||
│ ├── CcdiDataUploadDTO.java
|
||||
│ ├── CcdiModelConfigDTO.java
|
||||
│ └── ...
|
||||
└── vo/
|
||||
├── CcdiProjectVO.java
|
||||
├── CcdiPreliminaryCheckVO.java
|
||||
├── CcdiInvestigationVO.java
|
||||
└── ...
|
||||
```
|
||||
|
||||
### 3.2 前端模块划分
|
||||
|
||||
```
|
||||
ruoyi-ui/src/views/ccdi/
|
||||
├── project/
|
||||
│ ├── index.vue # 项目列表
|
||||
│ ├── detail.vue # 项目详情
|
||||
│ ├── upload.vue # 上传数据
|
||||
│ └── components/
|
||||
│ ├── UploadCard.vue # 上传卡片组件
|
||||
│ ├── QualityCheck.vue # 数据质量检查组件
|
||||
│ └── BlacklistSelect.vue # 名单库选择组件
|
||||
├── model/
|
||||
│ ├── config.vue # 参数配置
|
||||
│ └── components/
|
||||
│ └── ModelConfigTable.vue # 模型配置表格组件
|
||||
├── preliminary/
|
||||
│ ├── index.vue # 初核提示
|
||||
│ └── components/
|
||||
│ ├── RiskStatistics.vue # 风险统计卡片
|
||||
│ ├── ModelTriggerTable.vue # 模型触发表格
|
||||
│ ├── SuspiciousTransactionTable.vue # 涉疑交易表格
|
||||
│ └── PersonRiskList.vue # 人员风险列表
|
||||
├── investigation/
|
||||
│ ├── high-risk.vue # 高风险工作台
|
||||
│ ├── mid-risk.vue # 中风险工作台
|
||||
│ └── components/
|
||||
│ ├── ObjectInfo.vue # 排查对象信息
|
||||
│ ├── AbnormalTransaction.vue # 异常交易明细
|
||||
│ ├── InvestigationTools.vue # 排查工具箱
|
||||
│ └── InvestigationTabs.vue # 排查进度标签页
|
||||
├── special/
|
||||
│ ├── index.vue # 专项排查
|
||||
│ └── components/
|
||||
│ ├── AssetAnalysis.vue # 资产分析
|
||||
│ ├── RelationshipGraph.vue # 关系人图谱
|
||||
│ └── PurchaseTable.vue # 采购查询表格
|
||||
└── transaction/
|
||||
└── index.vue # 流水明细查询
|
||||
```
|
||||
|
||||
### 3.3 开发顺序建议
|
||||
|
||||
1. **第一阶段:基础数据管理**
|
||||
- 项目管理(创建、查询、更新)
|
||||
- 数据上传功能
|
||||
- 数据质量检查
|
||||
|
||||
2. **第二阶段:模型配置**
|
||||
- 风险模型配置
|
||||
- 模型参数配置
|
||||
- 模型触发规则
|
||||
|
||||
3. **第三阶段:初核分析**
|
||||
- 初核提示页面
|
||||
- 风险评分计算
|
||||
- 人员风险分类
|
||||
|
||||
4. **第四阶段:排查工作台**
|
||||
- 高风险工作台
|
||||
- 中风险工作台
|
||||
- 排查进度跟踪
|
||||
|
||||
5. **第五阶段:专项排查**
|
||||
- 员工详查分析
|
||||
- 资产收入分析
|
||||
- 关系图谱分析
|
||||
- 采购查询
|
||||
|
||||
6. **第六阶段:流水查询**
|
||||
- 流水明细查询
|
||||
- 多维度筛选
|
||||
- 流水分类管理
|
||||
|
||||
---
|
||||
|
||||
## 四、关键技术要点
|
||||
|
||||
### 4.1 文件上传处理
|
||||
- 支持Excel、PDF、HTML多种格式
|
||||
- 需要实现文件解析功能
|
||||
- 大文件上传需要分片处理
|
||||
- 上传进度显示
|
||||
|
||||
### 4.2 数据质量检查
|
||||
- 数据完整性检查
|
||||
- 格式一致性检查
|
||||
- 余额连续性检查
|
||||
- 异常数据识别
|
||||
|
||||
### 4.3 风险评分模型
|
||||
- 可配置的风险模型
|
||||
- 可配置的阈值参数
|
||||
- 多模型触发计算
|
||||
- 风险等级分类
|
||||
|
||||
### 4.4 图谱可视化
|
||||
- 关系人图谱展示
|
||||
- 资金流向图谱
|
||||
- 实控账户图谱
|
||||
- 图谱交互操作
|
||||
|
||||
### 4.5 数据导出
|
||||
- 支持多种导出格式
|
||||
- 大数据量导出优化
|
||||
- 批量导出功能
|
||||
|
||||
---
|
||||
|
||||
## 五、接口设计建议
|
||||
|
||||
### 5.1 项目管理接口
|
||||
|
||||
```
|
||||
POST /ccdi/project/list # 项目列表查询
|
||||
GET /ccdi/project/{id} # 项目详情
|
||||
POST /ccdi/project # 新增项目
|
||||
PUT /ccdi/project # 更新项目
|
||||
DELETE /ccdi/project/{id} # 删除项目
|
||||
```
|
||||
|
||||
### 5.2 数据上传接口
|
||||
|
||||
```
|
||||
POST /ccdi/upload/transaction # 上传流水文件
|
||||
POST /ccdi/upload/credit # 上传征信文件
|
||||
POST /ccdi/upload/relation # 上传家庭关系文件
|
||||
GET /ccdi/upload/progress/{id} # 查询上传进度
|
||||
POST /ccdi/upload/quality/check # 数据质量检查
|
||||
```
|
||||
|
||||
### 5.3 初核分析接口
|
||||
|
||||
```
|
||||
GET /ccdi/preliminary/statistics # 获取统计数据
|
||||
GET /ccdi/preliminary/model/trigger # 模型触发情况
|
||||
GET /ccdi/preliminary/transaction # 涉疑交易明细
|
||||
GET /ccdi/preliminary/person/list # 人员风险列表
|
||||
GET /ccdi/preliminary/abnormal/account # 异常账户列表
|
||||
POST /ccdi/preliminary/batch/report # 批量生成报告
|
||||
```
|
||||
|
||||
### 5.4 排查工作台接口
|
||||
|
||||
```
|
||||
GET /ccdi/investigation/object/{id} # 获取排查对象详情
|
||||
GET /ccdi/investigation/abnormal/{id} # 获取异常交易详情
|
||||
GET /ccdi/investigation/progress/{id} # 获取排查进度
|
||||
PUT /ccdi/investigation/mark/status # 标记状态
|
||||
POST /ccdi/investigation/report # 生成排查报告
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、数据库表汇总
|
||||
|
||||
| 序号 | 表名 | 说明 |
|
||||
|------|------|------|
|
||||
| 1 | ccdi_project | 项目表 |
|
||||
| 2 | ccdi_data_upload | 数据上传记录表 |
|
||||
| 3 | ccdi_blacklist_selection | 名单库选择记录表 |
|
||||
| 4 | ccdi_data_quality | 数据质量检查表 |
|
||||
| 5 | ccdi_risk_model | 风险模型表 |
|
||||
| 6 | ccdi_model_parameter | 模型参数配置表 |
|
||||
| 7 | ccdi_person_risk_score | 人员风险评分表 |
|
||||
| 8 | ccdi_model_trigger_record | 模型触发记录表 |
|
||||
| 9 | ccdi_suspicious_transaction | 涉嫌交易明细表 |
|
||||
| 10 | ccdi_abnormal_account | 异常账户表 |
|
||||
| 11 | ccdi_illegal_person_info | 违法人员信息表 |
|
||||
| 12 | ccdi_investigation_object | 排查对象表 |
|
||||
| 13 | ccdi_investigation_trigger_model | 排查触发模型表 |
|
||||
| 14 | ccdi_abnormal_transaction_detail | 异常交易明细表 |
|
||||
| 15 | ccdi_investigation_progress | 排查进度表 |
|
||||
| 16 | ccdi_attention_list | 关注列表表 |
|
||||
| 17 | ccdi_employee_asset_analysis | 员工资产分析表 |
|
||||
| 18 | ccdi_relationship_graph | 关系人图谱表 |
|
||||
| 19 | ccdi_purchase_record | 采购查询记录表 |
|
||||
| 20 | ccdi_transaction_detail | 流水明细表 |
|
||||
| 21 | ccdi_transaction_category | 流水分类表 |
|
||||
|
||||
---
|
||||
|
||||
## 七、前端组件建议
|
||||
|
||||
### 7.1 通用组件
|
||||
|
||||
```javascript
|
||||
// components/ccdi/
|
||||
├── UploadCard.vue # 文件上传卡片
|
||||
├── RiskStatisticsCard.vue # 风险统计卡片
|
||||
├── QualityProgressBar.vue # 质量检查进度条
|
||||
├── ModelTriggerTable.vue # 模型触发表格
|
||||
├── PersonRiskList.vue # 人员风险列表
|
||||
├── TransactionTable.vue # 交易明细表格
|
||||
├── RelationshipGraph.vue # 关系图谱组件
|
||||
└── FilterPanel.vue # 筛选面板组件
|
||||
```
|
||||
|
||||
### 7.2 图表组件
|
||||
|
||||
```javascript
|
||||
// 使用ECharts实现
|
||||
├── RiskDistributionChart.vue # 风险分布图
|
||||
├── ModelTriggerChart.vue # 模型触发图表
|
||||
├── AssetAnalysisChart.vue # 资产分析图表
|
||||
└── RelationshipGraphChart.vue # 关系图谱
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 八、开发注意事项
|
||||
|
||||
### 8.1 权限控制
|
||||
- 项目级权限控制
|
||||
- 数据访问权限
|
||||
- 敏感信息脱敏
|
||||
|
||||
### 8.2 性能优化
|
||||
- 大数据量查询分页
|
||||
- 索引优化
|
||||
- 缓存策略
|
||||
|
||||
### 8.3 数据安全
|
||||
- 敏感数据加密
|
||||
- 操作日志记录
|
||||
- 数据备份
|
||||
|
||||
### 8.4 用户体验
|
||||
- 加载状态提示
|
||||
- 操作反馈
|
||||
- 错误提示
|
||||
|
||||
---
|
||||
|
||||
## 九、后续扩展方向
|
||||
|
||||
1. **智能分析**:引入机器学习算法,提高风险识别准确率
|
||||
2. **移动端适配**:开发移动端应用,支持移动办公
|
||||
3. **报表中心**:自定义报表功能
|
||||
4. **预警机制**:实时预警通知
|
||||
5. **案例库管理**:典型案例沉淀和复用
|
||||
|
||||
---
|
||||
|
||||
**文档版本**: v1.0
|
||||
**创建时间**: 2025-01-30
|
||||
**最后更新**: 2025-01-30
|
||||
326
doc/后端枚举字段说明.md
Normal file
326
doc/后端枚举字段说明.md
Normal file
@@ -0,0 +1,326 @@
|
||||
# 后端枚举字段说明
|
||||
|
||||
## 概述
|
||||
|
||||
后端只返回枚举代码值,不返回枚举名称。前端需要根据代码值进行转换显示。
|
||||
|
||||
---
|
||||
|
||||
## API 返回的枚举字段
|
||||
|
||||
### 1. 中介类型 (intermediaryType)
|
||||
|
||||
| 代码值 | 说明 |
|
||||
|--------|------|
|
||||
| `1` | 个人中介 |
|
||||
| `2` | 机构中介 |
|
||||
|
||||
**前端转换示例:**
|
||||
```javascript
|
||||
const getIntermediaryTypeName = (type) => {
|
||||
const map = {
|
||||
'1': '个人',
|
||||
'2': '机构'
|
||||
}
|
||||
return map[type] || '未知'
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 状态 (status)
|
||||
|
||||
| 代码值 | 说明 |
|
||||
|--------|------|
|
||||
| `0` | 正常 |
|
||||
| `1` | 停用 |
|
||||
|
||||
**前端转换示例:**
|
||||
```javascript
|
||||
const getStatusName = (status) => {
|
||||
const map = {
|
||||
'0': '正常',
|
||||
'1': '停用'
|
||||
}
|
||||
return map[status] || '未知'
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 数据来源 (dataSource / date_source)
|
||||
|
||||
| 代码值 | 说明 |
|
||||
|--------|------|
|
||||
| `MANUAL` | 手动录入 |
|
||||
| `IMPORT` | 批量导入 |
|
||||
| `SYSTEM` | 系统同步 |
|
||||
| `API` | 接口获取 |
|
||||
|
||||
**前端转换示例:**
|
||||
```javascript
|
||||
const getDataSourceName = (source) => {
|
||||
const map = {
|
||||
'MANUAL': '手动录入',
|
||||
'IMPORT': '批量导入',
|
||||
'SYSTEM': '系统同步',
|
||||
'API': '接口获取'
|
||||
}
|
||||
return map[source] || '未知'
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 性别 (indivGender) - 个人中介
|
||||
|
||||
| 代码值 | 说明 |
|
||||
|--------|------|
|
||||
| `M` | 男 |
|
||||
| `F` | 女 |
|
||||
| `O` | 其他 |
|
||||
|
||||
**前端转换示例:**
|
||||
```javascript
|
||||
const getGenderName = (gender) => {
|
||||
const map = {
|
||||
'M': '男',
|
||||
'F': '女',
|
||||
'O': '其他'
|
||||
}
|
||||
return map[gender] || '未知'
|
||||
}
|
||||
```
|
||||
|
||||
### 5. 证件类型 (indivCertType)
|
||||
|
||||
常用证件类型代码:
|
||||
- `身份证` - 身份证
|
||||
- `护照` - 护照
|
||||
- `港澳通行证` - 港澳通行证
|
||||
- `台湾通行证` - 台湾通行证
|
||||
|
||||
---
|
||||
|
||||
## API 返回数据示例
|
||||
|
||||
### 列表查询响应
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "查询成功",
|
||||
"rows": [
|
||||
{
|
||||
"intermediaryId": 1,
|
||||
"name": "张三",
|
||||
"certificateNo": "110101199001011234",
|
||||
"intermediaryType": "1",
|
||||
"status": "0",
|
||||
"dataSource": "MANUAL",
|
||||
"createTime": "2026-02-04 10:00:00",
|
||||
"updateTime": "2026-02-04 10:00:00"
|
||||
},
|
||||
{
|
||||
"intermediaryId": 0,
|
||||
"name": "测试机构有限公司",
|
||||
"certificateNo": "91110000123456789X",
|
||||
"intermediaryType": "2",
|
||||
"status": "0",
|
||||
"dataSource": "MANUAL",
|
||||
"createTime": "2026-02-04 10:00:00",
|
||||
"updateTime": "2026-02-04 10:00:00"
|
||||
}
|
||||
],
|
||||
"total": 2
|
||||
}
|
||||
```
|
||||
|
||||
### 个人中介详情响应
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": {
|
||||
"intermediaryId": 1,
|
||||
"name": "张三",
|
||||
"certificateNo": "110101199001011234",
|
||||
"intermediaryType": "1",
|
||||
"status": "0",
|
||||
"dataSource": "MANUAL",
|
||||
"remark": "测试数据",
|
||||
"indivType": "中介",
|
||||
"indivSubType": "本人",
|
||||
"indivGender": "M",
|
||||
"indivCertType": "身份证",
|
||||
"indivPhone": "13800138000",
|
||||
"indivWechat": "test_wx001",
|
||||
"indivAddress": "北京市朝阳区测试路123号",
|
||||
"indivCompany": "测试公司",
|
||||
"indivPosition": "测试员",
|
||||
"createTime": "2026-02-04 10:00:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 机构中介详情响应
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": {
|
||||
"intermediaryId": 0,
|
||||
"name": "测试机构有限公司",
|
||||
"certificateNo": "91110000123456789X",
|
||||
"intermediaryType": "2",
|
||||
"status": "0",
|
||||
"dataSource": "MANUAL",
|
||||
"remark": "机构中介测试数据",
|
||||
"corpCreditCode": "91110000123456789X",
|
||||
"corpType": "有限责任公司",
|
||||
"corpNature": "民营企业",
|
||||
"corpIndustryCategory": "制造业",
|
||||
"corpIndustry": "通用设备制造业",
|
||||
"corpEstablishDate": "2020-01-01",
|
||||
"corpAddress": "北京市海淀区测试大街456号",
|
||||
"corpLegalRep": "李四",
|
||||
"corpLegalCertType": "身份证",
|
||||
"corpLegalCertNo": "110101198001011234",
|
||||
"createTime": "2026-02-04 10:00:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 前端 Vue 组件示例
|
||||
|
||||
### 枚举转换工具函数
|
||||
|
||||
```javascript
|
||||
// utils/enums.js
|
||||
export const IntermediaryType = {
|
||||
PERSON: '1',
|
||||
ENTITY: '2',
|
||||
getName: (type) => {
|
||||
const map = {
|
||||
'1': '个人',
|
||||
'2': '机构'
|
||||
}
|
||||
return map[type] || '未知'
|
||||
}
|
||||
}
|
||||
|
||||
export const IntermediaryStatus = {
|
||||
NORMAL: '0',
|
||||
DISABLED: '1',
|
||||
getName: (status) => {
|
||||
const map = {
|
||||
'0': '正常',
|
||||
'1': '停用'
|
||||
}
|
||||
return map[status] || '未知'
|
||||
}
|
||||
}
|
||||
|
||||
export const DataSource = {
|
||||
MANUAL: 'MANUAL',
|
||||
IMPORT: 'IMPORT',
|
||||
SYSTEM: 'SYSTEM',
|
||||
API: 'API',
|
||||
getName: (source) => {
|
||||
const map = {
|
||||
'MANUAL': '手动录入',
|
||||
'IMPORT': '批量导入',
|
||||
'SYSTEM': '系统同步',
|
||||
'API': '接口获取'
|
||||
}
|
||||
return map[source] || '未知'
|
||||
}
|
||||
}
|
||||
|
||||
export const Gender = {
|
||||
MALE: 'M',
|
||||
FEMALE: 'F',
|
||||
OTHER: 'O',
|
||||
getName: (gender) => {
|
||||
const map = {
|
||||
'M': '男',
|
||||
'F': '女',
|
||||
'O': '其他'
|
||||
}
|
||||
return map[gender] || '未知'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 表格列使用枚举
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<el-table :data="tableData">
|
||||
<el-table-column prop="name" label="姓名" />
|
||||
|
||||
<el-table-column prop="intermediaryType" label="中介类型">
|
||||
<template #default="{ row }">
|
||||
{{ IntermediaryType.getName(row.intermediaryType) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="status" label="状态">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.status === '0' ? 'success' : 'danger'">
|
||||
{{ IntermediaryStatus.getName(row.status) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="dataSource" label="数据来源">
|
||||
<template #default="{ row }">
|
||||
{{ DataSource.getName(row.dataSource) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { IntermediaryType, IntermediaryStatus, DataSource } from '@/utils/enums'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
IntermediaryType,
|
||||
IntermediaryStatus,
|
||||
DataSource,
|
||||
tableData: []
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
### 表单下拉框使用枚举
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<el-form :model="form">
|
||||
<el-form-item label="中介类型" prop="intermediaryType">
|
||||
<el-select v-model="form.intermediaryType" placeholder="请选择中介类型">
|
||||
<el-option label="个人" value="1" />
|
||||
<el-option label="机构" value="2" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-radio-group v-model="form.status">
|
||||
<el-radio label="0">正常</el-radio>
|
||||
<el-radio label="1">停用</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **后端只返回代码值**,前端负责转换为显示名称
|
||||
2. **前端下拉框的 value 应该使用代码值**(如 '1', '2', '0' 等)
|
||||
3. **建议在前端统一维护枚举映射关系**,避免硬编码
|
||||
4. **新增枚举值时**,只需要前端更新映射表即可,后端无需修改
|
||||
5. **国际化支持**:前端可以根据语言切换返回不同的名称
|
||||
@@ -25,7 +25,7 @@ spring:
|
||||
druid:
|
||||
# 主库数据源
|
||||
master:
|
||||
url: jdbc:mysql://116.62.17.81:3306/discipline-prelim-check?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||
url: jdbc:mysql://116.62.17.81:3306/ccdi?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||
username: root
|
||||
password: Kfcx@1234
|
||||
# 从库数据源
|
||||
|
||||
@@ -17,7 +17,7 @@ import java.util.List;
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Tag(name = "DPC枚举接口", description = "中介黑名单相关枚举选项接口")
|
||||
@Tag(name = "枚举接口", description = "中介黑名单相关枚举选项接口")
|
||||
@RestController
|
||||
@RequestMapping("/ccdi/enum")
|
||||
public class CcdiEnumController {
|
||||
@@ -35,19 +35,6 @@ public class CcdiEnumController {
|
||||
return AjaxResult.success(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取人员子类型选项
|
||||
*/
|
||||
@Operation(summary = "获取人员子类型选项")
|
||||
@GetMapping("/indivSubType")
|
||||
public AjaxResult getIndivSubTypeOptions() {
|
||||
List<EnumOptionVO> options = new ArrayList<>();
|
||||
for (IndivSubType type : IndivSubType.values()) {
|
||||
options.add(new EnumOptionVO(type.getCode(), type.getDesc()));
|
||||
}
|
||||
return AjaxResult.success(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取性别选项
|
||||
*/
|
||||
|
||||
@@ -1,202 +0,0 @@
|
||||
package com.ruoyi.ccdi.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.ccdi.domain.CcdiIntermediaryBlacklist;
|
||||
import com.ruoyi.ccdi.domain.dto.*;
|
||||
import com.ruoyi.ccdi.domain.excel.CcdiIntermediaryBlacklistExcel;
|
||||
import com.ruoyi.ccdi.domain.excel.CcdiIntermediaryEntityExcel;
|
||||
import com.ruoyi.ccdi.domain.excel.CcdiIntermediaryPersonExcel;
|
||||
import com.ruoyi.ccdi.domain.vo.CcdiIntermediaryBlacklistVO;
|
||||
import com.ruoyi.ccdi.service.ICcdiIntermediaryBlacklistService;
|
||||
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-01-27
|
||||
*/
|
||||
@Tag(name = "中介黑名单管理")
|
||||
@RestController
|
||||
@RequestMapping("/ccdi/intermediary")
|
||||
public class CcdiIntermediaryBlacklistController extends BaseController {
|
||||
|
||||
@Resource
|
||||
private ICcdiIntermediaryBlacklistService intermediaryService;
|
||||
|
||||
/**
|
||||
* 查询中介黑名单列表
|
||||
*/
|
||||
@Operation(summary = "查询中介黑名单列表")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:intermediary:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(CcdiIntermediaryBlacklistQueryDTO queryDTO) {
|
||||
// 使用MyBatis Plus分页
|
||||
PageDomain pageDomain = TableSupport.buildPageRequest();
|
||||
Page<CcdiIntermediaryBlacklist> page = new Page<>(pageDomain.getPageNum(), pageDomain.getPageSize());
|
||||
Page<CcdiIntermediaryBlacklistVO> result = intermediaryService.selectIntermediaryPage(page, queryDTO);
|
||||
return getDataTable(result.getRecords(), result.getTotal());
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出中介黑名单列表
|
||||
*/
|
||||
@Operation(summary = "导出中介黑名单列表")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:intermediary:export')")
|
||||
@Log(title = "中介黑名单", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, CcdiIntermediaryBlacklistQueryDTO queryDTO) {
|
||||
List<CcdiIntermediaryBlacklistExcel> list = intermediaryService.selectIntermediaryListForExport(queryDTO);
|
||||
EasyExcelUtil.exportExcel(response, list, CcdiIntermediaryBlacklistExcel.class, "中介黑名单");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取中介黑名单详细信息(根据类型返回不同结构)
|
||||
*/
|
||||
@Operation(summary = "获取中介黑名单详细信息")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:intermediary:query')")
|
||||
@GetMapping(value = "/{intermediaryId}")
|
||||
public AjaxResult getInfo(@PathVariable Long intermediaryId) {
|
||||
return success(intermediaryService.selectIntermediaryDetailById(intermediaryId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增中介黑名单(已废弃,请使用类型专用接口)
|
||||
*/
|
||||
@Operation(summary = "新增中介黑名单(已废弃,请使用类型专用接口)")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:intermediary:add')")
|
||||
@Log(title = "中介黑名单", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
@Deprecated
|
||||
public AjaxResult add(@Validated @RequestBody CcdiIntermediaryBlacklistAddDTO addDTO) {
|
||||
return toAjax(intermediaryService.insertIntermediary(addDTO));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增个人中介黑名单
|
||||
*/
|
||||
@Operation(summary = "新增个人中介黑名单")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:intermediary:add')")
|
||||
@Log(title = "个人中介黑名单", businessType = BusinessType.INSERT)
|
||||
@PostMapping("/person")
|
||||
public AjaxResult addPerson(@Validated @RequestBody CcdiIntermediaryPersonAddDTO addDTO) {
|
||||
return toAjax(intermediaryService.insertPersonIntermediary(addDTO));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增机构中介黑名单
|
||||
*/
|
||||
@Operation(summary = "新增机构中介黑名单")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:intermediary:add')")
|
||||
@Log(title = "机构中介黑名单", businessType = BusinessType.INSERT)
|
||||
@PostMapping("/entity")
|
||||
public AjaxResult addEntity(@Validated @RequestBody CcdiIntermediaryEntityAddDTO addDTO) {
|
||||
return toAjax(intermediaryService.insertEntityIntermediary(addDTO));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改中介黑名单
|
||||
*/
|
||||
@Operation(summary = "修改中介黑名单(已废弃,请使用类型专用接口)")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:intermediary:edit')")
|
||||
@Log(title = "中介黑名单", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
@Deprecated
|
||||
public AjaxResult edit(@Validated @RequestBody CcdiIntermediaryBlacklistEditDTO editDTO) {
|
||||
return toAjax(intermediaryService.updateIntermediary(editDTO));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改个人中介黑名单
|
||||
*/
|
||||
@Operation(summary = "修改个人中介黑名单")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:intermediary:edit')")
|
||||
@Log(title = "个人中介黑名单", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/person")
|
||||
public AjaxResult editPerson(@Validated @RequestBody CcdiIntermediaryPersonEditDTO editDTO) {
|
||||
return toAjax(intermediaryService.updatePersonIntermediary(editDTO));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改机构中介黑名单
|
||||
*/
|
||||
@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.updateEntityIntermediary(editDTO));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除中介黑名单
|
||||
*/
|
||||
@Operation(summary = "删除中介黑名单")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:intermediary:remove')")
|
||||
@Log(title = "中介黑名单", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{intermediaryIds}")
|
||||
public AjaxResult remove(@PathVariable Long[] intermediaryIds) {
|
||||
return toAjax(intermediaryService.deleteIntermediaryByIds(intermediaryIds));
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载个人中介导入模板(带字典下拉框)
|
||||
*/
|
||||
@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(@RequestParam("file") MultipartFile file, @RequestParam(value = "updateSupport", defaultValue = "false") boolean updateSupport) throws Exception {
|
||||
List<CcdiIntermediaryPersonExcel> list = EasyExcelUtil.importExcel(file.getInputStream(), CcdiIntermediaryPersonExcel.class);
|
||||
String message = intermediaryService.importPersonIntermediary(list, updateSupport);
|
||||
return success(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入机构中介黑名单
|
||||
*/
|
||||
@Operation(summary = "导入机构中介黑名单")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:intermediary:import')")
|
||||
@Log(title = "中介黑名单", businessType = BusinessType.IMPORT)
|
||||
@PostMapping("/importEntityData")
|
||||
public AjaxResult importEntityData(@RequestParam("file") MultipartFile file, @RequestParam(value = "updateSupport", defaultValue = "false") boolean updateSupport) throws Exception {
|
||||
List<CcdiIntermediaryEntityExcel> list = EasyExcelUtil.importExcel(file.getInputStream(), CcdiIntermediaryEntityExcel.class);
|
||||
String message = intermediaryService.importEntityIntermediary(list, updateSupport);
|
||||
return success(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
package com.ruoyi.ccdi.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiIntermediaryEntityAddDTO;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiIntermediaryEntityEditDTO;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiIntermediaryPersonAddDTO;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiIntermediaryPersonEditDTO;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiIntermediaryQueryDTO;
|
||||
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 com.ruoyi.common.utils.StringUtils;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 查询中介列表
|
||||
*/
|
||||
@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 vo = intermediaryService.selectIntermediaryPersonDetail(bizId);
|
||||
return success(vo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询实体中介详情
|
||||
*/
|
||||
@Operation(summary = "查询实体中介详情")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:intermediary:query')")
|
||||
@GetMapping("/entity/{socialCreditCode}")
|
||||
public AjaxResult getEntityInfo(@PathVariable String socialCreditCode) {
|
||||
CcdiIntermediaryEntityDetailVO vo = intermediaryService.selectIntermediaryEntityDetail(socialCreditCode);
|
||||
return success(vo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增个人中介
|
||||
*/
|
||||
@Operation(summary = "新增个人中介")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:intermediary:add')")
|
||||
@Log(title = "个人中介", businessType = BusinessType.INSERT)
|
||||
@PostMapping("/person")
|
||||
public AjaxResult addPerson(@Validated @RequestBody CcdiIntermediaryPersonAddDTO addDTO) {
|
||||
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) {
|
||||
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) {
|
||||
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));
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验人员ID唯一性
|
||||
*/
|
||||
@Operation(summary = "校验人员ID唯一性")
|
||||
@GetMapping("/checkPersonIdUnique")
|
||||
public AjaxResult checkPersonIdUnique(@RequestParam String personId, @RequestParam(required = false) String bizId) {
|
||||
boolean unique = intermediaryService.checkPersonIdUnique(personId, bizId);
|
||||
return success(unique);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验统一社会信用代码唯一性
|
||||
*/
|
||||
@Operation(summary = "校验统一社会信用代码唯一性")
|
||||
@GetMapping("/checkSocialCreditCodeUnique")
|
||||
public AjaxResult checkSocialCreditCodeUnique(@RequestParam String socialCreditCode, @RequestParam(required = false) String excludeId) {
|
||||
boolean unique = intermediaryService.checkSocialCreditCodeUnique(socialCreditCode, excludeId);
|
||||
return success(unique);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载个人中介导入模板
|
||||
*/
|
||||
@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, @RequestParam(defaultValue = "false") 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, @RequestParam(defaultValue = "false") boolean updateSupport) throws Exception {
|
||||
List<CcdiIntermediaryEntityExcel> list = EasyExcelUtil.importExcel(file.getInputStream(), CcdiIntermediaryEntityExcel.class);
|
||||
String message = intermediaryService.importIntermediaryEntity(list, updateSupport);
|
||||
return success(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
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;
|
||||
|
||||
/** 数据来源,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;
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
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;
|
||||
}
|
||||
@@ -1,154 +0,0 @@
|
||||
package com.ruoyi.ccdi.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 中介人员黑名单对象 dpc_intermediary_blacklist
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2026-01-27
|
||||
*/
|
||||
@Data
|
||||
public class CcdiIntermediaryBlacklist implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 中介ID */
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long intermediaryId;
|
||||
|
||||
/** 姓名/机构名称 */
|
||||
private String name;
|
||||
|
||||
/** 证件号 */
|
||||
private String certificateNo;
|
||||
|
||||
/** 中介类型 */
|
||||
private String intermediaryType;
|
||||
|
||||
/** 状态 */
|
||||
private String status;
|
||||
|
||||
/** 备注 */
|
||||
private String remark;
|
||||
|
||||
// ============================================================
|
||||
// 个人类型字段 (以 indiv_ 前缀标识,individual 缩写)
|
||||
// ============================================================
|
||||
/** 人员类型(中介、职业背债人、房产中介等) */
|
||||
private String indivType;
|
||||
|
||||
/** 人员子类型(本人、配偶等) */
|
||||
private String indivSubType;
|
||||
|
||||
/** 性别(M男 F女 O其他) */
|
||||
private String indivGender;
|
||||
|
||||
/** 证件类型 */
|
||||
private String indivCertType;
|
||||
|
||||
/** 手机号码(加密存储) */
|
||||
private String indivPhone;
|
||||
|
||||
/** 微信号 */
|
||||
private String indivWechat;
|
||||
|
||||
/** 联系地址 */
|
||||
private String indivAddress;
|
||||
|
||||
/** 所在公司 */
|
||||
private String indivCompany;
|
||||
|
||||
/** 职位/职务 */
|
||||
private String indivPosition;
|
||||
|
||||
/** 关联人员ID */
|
||||
private String indivRelatedId;
|
||||
|
||||
/** 关联关系 */
|
||||
private String indivRelation;
|
||||
|
||||
// ============================================================
|
||||
// 机构类型字段 (以 corp_ 前缀标识,corporation 缩写)
|
||||
// ============================================================
|
||||
/** 统一社会信用代码 */
|
||||
private String corpCreditCode;
|
||||
|
||||
/** 主体类型(有限责任公司、股份有限公司等) */
|
||||
private String corpType;
|
||||
|
||||
/** 企业性质(国企、民企、外企等) */
|
||||
private String corpNature;
|
||||
|
||||
/** 行业分类 */
|
||||
private String corpIndustryCategory;
|
||||
|
||||
/** 所属行业 */
|
||||
private String corpIndustry;
|
||||
|
||||
/** 成立日期 */
|
||||
private Date corpEstablishDate;
|
||||
|
||||
/** 注册地址 */
|
||||
private String corpAddress;
|
||||
|
||||
/** 法定代表人 */
|
||||
private String corpLegalRep;
|
||||
|
||||
/** 法定代表人证件类型 */
|
||||
private String corpLegalCertType;
|
||||
|
||||
/** 法定代表人证件号码 */
|
||||
private String corpLegalCertNo;
|
||||
|
||||
/** 股东1 */
|
||||
@TableField("corp_shareholder_1")
|
||||
private String corpShareholder1;
|
||||
|
||||
/** 股东2 */
|
||||
@TableField("corp_shareholder_2")
|
||||
private String corpShareholder2;
|
||||
|
||||
/** 股东3 */
|
||||
@TableField("corp_shareholder_3")
|
||||
private String corpShareholder3;
|
||||
|
||||
/** 股东4 */
|
||||
@TableField("corp_shareholder_4")
|
||||
private String corpShareholder4;
|
||||
|
||||
/** 股东5 */
|
||||
@TableField("corp_shareholder_5")
|
||||
private String corpShareholder5;
|
||||
|
||||
// ============================================================
|
||||
// 通用字段
|
||||
// ============================================================
|
||||
/** 数据来源(MANUAL手动录入 SYSTEM系统同步 IMPORT批量导入 API接口获取) */
|
||||
private String dataSource;
|
||||
|
||||
/** 创建者 */
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private String createBy;
|
||||
|
||||
/** 创建时间 */
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Date createTime;
|
||||
|
||||
/** 更新者 */
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private String updateBy;
|
||||
|
||||
/** 更新时间 */
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private Date updateTime;
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
package com.ruoyi.ccdi.domain.dto;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 中介人员黑名单新增 DTO
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2026-01-27
|
||||
*/
|
||||
public class CcdiIntermediaryBlacklistAddDTO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 姓名/机构名称 */
|
||||
@NotBlank(message = "姓名/机构名称不能为空")
|
||||
@Size(min = 1, max = 100, message = "姓名/机构名称长度不能超过100个字符")
|
||||
private String name;
|
||||
|
||||
/** 证件号 */
|
||||
@Size(max = 50, message = "证件号长度不能超过50个字符")
|
||||
private String certificateNo;
|
||||
|
||||
/** 中介类型 */
|
||||
@NotBlank(message = "中介类型不能为空")
|
||||
private String intermediaryType;
|
||||
|
||||
/** 备注 */
|
||||
@Size(max = 500, message = "备注长度不能超过500个字符")
|
||||
private String remark;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getCertificateNo() {
|
||||
return certificateNo;
|
||||
}
|
||||
|
||||
public void setCertificateNo(String certificateNo) {
|
||||
this.certificateNo = certificateNo;
|
||||
}
|
||||
|
||||
public String getIntermediaryType() {
|
||||
return intermediaryType;
|
||||
}
|
||||
|
||||
public void setIntermediaryType(String intermediaryType) {
|
||||
this.intermediaryType = intermediaryType;
|
||||
}
|
||||
|
||||
public String getRemark() {
|
||||
return remark;
|
||||
}
|
||||
|
||||
public void setRemark(String remark) {
|
||||
this.remark = remark;
|
||||
}
|
||||
}
|
||||
@@ -1,386 +0,0 @@
|
||||
package com.ruoyi.ccdi.domain.dto;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 中介人员黑名单编辑 DTO
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2026-01-27
|
||||
*/
|
||||
public class CcdiIntermediaryBlacklistEditDTO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 中介ID */
|
||||
@NotNull(message = "中介ID不能为空")
|
||||
private Long intermediaryId;
|
||||
|
||||
/** 姓名/机构名称 */
|
||||
@NotBlank(message = "姓名/机构名称不能为空")
|
||||
@Size(min = 1, max = 100, message = "姓名/机构名称长度不能超过100个字符")
|
||||
private String name;
|
||||
|
||||
/** 证件号 */
|
||||
@Size(max = 50, message = "证件号长度不能超过50个字符")
|
||||
private String certificateNo;
|
||||
|
||||
/** 中介类型 */
|
||||
@NotBlank(message = "中介类型不能为空")
|
||||
private String intermediaryType;
|
||||
|
||||
/** 状态 */
|
||||
@NotBlank(message = "状态不能为空")
|
||||
private String status;
|
||||
|
||||
/** 备注 */
|
||||
@Size(max = 500, message = "备注长度不能超过500个字符")
|
||||
private String remark;
|
||||
|
||||
// ============================================================
|
||||
// 个人类型字段 (以 indiv_ 前缀标识,individual 缩写)
|
||||
// ============================================================
|
||||
/** 人员类型(中介、职业背债人、房产中介等) */
|
||||
private String indivType;
|
||||
|
||||
/** 人员子类型(本人、配偶等) */
|
||||
private String indivSubType;
|
||||
|
||||
/** 性别(M男 F女 O其他) */
|
||||
private String indivGender;
|
||||
|
||||
/** 证件类型 */
|
||||
private String indivCertType;
|
||||
|
||||
/** 手机号码(加密存储) */
|
||||
private String indivPhone;
|
||||
|
||||
/** 微信号 */
|
||||
private String indivWechat;
|
||||
|
||||
/** 联系地址 */
|
||||
private String indivAddress;
|
||||
|
||||
/** 所在公司 */
|
||||
private String indivCompany;
|
||||
|
||||
/** 职位/职务 */
|
||||
private String indivPosition;
|
||||
|
||||
/** 关联人员ID */
|
||||
private String indivRelatedId;
|
||||
|
||||
/** 关联关系 */
|
||||
private String indivRelation;
|
||||
|
||||
// ============================================================
|
||||
// 机构类型字段 (以 corp_ 前缀标识,corporation 缩写)
|
||||
// ============================================================
|
||||
/** 统一社会信用代码 */
|
||||
private String corpCreditCode;
|
||||
|
||||
/** 主体类型(有限责任公司、股份有限公司等) */
|
||||
private String corpType;
|
||||
|
||||
/** 企业性质(国企、民企、外企等) */
|
||||
private String corpNature;
|
||||
|
||||
/** 行业分类 */
|
||||
private String corpIndustryCategory;
|
||||
|
||||
/** 所属行业 */
|
||||
private String corpIndustry;
|
||||
|
||||
/** 成立日期 */
|
||||
private Date corpEstablishDate;
|
||||
|
||||
/** 注册地址 */
|
||||
private String corpAddress;
|
||||
|
||||
/** 法定代表人 */
|
||||
private String corpLegalRep;
|
||||
|
||||
/** 法定代表人证件类型 */
|
||||
private String corpLegalCertType;
|
||||
|
||||
/** 法定代表人证件号码 */
|
||||
private String corpLegalCertNo;
|
||||
|
||||
/** 股东1 */
|
||||
private String corpShareholder1;
|
||||
|
||||
/** 股东2 */
|
||||
private String corpShareholder2;
|
||||
|
||||
/** 股东3 */
|
||||
private String corpShareholder3;
|
||||
|
||||
/** 股东4 */
|
||||
private String corpShareholder4;
|
||||
|
||||
/** 股东5 */
|
||||
private String corpShareholder5;
|
||||
|
||||
public Long getIntermediaryId() {
|
||||
return intermediaryId;
|
||||
}
|
||||
|
||||
public void setIntermediaryId(Long intermediaryId) {
|
||||
this.intermediaryId = intermediaryId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getCertificateNo() {
|
||||
return certificateNo;
|
||||
}
|
||||
|
||||
public void setCertificateNo(String certificateNo) {
|
||||
this.certificateNo = certificateNo;
|
||||
}
|
||||
|
||||
public String getIntermediaryType() {
|
||||
return intermediaryType;
|
||||
}
|
||||
|
||||
public void setIntermediaryType(String intermediaryType) {
|
||||
this.intermediaryType = intermediaryType;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getRemark() {
|
||||
return remark;
|
||||
}
|
||||
|
||||
public void setRemark(String remark) {
|
||||
this.remark = remark;
|
||||
}
|
||||
|
||||
public String getIndivType() {
|
||||
return indivType;
|
||||
}
|
||||
|
||||
public void setIndivType(String indivType) {
|
||||
this.indivType = indivType;
|
||||
}
|
||||
|
||||
public String getIndivSubType() {
|
||||
return indivSubType;
|
||||
}
|
||||
|
||||
public void setIndivSubType(String indivSubType) {
|
||||
this.indivSubType = indivSubType;
|
||||
}
|
||||
|
||||
public String getIndivGender() {
|
||||
return indivGender;
|
||||
}
|
||||
|
||||
public void setIndivGender(String indivGender) {
|
||||
this.indivGender = indivGender;
|
||||
}
|
||||
|
||||
public String getIndivCertType() {
|
||||
return indivCertType;
|
||||
}
|
||||
|
||||
public void setIndivCertType(String indivCertType) {
|
||||
this.indivCertType = indivCertType;
|
||||
}
|
||||
|
||||
public String getIndivPhone() {
|
||||
return indivPhone;
|
||||
}
|
||||
|
||||
public void setIndivPhone(String indivPhone) {
|
||||
this.indivPhone = indivPhone;
|
||||
}
|
||||
|
||||
public String getIndivWechat() {
|
||||
return indivWechat;
|
||||
}
|
||||
|
||||
public void setIndivWechat(String indivWechat) {
|
||||
this.indivWechat = indivWechat;
|
||||
}
|
||||
|
||||
public String getIndivAddress() {
|
||||
return indivAddress;
|
||||
}
|
||||
|
||||
public void setIndivAddress(String indivAddress) {
|
||||
this.indivAddress = indivAddress;
|
||||
}
|
||||
|
||||
public String getIndivCompany() {
|
||||
return indivCompany;
|
||||
}
|
||||
|
||||
public void setIndivCompany(String indivCompany) {
|
||||
this.indivCompany = indivCompany;
|
||||
}
|
||||
|
||||
public String getIndivPosition() {
|
||||
return indivPosition;
|
||||
}
|
||||
|
||||
public void setIndivPosition(String indivPosition) {
|
||||
this.indivPosition = indivPosition;
|
||||
}
|
||||
|
||||
public String getIndivRelatedId() {
|
||||
return indivRelatedId;
|
||||
}
|
||||
|
||||
public void setIndivRelatedId(String indivRelatedId) {
|
||||
this.indivRelatedId = indivRelatedId;
|
||||
}
|
||||
|
||||
public String getIndivRelation() {
|
||||
return indivRelation;
|
||||
}
|
||||
|
||||
public void setIndivRelation(String indivRelation) {
|
||||
this.indivRelation = indivRelation;
|
||||
}
|
||||
|
||||
public String getCorpCreditCode() {
|
||||
return corpCreditCode;
|
||||
}
|
||||
|
||||
public void setCorpCreditCode(String corpCreditCode) {
|
||||
this.corpCreditCode = corpCreditCode;
|
||||
}
|
||||
|
||||
public String getCorpType() {
|
||||
return corpType;
|
||||
}
|
||||
|
||||
public void setCorpType(String corpType) {
|
||||
this.corpType = corpType;
|
||||
}
|
||||
|
||||
public String getCorpNature() {
|
||||
return corpNature;
|
||||
}
|
||||
|
||||
public void setCorpNature(String corpNature) {
|
||||
this.corpNature = corpNature;
|
||||
}
|
||||
|
||||
public String getCorpIndustryCategory() {
|
||||
return corpIndustryCategory;
|
||||
}
|
||||
|
||||
public void setCorpIndustryCategory(String corpIndustryCategory) {
|
||||
this.corpIndustryCategory = corpIndustryCategory;
|
||||
}
|
||||
|
||||
public String getCorpIndustry() {
|
||||
return corpIndustry;
|
||||
}
|
||||
|
||||
public void setCorpIndustry(String corpIndustry) {
|
||||
this.corpIndustry = corpIndustry;
|
||||
}
|
||||
|
||||
public Date getCorpEstablishDate() {
|
||||
return corpEstablishDate;
|
||||
}
|
||||
|
||||
public void setCorpEstablishDate(Date corpEstablishDate) {
|
||||
this.corpEstablishDate = corpEstablishDate;
|
||||
}
|
||||
|
||||
public String getCorpAddress() {
|
||||
return corpAddress;
|
||||
}
|
||||
|
||||
public void setCorpAddress(String corpAddress) {
|
||||
this.corpAddress = corpAddress;
|
||||
}
|
||||
|
||||
public String getCorpLegalRep() {
|
||||
return corpLegalRep;
|
||||
}
|
||||
|
||||
public void setCorpLegalRep(String corpLegalRep) {
|
||||
this.corpLegalRep = corpLegalRep;
|
||||
}
|
||||
|
||||
public String getCorpLegalCertType() {
|
||||
return corpLegalCertType;
|
||||
}
|
||||
|
||||
public void setCorpLegalCertType(String corpLegalCertType) {
|
||||
this.corpLegalCertType = corpLegalCertType;
|
||||
}
|
||||
|
||||
public String getCorpLegalCertNo() {
|
||||
return corpLegalCertNo;
|
||||
}
|
||||
|
||||
public void setCorpLegalCertNo(String corpLegalCertNo) {
|
||||
this.corpLegalCertNo = corpLegalCertNo;
|
||||
}
|
||||
|
||||
public String getCorpShareholder1() {
|
||||
return corpShareholder1;
|
||||
}
|
||||
|
||||
public void setCorpShareholder1(String corpShareholder1) {
|
||||
this.corpShareholder1 = corpShareholder1;
|
||||
}
|
||||
|
||||
public String getCorpShareholder2() {
|
||||
return corpShareholder2;
|
||||
}
|
||||
|
||||
public void setCorpShareholder2(String corpShareholder2) {
|
||||
this.corpShareholder2 = corpShareholder2;
|
||||
}
|
||||
|
||||
public String getCorpShareholder3() {
|
||||
return corpShareholder3;
|
||||
}
|
||||
|
||||
public void setCorpShareholder3(String corpShareholder3) {
|
||||
this.corpShareholder3 = corpShareholder3;
|
||||
}
|
||||
|
||||
public String getCorpShareholder4() {
|
||||
return corpShareholder4;
|
||||
}
|
||||
|
||||
public void setCorpShareholder4(String corpShareholder4) {
|
||||
this.corpShareholder4 = corpShareholder4;
|
||||
}
|
||||
|
||||
public String getCorpShareholder5() {
|
||||
return corpShareholder5;
|
||||
}
|
||||
|
||||
public void setCorpShareholder5(String corpShareholder5) {
|
||||
this.corpShareholder5 = corpShareholder5;
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
package com.ruoyi.ccdi.domain.dto;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 中介人员黑名单查询 DTO
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2026-01-27
|
||||
*/
|
||||
public class CcdiIntermediaryBlacklistQueryDTO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 姓名/机构名称(模糊查询) */
|
||||
private String name;
|
||||
|
||||
/** 证件号(精确查询) */
|
||||
private String certificateNo;
|
||||
|
||||
/** 中介类型 */
|
||||
private String intermediaryType;
|
||||
|
||||
/** 状态 */
|
||||
private String status;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getCertificateNo() {
|
||||
return certificateNo;
|
||||
}
|
||||
|
||||
public void setCertificateNo(String certificateNo) {
|
||||
this.certificateNo = certificateNo;
|
||||
}
|
||||
|
||||
public String getIntermediaryType() {
|
||||
return intermediaryType;
|
||||
}
|
||||
|
||||
public void setIntermediaryType(String intermediaryType) {
|
||||
this.intermediaryType = intermediaryType;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
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;
|
||||
@@ -9,87 +10,83 @@ import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 机构中介新增 DTO
|
||||
* 实体中介新增DTO
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2026-01-29
|
||||
* @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(min = 1, max = 100, message = "机构名称长度不能超过100个字符")
|
||||
private String name;
|
||||
@Size(max = 200, message = "机构名称长度不能超过200个字符")
|
||||
private String enterpriseName;
|
||||
|
||||
/** 统一社会信用代码 */
|
||||
@NotBlank(message = "统一社会信用代码不能为空")
|
||||
@Size(max = 18, message = "统一社会信用代码长度不能超过18个字符")
|
||||
private String corpCreditCode;
|
||||
@Schema(description = "统一社会信用代码")
|
||||
@Size(max = 50, message = "统一社会信用代码长度不能超过50个字符")
|
||||
private String socialCreditCode;
|
||||
|
||||
/** 主体类型 */
|
||||
@Schema(description = "主体类型")
|
||||
@Size(max = 50, message = "主体类型长度不能超过50个字符")
|
||||
private String corpType;
|
||||
private String enterpriseType;
|
||||
|
||||
/** 企业性质 */
|
||||
@Schema(description = "企业性质")
|
||||
@Size(max = 50, message = "企业性质长度不能超过50个字符")
|
||||
private String corpNature;
|
||||
private String enterpriseNature;
|
||||
|
||||
/** 行业分类 */
|
||||
@Schema(description = "行业分类")
|
||||
@Size(max = 100, message = "行业分类长度不能超过100个字符")
|
||||
private String corpIndustryCategory;
|
||||
private String industryClass;
|
||||
|
||||
/** 所属行业 */
|
||||
@Schema(description = "所属行业")
|
||||
@Size(max = 100, message = "所属行业长度不能超过100个字符")
|
||||
private String corpIndustry;
|
||||
private String industryName;
|
||||
|
||||
/** 成立日期 */
|
||||
private Date corpEstablishDate;
|
||||
@Schema(description = "成立日期")
|
||||
private Date establishDate;
|
||||
|
||||
/** 注册地址 */
|
||||
@Schema(description = "注册地址")
|
||||
@Size(max = 500, message = "注册地址长度不能超过500个字符")
|
||||
private String corpAddress;
|
||||
private String registerAddress;
|
||||
|
||||
/** 法定代表人 */
|
||||
@Size(max = 50, message = "法定代表人长度不能超过50个字符")
|
||||
private String corpLegalRep;
|
||||
@Schema(description = "法定代表人")
|
||||
@Size(max = 100, message = "法定代表人长度不能超过100个字符")
|
||||
private String legalRepresentative;
|
||||
|
||||
/** 法定代表人证件类型 */
|
||||
@Size(max = 30, message = "法定代表人证件类型长度不能超过30个字符")
|
||||
private String corpLegalCertType;
|
||||
@Schema(description = "法定代表人证件类型")
|
||||
@Size(max = 50, message = "法定代表人证件类型长度不能超过50个字符")
|
||||
private String legalCertType;
|
||||
|
||||
/** 法定代表人证件号码 */
|
||||
@Size(max = 30, message = "法定代表人证件号码长度不能超过30个字符")
|
||||
private String corpLegalCertNo;
|
||||
@Schema(description = "法定代表人证件号码")
|
||||
@Size(max = 50, message = "法定代表人证件号码长度不能超过50个字符")
|
||||
private String legalCertNo;
|
||||
|
||||
/** 股东1 */
|
||||
@Size(max = 30, message = "股东1长度不能超过30个字符")
|
||||
private String corpShareholder1;
|
||||
@Schema(description = "股东1")
|
||||
@Size(max = 100, message = "股东1长度不能超过100个字符")
|
||||
private String shareholder1;
|
||||
|
||||
/** 股东2 */
|
||||
@Size(max = 30, message = "股东2长度不能超过30个字符")
|
||||
private String corpShareholder2;
|
||||
@Schema(description = "股东2")
|
||||
@Size(max = 100, message = "股东2长度不能超过100个字符")
|
||||
private String shareholder2;
|
||||
|
||||
/** 股东3 */
|
||||
@Size(max = 30, message = "股东3长度不能超过30个字符")
|
||||
private String corpShareholder3;
|
||||
@Schema(description = "股东3")
|
||||
@Size(max = 100, message = "股东3长度不能超过100个字符")
|
||||
private String shareholder3;
|
||||
|
||||
/** 股东4 */
|
||||
@Size(max = 30, message = "股东4长度不能超过30个字符")
|
||||
private String corpShareholder4;
|
||||
@Schema(description = "股东4")
|
||||
@Size(max = 100, message = "股东4长度不能超过100个字符")
|
||||
private String shareholder4;
|
||||
|
||||
/** 股东5 */
|
||||
@Size(max = 30, message = "股东5长度不能超过30个字符")
|
||||
private String corpShareholder5;
|
||||
@Schema(description = "股东5")
|
||||
@Size(max = 100, message = "股东5长度不能超过100个字符")
|
||||
private String shareholder5;
|
||||
|
||||
/** 状态 */
|
||||
@NotBlank(message = "状态不能为空")
|
||||
private String status;
|
||||
|
||||
/** 备注 */
|
||||
@Schema(description = "备注")
|
||||
@Size(max = 500, message = "备注长度不能超过500个字符")
|
||||
private String remark;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
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;
|
||||
|
||||
@@ -10,80 +10,83 @@ import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 机构中介编辑 DTO
|
||||
* 实体中介修改DTO
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2026-01-29
|
||||
* @date 2026-02-04
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "实体中介修改DTO")
|
||||
public class CcdiIntermediaryEntityEditDTO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 中介ID */
|
||||
@NotNull(message = "中介ID不能为空")
|
||||
private Long intermediaryId;
|
||||
@Schema(description = "统一社会信用代码")
|
||||
@NotBlank(message = "统一社会信用代码不能为空")
|
||||
private String socialCreditCode;
|
||||
|
||||
/** 机构名称 */
|
||||
@Schema(description = "机构名称")
|
||||
@NotBlank(message = "机构名称不能为空")
|
||||
@Size(min = 1, max = 100, message = "机构名称长度不能超过100个字符")
|
||||
private String name;
|
||||
@Size(max = 200, message = "机构名称长度不能超过200个字符")
|
||||
private String enterpriseName;
|
||||
|
||||
/** 证件号(统一社会信用代码) */
|
||||
@Size(max = 50, message = "证件号长度不能超过50个字符")
|
||||
private String certificateNo;
|
||||
@Schema(description = "主体类型")
|
||||
@Size(max = 50, message = "主体类型长度不能超过50个字符")
|
||||
private String enterpriseType;
|
||||
|
||||
/** 统一社会信用代码 */
|
||||
private String corpCreditCode;
|
||||
@Schema(description = "企业性质")
|
||||
@Size(max = 50, message = "企业性质长度不能超过50个字符")
|
||||
private String enterpriseNature;
|
||||
|
||||
/** 主体类型(有限责任公司、股份有限公司等) */
|
||||
private String corpType;
|
||||
@Schema(description = "行业分类")
|
||||
@Size(max = 100, message = "行业分类长度不能超过100个字符")
|
||||
private String industryClass;
|
||||
|
||||
/** 企业性质(国企、民企、外企等) */
|
||||
private String corpNature;
|
||||
@Schema(description = "所属行业")
|
||||
@Size(max = 100, message = "所属行业长度不能超过100个字符")
|
||||
private String industryName;
|
||||
|
||||
/** 行业分类 */
|
||||
private String corpIndustryCategory;
|
||||
@Schema(description = "成立日期")
|
||||
private Date establishDate;
|
||||
|
||||
/** 所属行业 */
|
||||
private String corpIndustry;
|
||||
@Schema(description = "注册地址")
|
||||
@Size(max = 500, message = "注册地址长度不能超过500个字符")
|
||||
private String registerAddress;
|
||||
|
||||
/** 成立日期 */
|
||||
private Date corpEstablishDate;
|
||||
@Schema(description = "法定代表人")
|
||||
@Size(max = 100, message = "法定代表人长度不能超过100个字符")
|
||||
private String legalRepresentative;
|
||||
|
||||
/** 注册地址 */
|
||||
private String corpAddress;
|
||||
@Schema(description = "法定代表人证件类型")
|
||||
@Size(max = 50, message = "法定代表人证件类型长度不能超过50个字符")
|
||||
private String legalCertType;
|
||||
|
||||
/** 法定代表人 */
|
||||
private String corpLegalRep;
|
||||
@Schema(description = "法定代表人证件号码")
|
||||
@Size(max = 50, message = "法定代表人证件号码长度不能超过50个字符")
|
||||
private String legalCertNo;
|
||||
|
||||
/** 法定代表人证件类型 */
|
||||
private String corpLegalCertType;
|
||||
@Schema(description = "股东1")
|
||||
@Size(max = 100, message = "股东1长度不能超过100个字符")
|
||||
private String shareholder1;
|
||||
|
||||
/** 法定代表人证件号码 */
|
||||
private String corpLegalCertNo;
|
||||
@Schema(description = "股东2")
|
||||
@Size(max = 100, message = "股东2长度不能超过100个字符")
|
||||
private String shareholder2;
|
||||
|
||||
/** 股东1 */
|
||||
private String corpShareholder1;
|
||||
@Schema(description = "股东3")
|
||||
@Size(max = 100, message = "股东3长度不能超过100个字符")
|
||||
private String shareholder3;
|
||||
|
||||
/** 股东2 */
|
||||
private String corpShareholder2;
|
||||
@Schema(description = "股东4")
|
||||
@Size(max = 100, message = "股东4长度不能超过100个字符")
|
||||
private String shareholder4;
|
||||
|
||||
/** 股东3 */
|
||||
private String corpShareholder3;
|
||||
@Schema(description = "股东5")
|
||||
@Size(max = 100, message = "股东5长度不能超过100个字符")
|
||||
private String shareholder5;
|
||||
|
||||
/** 股东4 */
|
||||
private String corpShareholder4;
|
||||
|
||||
/** 股东5 */
|
||||
private String corpShareholder5;
|
||||
|
||||
/** 状态 */
|
||||
@NotBlank(message = "状态不能为空")
|
||||
private String status;
|
||||
|
||||
/** 备注 */
|
||||
@Schema(description = "备注")
|
||||
@Size(max = 500, message = "备注长度不能超过500个字符")
|
||||
private String remark;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
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;
|
||||
@@ -11,73 +12,71 @@ import java.io.Serializable;
|
||||
* 个人中介新增DTO
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2026-01-29
|
||||
* @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(min = 1, max = 100, message = "姓名长度不能超过100个字符")
|
||||
@Size(max = 100, message = "姓名长度不能超过100个字符")
|
||||
private String name;
|
||||
|
||||
/** 证件号 */
|
||||
@NotBlank(message = "证件号不能为空")
|
||||
@Size(max = 50, message = "证件号长度不能超过50个字符")
|
||||
private String certificateNo;
|
||||
@Schema(description = "人员类型")
|
||||
private String personType;
|
||||
|
||||
/** 人员类型(中介、职业背债人、房产中介等) */
|
||||
@Size(max = 30, message = "人员类型长度不能超过30个字符")
|
||||
private String indivType;
|
||||
@Schema(description = "人员子类型")
|
||||
private String personSubType;
|
||||
|
||||
/** 人员子类型(本人、配偶等) */
|
||||
@Size(max = 50, message = "人员子类型长度不能超过50个字符")
|
||||
private String indivSubType;
|
||||
@Schema(description = "性别")
|
||||
private String gender;
|
||||
|
||||
/** 性别(M男 F女 O其他) */
|
||||
@Size(max = 1, message = "性别长度不能超过1个字符")
|
||||
private String indivGender;
|
||||
@Schema(description = "证件类型")
|
||||
private String idType;
|
||||
|
||||
/** 证件类型 */
|
||||
@Size(max = 30, message = "证件类型长度不能超过30个字符")
|
||||
private String indivCertType;
|
||||
@Schema(description = "证件号码")
|
||||
@NotBlank(message = "证件号码不能为空")
|
||||
@Size(max = 50, message = "证件号码长度不能超过50个字符")
|
||||
private String personId;
|
||||
|
||||
/** 手机号码(加密存储) */
|
||||
@Schema(description = "手机号码")
|
||||
@Size(max = 20, message = "手机号码长度不能超过20个字符")
|
||||
private String indivPhone;
|
||||
private String mobile;
|
||||
|
||||
/** 微信号 */
|
||||
@Schema(description = "微信号")
|
||||
@Size(max = 50, message = "微信号长度不能超过50个字符")
|
||||
private String indivWechat;
|
||||
private String wechatNo;
|
||||
|
||||
/** 联系地址 */
|
||||
@Schema(description = "联系地址")
|
||||
@Size(max = 200, message = "联系地址长度不能超过200个字符")
|
||||
private String indivAddress;
|
||||
private String contactAddress;
|
||||
|
||||
/** 所在公司 */
|
||||
@Size(max = 100, message = "所在公司长度不能超过100个字符")
|
||||
private String indivCompany;
|
||||
@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 indivPosition;
|
||||
private String position;
|
||||
|
||||
/** 关联人员ID */
|
||||
@Size(max = 20, message = "关联人员ID长度不能超过20个字符")
|
||||
private String indivRelatedId;
|
||||
@Schema(description = "关联人员ID")
|
||||
@Size(max = 50, message = "关联人员ID长度不能超过50个字符")
|
||||
private String relatedNumId;
|
||||
|
||||
/** 关联关系 */
|
||||
@Schema(description = "关联关系")
|
||||
@Size(max = 50, message = "关联关系长度不能超过50个字符")
|
||||
private String indivRelation;
|
||||
private String relationType;
|
||||
|
||||
/** 状态 */
|
||||
@NotBlank(message = "状态不能为空")
|
||||
private String status;
|
||||
|
||||
/** 备注 */
|
||||
@Schema(description = "备注")
|
||||
@Size(max = 500, message = "备注长度不能超过500个字符")
|
||||
private String remark;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
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;
|
||||
|
||||
@@ -9,68 +9,76 @@ import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 个人中介编辑 DTO
|
||||
* 个人中介修改DTO
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2026-01-29
|
||||
* @date 2026-02-04
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "个人中介修改DTO")
|
||||
public class CcdiIntermediaryPersonEditDTO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 中介ID */
|
||||
@NotNull(message = "中介ID不能为空")
|
||||
private Long intermediaryId;
|
||||
@Schema(description = "人员ID")
|
||||
@NotBlank(message = "人员ID不能为空")
|
||||
private String bizId;
|
||||
|
||||
/** 姓名 */
|
||||
@Schema(description = "姓名")
|
||||
@NotBlank(message = "姓名不能为空")
|
||||
@Size(min = 1, max = 100, message = "姓名长度不能超过100个字符")
|
||||
@Size(max = 100, message = "姓名长度不能超过100个字符")
|
||||
private String name;
|
||||
|
||||
/** 证件号 */
|
||||
@Size(max = 50, message = "证件号长度不能超过50个字符")
|
||||
private String certificateNo;
|
||||
@Schema(description = "人员类型")
|
||||
private String personType;
|
||||
|
||||
/** 人员类型(中介、职业背债人、房产中介等) */
|
||||
private String indivType;
|
||||
@Schema(description = "人员子类型")
|
||||
private String personSubType;
|
||||
|
||||
/** 人员子类型(本人、配偶等) */
|
||||
private String indivSubType;
|
||||
@Schema(description = "性别")
|
||||
private String gender;
|
||||
|
||||
/** 性别(M男 F女 O其他) */
|
||||
private String indivGender;
|
||||
@Schema(description = "证件类型")
|
||||
private String idType;
|
||||
|
||||
/** 证件类型 */
|
||||
private String indivCertType;
|
||||
@Schema(description = "证件号码")
|
||||
@Size(max = 50, message = "证件号码长度不能超过50个字符")
|
||||
private String personId;
|
||||
|
||||
/** 手机号码(加密存储) */
|
||||
private String indivPhone;
|
||||
@Schema(description = "手机号码")
|
||||
@Size(max = 20, message = "手机号码长度不能超过20个字符")
|
||||
private String mobile;
|
||||
|
||||
/** 微信号 */
|
||||
private String indivWechat;
|
||||
@Schema(description = "微信号")
|
||||
@Size(max = 50, message = "微信号长度不能超过50个字符")
|
||||
private String wechatNo;
|
||||
|
||||
/** 联系地址 */
|
||||
private String indivAddress;
|
||||
@Schema(description = "联系地址")
|
||||
@Size(max = 200, message = "联系地址长度不能超过200个字符")
|
||||
private String contactAddress;
|
||||
|
||||
/** 所在公司 */
|
||||
private String indivCompany;
|
||||
@Schema(description = "所在公司")
|
||||
@Size(max = 200, message = "所在公司长度不能超过200个字符")
|
||||
private String company;
|
||||
|
||||
/** 职位/职务 */
|
||||
private String indivPosition;
|
||||
@Schema(description = "企业统一信用码")
|
||||
@Size(max = 50, message = "企业统一信用码长度不能超过50个字符")
|
||||
private String socialCreditCode;
|
||||
|
||||
/** 关联人员ID */
|
||||
private String indivRelatedId;
|
||||
@Schema(description = "职位")
|
||||
@Size(max = 100, message = "职位长度不能超过100个字符")
|
||||
private String position;
|
||||
|
||||
/** 关联关系 */
|
||||
private String indivRelation;
|
||||
@Schema(description = "关联人员ID")
|
||||
@Size(max = 50, message = "关联人员ID长度不能超过50个字符")
|
||||
private String relatedNumId;
|
||||
|
||||
/** 状态 */
|
||||
@NotBlank(message = "状态不能为空")
|
||||
private String status;
|
||||
@Schema(description = "关联关系")
|
||||
@Size(max = 50, message = "关联关系长度不能超过50个字符")
|
||||
private String relationType;
|
||||
|
||||
/** 备注 */
|
||||
@Schema(description = "备注")
|
||||
@Size(max = 500, message = "备注长度不能超过500个字符")
|
||||
private String remark;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
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;
|
||||
|
||||
@Schema(description = "中介类型(1=个人, 2=实体)")
|
||||
private String intermediaryType;
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package com.ruoyi.ccdi.domain.excel;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import com.alibaba.excel.annotation.write.style.ColumnWidth;
|
||||
import com.ruoyi.ccdi.utils.converter.IntermediaryStatusConverter;
|
||||
import com.ruoyi.ccdi.utils.converter.IntermediaryTypeConverter;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 中介人员黑名单Excel导入导出对象
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2026-01-27
|
||||
*/
|
||||
@Data
|
||||
public class CcdiIntermediaryBlacklistExcel implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 姓名/机构名称 */
|
||||
@ExcelProperty(value = "姓名/机构名称", index = 0)
|
||||
@ColumnWidth(20)
|
||||
private String name;
|
||||
|
||||
/** 证件号 */
|
||||
@ExcelProperty(value = "证件号", index = 1)
|
||||
@ColumnWidth(20)
|
||||
private String certificateNo;
|
||||
|
||||
/** 中介类型 */
|
||||
@ExcelProperty(value = "中介类型", converter = IntermediaryTypeConverter.class, index = 2)
|
||||
@ColumnWidth(15)
|
||||
private String intermediaryType;
|
||||
|
||||
/** 状态 */
|
||||
@ExcelProperty(value = "状态", converter = IntermediaryStatusConverter.class, index = 3)
|
||||
@ColumnWidth(10)
|
||||
private String status;
|
||||
|
||||
/** 备注 */
|
||||
@ExcelProperty(value = "备注", index = 4)
|
||||
@ColumnWidth(30)
|
||||
private String remark;
|
||||
}
|
||||
@@ -7,12 +7,13 @@ import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 机构中介黑名单Excel导入对象
|
||||
* 实体中介Excel导入导出对象
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2026-01-29
|
||||
* @date 2026-02-04
|
||||
*/
|
||||
@Data
|
||||
public class CcdiIntermediaryEntityExcel implements Serializable {
|
||||
@@ -20,77 +21,91 @@ public class CcdiIntermediaryEntityExcel implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ExcelProperty(value = "机构名称", index = 0)
|
||||
@ColumnWidth(25)
|
||||
private String name;
|
||||
/** 机构名称 */
|
||||
@ExcelProperty(value = "机构名称*", index = 0)
|
||||
@ColumnWidth(30)
|
||||
private String enterpriseName;
|
||||
|
||||
@ExcelProperty(value = "统一社会信用代码", index = 1)
|
||||
/** 统一社会信用代码 */
|
||||
@ExcelProperty(value = "统一社会信用代码*", index = 1)
|
||||
@ColumnWidth(20)
|
||||
private String corpCreditCode;
|
||||
private String socialCreditCode;
|
||||
|
||||
/** 主体类型 */
|
||||
@ExcelProperty(value = "主体类型", index = 2)
|
||||
@ColumnWidth(20)
|
||||
@DictDropdown(dictType = "dpc_entity_type")
|
||||
private String corpType;
|
||||
@ColumnWidth(15)
|
||||
@DictDropdown(dictType = "ccdi_entity_type")
|
||||
private String enterpriseType;
|
||||
|
||||
/** 企业性质 */
|
||||
@ExcelProperty(value = "企业性质", index = 3)
|
||||
@ColumnWidth(15)
|
||||
@DictDropdown(dictType = "dpc_enterprise_nature")
|
||||
private String corpNature;
|
||||
@DictDropdown(dictType = "ccdi_enterprise_nature")
|
||||
private String enterpriseNature;
|
||||
|
||||
/** 行业分类 */
|
||||
@ExcelProperty(value = "行业分类", index = 4)
|
||||
@ColumnWidth(15)
|
||||
private String corpIndustryCategory;
|
||||
private String industryClass;
|
||||
|
||||
/** 所属行业 */
|
||||
@ExcelProperty(value = "所属行业", index = 5)
|
||||
@ColumnWidth(15)
|
||||
private String corpIndustry;
|
||||
private String industryName;
|
||||
|
||||
/** 成立日期 */
|
||||
@ExcelProperty(value = "成立日期", index = 6)
|
||||
@ColumnWidth(15)
|
||||
private String corpEstablishDate;
|
||||
private Date establishDate;
|
||||
|
||||
/** 注册地址 */
|
||||
@ExcelProperty(value = "注册地址", index = 7)
|
||||
@ColumnWidth(40)
|
||||
private String corpAddress;
|
||||
private String registerAddress;
|
||||
|
||||
/** 法定代表人 */
|
||||
@ExcelProperty(value = "法定代表人", index = 8)
|
||||
@ColumnWidth(15)
|
||||
private String corpLegalRep;
|
||||
private String legalRepresentative;
|
||||
|
||||
/** 法定代表人证件类型 */
|
||||
@ExcelProperty(value = "法定代表人证件类型", index = 9)
|
||||
@ColumnWidth(20)
|
||||
private String corpLegalCertType;
|
||||
@DictDropdown(dictType = "ccdi_certificate_type")
|
||||
private String legalCertType;
|
||||
|
||||
/** 法定代表人证件号码 */
|
||||
@ExcelProperty(value = "法定代表人证件号码", index = 10)
|
||||
@ColumnWidth(20)
|
||||
private String corpLegalCertNo;
|
||||
private String legalCertNo;
|
||||
|
||||
/** 股东1 */
|
||||
@ExcelProperty(value = "股东1", index = 11)
|
||||
@ColumnWidth(15)
|
||||
private String corpShareholder1;
|
||||
private String shareholder1;
|
||||
|
||||
/** 股东2 */
|
||||
@ExcelProperty(value = "股东2", index = 12)
|
||||
@ColumnWidth(15)
|
||||
private String corpShareholder2;
|
||||
private String shareholder2;
|
||||
|
||||
/** 股东3 */
|
||||
@ExcelProperty(value = "股东3", index = 13)
|
||||
@ColumnWidth(15)
|
||||
private String corpShareholder3;
|
||||
private String shareholder3;
|
||||
|
||||
/** 股东4 */
|
||||
@ExcelProperty(value = "股东4", index = 14)
|
||||
@ColumnWidth(15)
|
||||
private String corpShareholder4;
|
||||
private String shareholder4;
|
||||
|
||||
/** 股东5 */
|
||||
@ExcelProperty(value = "股东5", index = 15)
|
||||
@ColumnWidth(15)
|
||||
private String corpShareholder5;
|
||||
private String shareholder5;
|
||||
|
||||
/** 备注 */
|
||||
@ExcelProperty(value = "备注", index = 16)
|
||||
@ColumnWidth(30)
|
||||
private String remark;
|
||||
|
||||
// 以下字段不在 Excel 中显示,由系统自动设置
|
||||
// private String status; // 默认:正常(0)
|
||||
// private String dataSource; // 默认:批量导入(IMPORT)
|
||||
}
|
||||
|
||||
@@ -9,10 +9,10 @@ import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 个人中介黑名单Excel导入对象
|
||||
* 个人中介Excel导入导出对象
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2026-01-29
|
||||
* @date 2026-02-04
|
||||
*/
|
||||
@Data
|
||||
public class CcdiIntermediaryPersonExcel implements Serializable {
|
||||
@@ -20,65 +20,82 @@ public class CcdiIntermediaryPersonExcel implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ExcelProperty(value = "姓名", index = 0)
|
||||
/** 姓名 */
|
||||
@ExcelProperty(value = "姓名*", index = 0)
|
||||
@ColumnWidth(15)
|
||||
private String name;
|
||||
|
||||
/** 人员类型 */
|
||||
@ExcelProperty(value = "人员类型", index = 1)
|
||||
@ColumnWidth(15)
|
||||
private String indivType;
|
||||
@DictDropdown(dictType = "ccdi_person_type")
|
||||
private String personType;
|
||||
|
||||
/** 人员子类型 */
|
||||
@ExcelProperty(value = "人员子类型", index = 2)
|
||||
@ColumnWidth(15)
|
||||
private String indivSubType;
|
||||
private String personSubType;
|
||||
|
||||
/** 性别 */
|
||||
@ExcelProperty(value = "性别", index = 3)
|
||||
@ColumnWidth(10)
|
||||
@DictDropdown(dictType = "dpc_indiv_gender")
|
||||
private String indivGender;
|
||||
@DictDropdown(dictType = "ccdi_indiv_gender")
|
||||
private String gender;
|
||||
|
||||
/** 证件类型 */
|
||||
@ExcelProperty(value = "证件类型", index = 4)
|
||||
@ColumnWidth(15)
|
||||
@DictDropdown(dictType = "dpc_certificate_type")
|
||||
private String indivCertType;
|
||||
@DictDropdown(dictType = "ccdi_certificate_type")
|
||||
private String idType;
|
||||
|
||||
@ExcelProperty(value = "证件号码", index = 5)
|
||||
/** 证件号码 */
|
||||
@ExcelProperty(value = "证件号码*", index = 5)
|
||||
@ColumnWidth(20)
|
||||
private String certificateNo;
|
||||
private String personId;
|
||||
|
||||
/** 手机号码 */
|
||||
@ExcelProperty(value = "手机号码", index = 6)
|
||||
@ColumnWidth(15)
|
||||
private String indivPhone;
|
||||
private String mobile;
|
||||
|
||||
/** 微信号 */
|
||||
@ExcelProperty(value = "微信号", index = 7)
|
||||
@ColumnWidth(15)
|
||||
private String indivWechat;
|
||||
private String wechatNo;
|
||||
|
||||
/** 联系地址 */
|
||||
@ExcelProperty(value = "联系地址", index = 8)
|
||||
@ColumnWidth(30)
|
||||
private String indivAddress;
|
||||
private String contactAddress;
|
||||
|
||||
/** 所在公司 */
|
||||
@ExcelProperty(value = "所在公司", index = 9)
|
||||
@ColumnWidth(20)
|
||||
private String indivCompany;
|
||||
private String company;
|
||||
|
||||
@ExcelProperty(value = "职位", index = 10)
|
||||
/** 企业统一信用码 */
|
||||
@ExcelProperty(value = "企业统一信用码", index = 10)
|
||||
@ColumnWidth(20)
|
||||
private String socialCreditCode;
|
||||
|
||||
/** 职位 */
|
||||
@ExcelProperty(value = "职位", index = 11)
|
||||
@ColumnWidth(15)
|
||||
private String indivPosition;
|
||||
private String position;
|
||||
|
||||
@ExcelProperty(value = "关联人员ID", index = 11)
|
||||
/** 关联人员ID */
|
||||
@ExcelProperty(value = "关联人员ID", index = 12)
|
||||
@ColumnWidth(15)
|
||||
private String indivRelatedId;
|
||||
private String relatedNumId;
|
||||
|
||||
@ExcelProperty(value = "关联关系", index = 12)
|
||||
/** 关系类型 */
|
||||
@ExcelProperty(value = "关系类型", index = 13)
|
||||
@ColumnWidth(15)
|
||||
private String indivRelation;
|
||||
@DictDropdown(dictType = "ccdi_relation_type")
|
||||
private String relationType;
|
||||
|
||||
@ExcelProperty(value = "备注", index = 13)
|
||||
/** 备注 */
|
||||
@ExcelProperty(value = "备注", index = 14)
|
||||
@ColumnWidth(30)
|
||||
private String remark;
|
||||
|
||||
// 以下字段不在 Excel 中显示,由系统自动设置
|
||||
// private String status; // 默认:正常(0)
|
||||
// private String dataSource; // 默认:批量导入(IMPORT)
|
||||
}
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
package com.ruoyi.ccdi.domain.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 中介人员黑名单视图对象 VO
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2026-01-27
|
||||
*/
|
||||
@Data
|
||||
public class CcdiIntermediaryBlacklistVO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 中介ID */
|
||||
private Long intermediaryId;
|
||||
|
||||
/** 姓名/机构名称 */
|
||||
private String name;
|
||||
|
||||
/** 证件号 */
|
||||
private String certificateNo;
|
||||
|
||||
/** 中介类型 */
|
||||
private String intermediaryType;
|
||||
|
||||
/** 中介类型名称(用于前端显示) */
|
||||
private String intermediaryTypeName;
|
||||
|
||||
/** 状态 */
|
||||
private String status;
|
||||
|
||||
/** 状态名称(用于前端显示) */
|
||||
private String statusName;
|
||||
|
||||
/** 备注 */
|
||||
private String remark;
|
||||
|
||||
/** 创建者 */
|
||||
private String createBy;
|
||||
|
||||
/** 创建时间 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
|
||||
/** 更新者 */
|
||||
private String updateBy;
|
||||
|
||||
/** 更新时间 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime;
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
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;
|
||||
@@ -8,119 +9,86 @@ import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 机构中介黑名单详情 VO
|
||||
* 实体中介详情VO
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2026-01-29
|
||||
* @date 2026-02-04
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "实体中介详情VO")
|
||||
public class CcdiIntermediaryEntityDetailVO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
// ============================================================
|
||||
// 核心字段
|
||||
// ============================================================
|
||||
/** 中介ID */
|
||||
private Long intermediaryId;
|
||||
@Schema(description = "业务ID")
|
||||
private String bizId;
|
||||
|
||||
/** 机构名称 */
|
||||
private String name;
|
||||
@Schema(description = "统一社会信用代码")
|
||||
private String socialCreditCode;
|
||||
|
||||
/** 证件号码 */
|
||||
private String certificateNo;
|
||||
|
||||
/** 中介类型 */
|
||||
@Schema(description = "中介类型(1=个人, 2=实体)")
|
||||
private String intermediaryType;
|
||||
|
||||
/** 中介类型名称 */
|
||||
private String intermediaryTypeName;
|
||||
@Schema(description = "企业名称")
|
||||
private String enterpriseName;
|
||||
|
||||
/** 状态 */
|
||||
private String status;
|
||||
@Schema(description = "企业类型")
|
||||
private String enterpriseType;
|
||||
|
||||
/** 状态名称 */
|
||||
private String statusName;
|
||||
@Schema(description = "企业性质")
|
||||
private String enterpriseNature;
|
||||
|
||||
/** 备注 */
|
||||
private String remark;
|
||||
@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;
|
||||
|
||||
/** 数据来源名称 */
|
||||
private String dataSourceName;
|
||||
@Schema(description = "备注")
|
||||
private String remark;
|
||||
|
||||
// ============================================================
|
||||
// 机构专属字段
|
||||
// ============================================================
|
||||
/** 统一社会信用代码 */
|
||||
private String corpCreditCode;
|
||||
|
||||
/** 主体类型 */
|
||||
private String corpType;
|
||||
|
||||
/** 主体类型名称 */
|
||||
private String corpTypeName;
|
||||
|
||||
/** 企业性质 */
|
||||
private String corpNature;
|
||||
|
||||
/** 企业性质名称 */
|
||||
private String corpNatureName;
|
||||
|
||||
/** 行业分类 */
|
||||
private String corpIndustryCategory;
|
||||
|
||||
/** 所属行业 */
|
||||
private String corpIndustry;
|
||||
|
||||
/** 成立日期 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private Date corpEstablishDate;
|
||||
|
||||
/** 注册地址 */
|
||||
private String corpAddress;
|
||||
|
||||
/** 法定代表人 */
|
||||
private String corpLegalRep;
|
||||
|
||||
/** 法定代表人证件类型 */
|
||||
private String corpLegalCertType;
|
||||
|
||||
/** 法定代表人证件号码 */
|
||||
private String corpLegalCertNo;
|
||||
|
||||
/** 股东1 */
|
||||
private String corpShareholder1;
|
||||
|
||||
/** 股东2 */
|
||||
private String corpShareholder2;
|
||||
|
||||
/** 股东3 */
|
||||
private String corpShareholder3;
|
||||
|
||||
/** 股东4 */
|
||||
private String corpShareholder4;
|
||||
|
||||
/** 股东5 */
|
||||
private String corpShareholder5;
|
||||
|
||||
// ============================================================
|
||||
// 审计字段
|
||||
// ============================================================
|
||||
/** 创建者 */
|
||||
private String createBy;
|
||||
|
||||
/** 创建时间 */
|
||||
@Schema(description = "创建时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
|
||||
/** 更新者 */
|
||||
private String updateBy;
|
||||
|
||||
/** 更新时间 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
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;
|
||||
@@ -8,106 +9,73 @@ import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 个人中介黑名单详情 VO
|
||||
* 个人中介详情VO
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2026-01-29
|
||||
* @date 2026-02-04
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "个人中介详情VO")
|
||||
public class CcdiIntermediaryPersonDetailVO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
// ============================================================
|
||||
// 核心字段
|
||||
// ============================================================
|
||||
/** 中介ID */
|
||||
private Long intermediaryId;
|
||||
@Schema(description = "人员ID")
|
||||
private String bizId;
|
||||
|
||||
/** 姓名 */
|
||||
private String name;
|
||||
|
||||
/** 证件号码 */
|
||||
private String certificateNo;
|
||||
|
||||
/** 中介类型 */
|
||||
@Schema(description = "中介类型(1=个人, 2=实体)")
|
||||
private String intermediaryType;
|
||||
|
||||
/** 中介类型名称 */
|
||||
private String intermediaryTypeName;
|
||||
@Schema(description = "姓名")
|
||||
private String name;
|
||||
|
||||
/** 状态 */
|
||||
private String status;
|
||||
@Schema(description = "人员类型")
|
||||
private String personType;
|
||||
|
||||
/** 状态名称 */
|
||||
private String statusName;
|
||||
@Schema(description = "人员子类型")
|
||||
private String personSubType;
|
||||
|
||||
/** 备注 */
|
||||
private String remark;
|
||||
@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 socialCreditCode;
|
||||
|
||||
@Schema(description = "职位")
|
||||
private String position;
|
||||
|
||||
@Schema(description = "关联人员ID")
|
||||
private String relatedNumId;
|
||||
|
||||
@Schema(description = "关联关系")
|
||||
private String relationType;
|
||||
|
||||
@Schema(description = "数据来源")
|
||||
private String dataSource;
|
||||
|
||||
/** 数据来源名称 */
|
||||
private String dataSourceName;
|
||||
@Schema(description = "备注")
|
||||
private String remark;
|
||||
|
||||
// ============================================================
|
||||
// 个人专属字段
|
||||
// ============================================================
|
||||
/** 人员类型 */
|
||||
private String indivType;
|
||||
|
||||
/** 人员子类型 */
|
||||
private String indivSubType;
|
||||
|
||||
/** 性别 */
|
||||
private String indivGender;
|
||||
|
||||
/** 性别名称 */
|
||||
private String indivGenderName;
|
||||
|
||||
/** 证件类型 */
|
||||
private String indivCertType;
|
||||
|
||||
/** 证件类型名称 */
|
||||
private String indivCertTypeName;
|
||||
|
||||
/** 手机号码 */
|
||||
private String indivPhone;
|
||||
|
||||
/** 微信号 */
|
||||
private String indivWechat;
|
||||
|
||||
/** 联系地址 */
|
||||
private String indivAddress;
|
||||
|
||||
/** 所在公司 */
|
||||
private String indivCompany;
|
||||
|
||||
/** 职位/职务 */
|
||||
private String indivPosition;
|
||||
|
||||
/** 关联人员ID */
|
||||
private String indivRelatedId;
|
||||
|
||||
/** 关联关系 */
|
||||
private String indivRelation;
|
||||
|
||||
// ============================================================
|
||||
// 审计字段
|
||||
// ============================================================
|
||||
/** 创建者 */
|
||||
private String createBy;
|
||||
|
||||
/** 创建时间 */
|
||||
@Schema(description = "创建时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
|
||||
/** 更新者 */
|
||||
private String updateBy;
|
||||
|
||||
/** 更新时间 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
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;
|
||||
|
||||
@Schema(description = "ID")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "姓名/机构名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "证件号/统一社会信用代码")
|
||||
private String certificateNo;
|
||||
|
||||
@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;
|
||||
|
||||
@Schema(description = "修改时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime;
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
package com.ruoyi.ccdi.enums;
|
||||
|
||||
|
||||
/**
|
||||
* 人员子类型枚举
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public enum IndivSubType {
|
||||
|
||||
/** 本人 */
|
||||
SELF("本人", "本人"),
|
||||
|
||||
/** 配偶 */
|
||||
SPOUSE("配偶", "配偶"),
|
||||
|
||||
/** 父亲 */
|
||||
FATHER("父亲", "父亲"),
|
||||
|
||||
/** 母亲 */
|
||||
MOTHER("母亲", "母亲"),
|
||||
|
||||
/** 兄弟 */
|
||||
BROTHER("兄弟", "兄弟"),
|
||||
|
||||
/** 姐妹 */
|
||||
SISTER("姐妹", "姐妹"),
|
||||
|
||||
/** 子女 */
|
||||
CHILD("子女", "子女");
|
||||
|
||||
private final String code;
|
||||
private final String desc;
|
||||
|
||||
IndivSubType(String code, String desc) {
|
||||
this.code = code;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getDesc() {
|
||||
return desc;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据编码获取描述
|
||||
*/
|
||||
public static String getDescByCode(String code) {
|
||||
for (IndivSubType type : values()) {
|
||||
if (type.getCode().equals(code)) {
|
||||
return type.getDesc();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.ruoyi.ccdi.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.ruoyi.ccdi.domain.CcdiBizIntermediary;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 个人中介Mapper接口
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2026-02-04
|
||||
*/
|
||||
@Mapper
|
||||
public interface CcdiBizIntermediaryMapper extends BaseMapper<CcdiBizIntermediary> {
|
||||
|
||||
/**
|
||||
* 批量插入个人中介
|
||||
*
|
||||
* @param list 个人中介列表
|
||||
* @return 插入行数
|
||||
*/
|
||||
int insertBatch(List<CcdiBizIntermediary> list);
|
||||
|
||||
/**
|
||||
* 批量更新个人中介
|
||||
*
|
||||
* @param list 个人中介列表
|
||||
* @return 更新行数
|
||||
*/
|
||||
int updateBatch(List<CcdiBizIntermediary> list);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.ruoyi.ccdi.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.ruoyi.ccdi.domain.CcdiEnterpriseBaseInfo;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 实体中介Mapper接口
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2026-02-04
|
||||
*/
|
||||
@Mapper
|
||||
public interface CcdiEnterpriseBaseInfoMapper extends BaseMapper<CcdiEnterpriseBaseInfo> {
|
||||
|
||||
/**
|
||||
* 批量插入实体中介
|
||||
*
|
||||
* @param list 实体中介列表
|
||||
* @return 插入行数
|
||||
*/
|
||||
int insertBatch(List<CcdiEnterpriseBaseInfo> list);
|
||||
|
||||
/**
|
||||
* 批量更新实体中介
|
||||
*
|
||||
* @param list 实体中介列表
|
||||
* @return 更新行数
|
||||
*/
|
||||
int updateBatch(List<CcdiEnterpriseBaseInfo> list);
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package com.ruoyi.ccdi.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.ruoyi.ccdi.domain.CcdiIntermediaryBlacklist;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 中介人员黑名单 数据层
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2026-01-27
|
||||
*/
|
||||
public interface CcdiIntermediaryBlacklistMapper extends BaseMapper<CcdiIntermediaryBlacklist> {
|
||||
|
||||
/**
|
||||
* 批量插入中介黑名单数据
|
||||
*
|
||||
* @param list 中介黑名单列表
|
||||
* @return 插入行数
|
||||
*/
|
||||
int batchInsert(@Param("list") List<CcdiIntermediaryBlacklist> list);
|
||||
|
||||
/**
|
||||
* 批量更新中介黑名单数据
|
||||
*
|
||||
* @param list 中介黑名单列表
|
||||
* @return 更新行数
|
||||
*/
|
||||
int batchUpdate(@Param("list") List<CcdiIntermediaryBlacklist> list);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.ruoyi.ccdi.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiIntermediaryQueryDTO;
|
||||
import com.ruoyi.ccdi.domain.vo.CcdiIntermediaryVO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
/**
|
||||
* 中介黑名单联合查询Mapper接口
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2026-02-05
|
||||
*/
|
||||
@Mapper
|
||||
public interface CcdiIntermediaryMapper {
|
||||
|
||||
/**
|
||||
* 联合查询中介列表(支持MyBatis Plus分页)
|
||||
* 通过UNION ALL联合查询个人中介和实体中介
|
||||
* 支持按中介类型筛选(1=个人, 2=实体, null=全部)
|
||||
*
|
||||
* @param page 分页对象
|
||||
* @param queryDTO 查询条件
|
||||
* @return 中介VO分页结果
|
||||
*/
|
||||
Page<CcdiIntermediaryVO> selectIntermediaryList(Page<CcdiIntermediaryVO> page, @Param("query") CcdiIntermediaryQueryDTO queryDTO);
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
package com.ruoyi.ccdi.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.ccdi.domain.CcdiIntermediaryBlacklist;
|
||||
import com.ruoyi.ccdi.domain.dto.*;
|
||||
import com.ruoyi.ccdi.domain.excel.CcdiIntermediaryBlacklistExcel;
|
||||
import com.ruoyi.ccdi.domain.excel.CcdiIntermediaryEntityExcel;
|
||||
import com.ruoyi.ccdi.domain.excel.CcdiIntermediaryPersonExcel;
|
||||
import com.ruoyi.ccdi.domain.vo.CcdiIntermediaryBlacklistVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 中介人员黑名单 服务层
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2026-01-27
|
||||
*/
|
||||
public interface ICcdiIntermediaryBlacklistService {
|
||||
|
||||
/**
|
||||
* 查询中介黑名单列表
|
||||
*
|
||||
* @param queryDTO 查询条件
|
||||
* @return 中介黑名单集合
|
||||
*/
|
||||
List<CcdiIntermediaryBlacklistVO> selectIntermediaryList(CcdiIntermediaryBlacklistQueryDTO queryDTO);
|
||||
|
||||
/**
|
||||
* 分页查询中介黑名单列表
|
||||
*
|
||||
* @param page 分页对象
|
||||
* @param queryDTO 查询条件
|
||||
* @return 中介黑名单VO分页结果
|
||||
*/
|
||||
Page<CcdiIntermediaryBlacklistVO> selectIntermediaryPage(Page<CcdiIntermediaryBlacklist> page, CcdiIntermediaryBlacklistQueryDTO queryDTO);
|
||||
|
||||
/**
|
||||
* 查询中介黑名单列表(用于导出)
|
||||
*
|
||||
* @param queryDTO 查询条件
|
||||
* @return 中介黑名单Excel实体集合
|
||||
*/
|
||||
List<CcdiIntermediaryBlacklistExcel> selectIntermediaryListForExport(CcdiIntermediaryBlacklistQueryDTO queryDTO);
|
||||
|
||||
/**
|
||||
* 查询中介黑名单详细
|
||||
*
|
||||
* @param intermediaryId 中介ID
|
||||
* @return 中介黑名单VO
|
||||
*/
|
||||
CcdiIntermediaryBlacklistVO selectIntermediaryById(Long intermediaryId);
|
||||
|
||||
/**
|
||||
* 新增中介黑名单(通用接口,不推荐使用)
|
||||
*
|
||||
* @param addDTO 新增DTO
|
||||
* @return 结果
|
||||
* @deprecated 请使用 insertPersonIntermediary 或 insertEntityIntermediary 代替
|
||||
*/
|
||||
@Deprecated
|
||||
int insertIntermediary(CcdiIntermediaryBlacklistAddDTO addDTO);
|
||||
|
||||
/**
|
||||
* 新增个人中介黑名单
|
||||
*
|
||||
* @param addDTO 个人中介新增DTO
|
||||
* @return 结果
|
||||
*/
|
||||
int insertPersonIntermediary(CcdiIntermediaryPersonAddDTO addDTO);
|
||||
|
||||
/**
|
||||
* 新增机构中介黑名单
|
||||
*
|
||||
* @param addDTO 机构中介新增DTO
|
||||
* @return 结果
|
||||
*/
|
||||
int insertEntityIntermediary(CcdiIntermediaryEntityAddDTO addDTO);
|
||||
|
||||
/**
|
||||
* 修改中介黑名单(通用接口,不推荐使用)
|
||||
*
|
||||
* @param editDTO 编辑DTO
|
||||
* @return 结果
|
||||
* @deprecated 请使用 updatePersonIntermediary 或 updateEntityIntermediary 代替
|
||||
*/
|
||||
@Deprecated
|
||||
int updateIntermediary(CcdiIntermediaryBlacklistEditDTO editDTO);
|
||||
|
||||
/**
|
||||
* 修改个人中介黑名单
|
||||
*
|
||||
* @param editDTO 个人中介编辑DTO
|
||||
* @return 结果
|
||||
*/
|
||||
int updatePersonIntermediary(CcdiIntermediaryPersonEditDTO editDTO);
|
||||
|
||||
/**
|
||||
* 修改机构中介黑名单
|
||||
*
|
||||
* @param editDTO 机构中介编辑DTO
|
||||
* @return 结果
|
||||
*/
|
||||
int updateEntityIntermediary(CcdiIntermediaryEntityEditDTO editDTO);
|
||||
|
||||
/**
|
||||
* 批量删除中介黑名单
|
||||
*
|
||||
* @param intermediaryIds 需要删除的中介ID
|
||||
* @return 结果
|
||||
*/
|
||||
int deleteIntermediaryByIds(Long[] intermediaryIds);
|
||||
|
||||
/**
|
||||
* 导入中介黑名单数据
|
||||
*
|
||||
* @param excelList Excel实体列表
|
||||
* @param isUpdateSupport 是否更新支持
|
||||
* @return 结果
|
||||
*/
|
||||
String importIntermediary(List<CcdiIntermediaryBlacklistExcel> excelList, Boolean isUpdateSupport);
|
||||
|
||||
/**
|
||||
* 根据中介类型获取详情(返回不同类型)
|
||||
*
|
||||
* @param intermediaryId 中介ID
|
||||
* @return 个人返回 CcdiIntermediaryPersonDetailVO,机构返回 CcdiIntermediaryEntityDetailVO
|
||||
*/
|
||||
Object selectIntermediaryDetailById(Long intermediaryId);
|
||||
|
||||
/**
|
||||
* 导入个人中介数据
|
||||
*
|
||||
* @param excelList Excel实体列表
|
||||
* @param isUpdateSupport 是否更新支持
|
||||
* @return 结果
|
||||
*/
|
||||
String importPersonIntermediary(List<CcdiIntermediaryPersonExcel> excelList, Boolean isUpdateSupport);
|
||||
|
||||
/**
|
||||
* 导入机构中介数据
|
||||
*
|
||||
* @param excelList Excel实体列表
|
||||
* @param isUpdateSupport 是否更新支持
|
||||
* @return 结果
|
||||
*/
|
||||
String importEntityIntermediary(List<CcdiIntermediaryEntityExcel> excelList, Boolean isUpdateSupport);
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
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 {
|
||||
|
||||
/**
|
||||
* 分页查询中介列表
|
||||
*
|
||||
* @param page 分页对象
|
||||
* @param queryDTO 查询条件
|
||||
* @return 中介VO分页结果
|
||||
*/
|
||||
Page<CcdiIntermediaryVO> selectIntermediaryPage(Page<CcdiIntermediaryVO> page, CcdiIntermediaryQueryDTO queryDTO);
|
||||
|
||||
/**
|
||||
* 查询个人中介详情
|
||||
*
|
||||
* @param bizId 人员ID
|
||||
* @return 个人中介详情VO
|
||||
*/
|
||||
CcdiIntermediaryPersonDetailVO selectIntermediaryPersonDetail(String bizId);
|
||||
|
||||
/**
|
||||
* 查询实体中介详情
|
||||
*
|
||||
* @param socialCreditCode 统一社会信用代码
|
||||
* @return 实体中介详情VO
|
||||
*/
|
||||
CcdiIntermediaryEntityDetailVO selectIntermediaryEntityDetail(String socialCreditCode);
|
||||
|
||||
/**
|
||||
* 新增个人中介
|
||||
*
|
||||
* @param addDTO 新增DTO
|
||||
* @return 结果
|
||||
*/
|
||||
int insertIntermediaryPerson(CcdiIntermediaryPersonAddDTO addDTO);
|
||||
|
||||
/**
|
||||
* 修改个人中介
|
||||
*
|
||||
* @param editDTO 编辑DTO
|
||||
* @return 结果
|
||||
*/
|
||||
int updateIntermediaryPerson(CcdiIntermediaryPersonEditDTO editDTO);
|
||||
|
||||
/**
|
||||
* 新增实体中介
|
||||
*
|
||||
* @param addDTO 新增DTO
|
||||
* @return 结果
|
||||
*/
|
||||
int insertIntermediaryEntity(CcdiIntermediaryEntityAddDTO addDTO);
|
||||
|
||||
/**
|
||||
* 修改实体中介
|
||||
*
|
||||
* @param editDTO 编辑DTO
|
||||
* @return 结果
|
||||
*/
|
||||
int updateIntermediaryEntity(CcdiIntermediaryEntityEditDTO editDTO);
|
||||
|
||||
/**
|
||||
* 批量删除中介
|
||||
*
|
||||
* @param ids 需要删除的ID数组
|
||||
* @return 结果
|
||||
*/
|
||||
int deleteIntermediaryByIds(String[] ids);
|
||||
|
||||
/**
|
||||
* 校验人员ID唯一性
|
||||
*
|
||||
* @param personId 人员ID
|
||||
* @param bizId 排除的人员ID
|
||||
* @return true=唯一, false=不唯一
|
||||
*/
|
||||
boolean checkPersonIdUnique(String personId, String bizId);
|
||||
|
||||
/**
|
||||
* 校验统一社会信用代码唯一性
|
||||
*
|
||||
* @param socialCreditCode 统一社会信用代码
|
||||
* @param excludeId 排除的ID
|
||||
* @return true=唯一, false=不唯一
|
||||
*/
|
||||
boolean checkSocialCreditCodeUnique(String socialCreditCode, String excludeId);
|
||||
|
||||
/**
|
||||
* 导入个人中介数据
|
||||
*
|
||||
* @param list Excel实体列表
|
||||
* @param updateSupport 是否更新支持
|
||||
* @return 结果
|
||||
*/
|
||||
String importIntermediaryPerson(java.util.List<com.ruoyi.ccdi.domain.excel.CcdiIntermediaryPersonExcel> list, boolean updateSupport);
|
||||
|
||||
/**
|
||||
* 导入实体中介数据
|
||||
*
|
||||
* @param list Excel实体列表
|
||||
* @param updateSupport 是否更新支持
|
||||
* @return 结果
|
||||
*/
|
||||
String importIntermediaryEntity(java.util.List<com.ruoyi.ccdi.domain.excel.CcdiIntermediaryEntityExcel> list, boolean updateSupport);
|
||||
}
|
||||
@@ -1,741 +0,0 @@
|
||||
package com.ruoyi.ccdi.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.ccdi.domain.CcdiIntermediaryBlacklist;
|
||||
import com.ruoyi.ccdi.domain.dto.*;
|
||||
import com.ruoyi.ccdi.domain.excel.CcdiIntermediaryBlacklistExcel;
|
||||
import com.ruoyi.ccdi.domain.excel.CcdiIntermediaryEntityExcel;
|
||||
import com.ruoyi.ccdi.domain.excel.CcdiIntermediaryPersonExcel;
|
||||
import com.ruoyi.ccdi.domain.vo.CcdiIntermediaryBlacklistVO;
|
||||
import com.ruoyi.ccdi.domain.vo.CcdiIntermediaryEntityDetailVO;
|
||||
import com.ruoyi.ccdi.domain.vo.CcdiIntermediaryPersonDetailVO;
|
||||
import com.ruoyi.ccdi.enums.DataSource;
|
||||
import com.ruoyi.ccdi.enums.Gender;
|
||||
import com.ruoyi.ccdi.enums.IntermediaryStatus;
|
||||
import com.ruoyi.ccdi.enums.IntermediaryType;
|
||||
import com.ruoyi.ccdi.mapper.CcdiIntermediaryBlacklistMapper;
|
||||
import com.ruoyi.ccdi.service.ICcdiIntermediaryBlacklistService;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 中介人员黑名单 服务层处理
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2026-01-27
|
||||
*/
|
||||
@Service
|
||||
public class CcdiIntermediaryBlacklistServiceImpl implements ICcdiIntermediaryBlacklistService {
|
||||
|
||||
@Resource
|
||||
private CcdiIntermediaryBlacklistMapper intermediaryMapper;
|
||||
|
||||
/**
|
||||
* 查询中介黑名单列表
|
||||
*
|
||||
* @param queryDTO 查询条件
|
||||
* @return 中介黑名单集合
|
||||
*/
|
||||
@Override
|
||||
public List<CcdiIntermediaryBlacklistVO> selectIntermediaryList(CcdiIntermediaryBlacklistQueryDTO queryDTO) {
|
||||
LambdaQueryWrapper<CcdiIntermediaryBlacklist> wrapper = buildQueryWrapper(queryDTO);
|
||||
List<CcdiIntermediaryBlacklist> list = intermediaryMapper.selectList(wrapper);
|
||||
return list.stream().map(this::convertToVO).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询中介黑名单列表
|
||||
*
|
||||
* @param page 分页对象
|
||||
* @param queryDTO 查询条件
|
||||
* @return 中介黑名单VO分页结果
|
||||
*/
|
||||
@Override
|
||||
public Page<CcdiIntermediaryBlacklistVO> selectIntermediaryPage(Page<CcdiIntermediaryBlacklist> page, CcdiIntermediaryBlacklistQueryDTO queryDTO) {
|
||||
LambdaQueryWrapper<CcdiIntermediaryBlacklist> wrapper = buildQueryWrapper(queryDTO);
|
||||
Page<CcdiIntermediaryBlacklist> resultPage = intermediaryMapper.selectPage(page, wrapper);
|
||||
|
||||
// 转换为VO
|
||||
Page<CcdiIntermediaryBlacklistVO> voPage = new Page<>(resultPage.getCurrent(), resultPage.getSize(), resultPage.getTotal());
|
||||
voPage.setRecords(resultPage.getRecords().stream().map(this::convertToVO).collect(Collectors.toList()));
|
||||
voPage.setPages(resultPage.getPages());
|
||||
|
||||
return voPage;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询中介黑名单列表(用于导出)
|
||||
*
|
||||
* @param queryDTO 查询条件
|
||||
* @return 中介黑名单Excel实体集合
|
||||
*/
|
||||
@Override
|
||||
public List<CcdiIntermediaryBlacklistExcel> selectIntermediaryListForExport(CcdiIntermediaryBlacklistQueryDTO queryDTO) {
|
||||
LambdaQueryWrapper<CcdiIntermediaryBlacklist> wrapper = buildQueryWrapper(queryDTO);
|
||||
List<CcdiIntermediaryBlacklist> list = intermediaryMapper.selectList(wrapper);
|
||||
return list.stream().map(entity -> {
|
||||
CcdiIntermediaryBlacklistExcel excel = new CcdiIntermediaryBlacklistExcel();
|
||||
BeanUtils.copyProperties(entity, excel);
|
||||
return excel;
|
||||
}).toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询中介黑名单详细
|
||||
*
|
||||
* @param intermediaryId 中介ID
|
||||
* @return 中介黑名单VO
|
||||
*/
|
||||
@Override
|
||||
public CcdiIntermediaryBlacklistVO selectIntermediaryById(Long intermediaryId) {
|
||||
CcdiIntermediaryBlacklist intermediary = intermediaryMapper.selectById(intermediaryId);
|
||||
return convertToVO(intermediary);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增中介黑名单
|
||||
*
|
||||
* @param addDTO 新增DTO
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public int insertIntermediary(CcdiIntermediaryBlacklistAddDTO addDTO) {
|
||||
CcdiIntermediaryBlacklist intermediary = new CcdiIntermediaryBlacklist();
|
||||
BeanUtils.copyProperties(addDTO, intermediary);
|
||||
// 手动新增时,数据来源设置为 MANUAL
|
||||
intermediary.setDataSource("MANUAL");
|
||||
// 默认状态设置为正常
|
||||
intermediary.setStatus("0");
|
||||
return intermediaryMapper.insert(intermediary);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增个人中介黑名单
|
||||
*
|
||||
* @param addDTO 个人中介新增DTO
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int insertPersonIntermediary(CcdiIntermediaryPersonAddDTO addDTO) {
|
||||
CcdiIntermediaryBlacklist intermediary = new CcdiIntermediaryBlacklist();
|
||||
BeanUtils.copyProperties(addDTO, intermediary);
|
||||
// 设置中介类型为个人
|
||||
intermediary.setIntermediaryType("1");
|
||||
// 手动新增时,数据来源设置为 MANUAL
|
||||
intermediary.setDataSource("MANUAL");
|
||||
return intermediaryMapper.insert(intermediary);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增机构中介黑名单
|
||||
*
|
||||
* @param addDTO 机构中介新增DTO
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int insertEntityIntermediary(CcdiIntermediaryEntityAddDTO addDTO) {
|
||||
CcdiIntermediaryBlacklist intermediary = new CcdiIntermediaryBlacklist();
|
||||
BeanUtils.copyProperties(addDTO, intermediary);
|
||||
// 设置中介类型为机构
|
||||
intermediary.setIntermediaryType("2");
|
||||
// 证件号使用统一社会信用代码
|
||||
intermediary.setCertificateNo(addDTO.getCorpCreditCode());
|
||||
// 手动新增时,数据来源设置为 MANUAL
|
||||
intermediary.setDataSource("MANUAL");
|
||||
return intermediaryMapper.insert(intermediary);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改中介黑名单
|
||||
*
|
||||
* @param editDTO 编辑DTO
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public int updateIntermediary(CcdiIntermediaryBlacklistEditDTO editDTO) {
|
||||
CcdiIntermediaryBlacklist intermediary = new CcdiIntermediaryBlacklist();
|
||||
BeanUtils.copyProperties(editDTO, intermediary);
|
||||
return intermediaryMapper.updateById(intermediary);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改个人中介黑名单
|
||||
*
|
||||
* @param editDTO 个人中介编辑DTO
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int updatePersonIntermediary(CcdiIntermediaryPersonEditDTO editDTO) {
|
||||
CcdiIntermediaryBlacklist intermediary = new CcdiIntermediaryBlacklist();
|
||||
BeanUtils.copyProperties(editDTO, intermediary);
|
||||
// 设置中介类型为个人
|
||||
intermediary.setIntermediaryType("1");
|
||||
// 清空机构专属字段
|
||||
clearEntityFields(intermediary);
|
||||
return intermediaryMapper.updateById(intermediary);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改机构中介黑名单
|
||||
*
|
||||
* @param editDTO 机构中介编辑DTO
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int updateEntityIntermediary(CcdiIntermediaryEntityEditDTO editDTO) {
|
||||
CcdiIntermediaryBlacklist intermediary = new CcdiIntermediaryBlacklist();
|
||||
BeanUtils.copyProperties(editDTO, intermediary);
|
||||
// 设置中介类型为机构
|
||||
intermediary.setIntermediaryType("2");
|
||||
// 清空个人专属字段
|
||||
clearPersonFields(intermediary);
|
||||
return intermediaryMapper.updateById(intermediary);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空个人专属字段
|
||||
*/
|
||||
private void clearPersonFields(CcdiIntermediaryBlacklist intermediary) {
|
||||
intermediary.setIndivType(null);
|
||||
intermediary.setIndivSubType(null);
|
||||
intermediary.setIndivGender(null);
|
||||
intermediary.setIndivCertType(null);
|
||||
intermediary.setIndivPhone(null);
|
||||
intermediary.setIndivWechat(null);
|
||||
intermediary.setIndivAddress(null);
|
||||
intermediary.setIndivCompany(null);
|
||||
intermediary.setIndivPosition(null);
|
||||
intermediary.setIndivRelatedId(null);
|
||||
intermediary.setIndivRelation(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空机构专属字段
|
||||
*/
|
||||
private void clearEntityFields(CcdiIntermediaryBlacklist intermediary) {
|
||||
intermediary.setCorpCreditCode(null);
|
||||
intermediary.setCorpType(null);
|
||||
intermediary.setCorpNature(null);
|
||||
intermediary.setCorpIndustryCategory(null);
|
||||
intermediary.setCorpIndustry(null);
|
||||
intermediary.setCorpEstablishDate(null);
|
||||
intermediary.setCorpAddress(null);
|
||||
intermediary.setCorpLegalRep(null);
|
||||
intermediary.setCorpLegalCertType(null);
|
||||
intermediary.setCorpLegalCertNo(null);
|
||||
intermediary.setCorpShareholder1(null);
|
||||
intermediary.setCorpShareholder2(null);
|
||||
intermediary.setCorpShareholder3(null);
|
||||
intermediary.setCorpShareholder4(null);
|
||||
intermediary.setCorpShareholder5(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除中介黑名单
|
||||
*
|
||||
* @param intermediaryIds 需要删除的中介ID
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int deleteIntermediaryByIds(Long[] intermediaryIds) {
|
||||
return intermediaryMapper.deleteBatchIds(List.of(intermediaryIds));
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入中介黑名单数据
|
||||
*
|
||||
* @param excelList Excel实体列表
|
||||
* @param isUpdateSupport 是否更新支持
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public String importIntermediary(List<CcdiIntermediaryBlacklistExcel> excelList, Boolean isUpdateSupport) {
|
||||
if (excelList == null || excelList.isEmpty()) {
|
||||
return "至少需要一条数据";
|
||||
}
|
||||
|
||||
int successNum = 0;
|
||||
int failureNum = 0;
|
||||
StringBuilder successMsg = new StringBuilder();
|
||||
StringBuilder failureMsg = new StringBuilder();
|
||||
|
||||
for (CcdiIntermediaryBlacklistExcel excel : excelList) {
|
||||
try {
|
||||
// 转换为AddDTO
|
||||
CcdiIntermediaryBlacklistAddDTO addDTO = new CcdiIntermediaryBlacklistAddDTO();
|
||||
BeanUtils.copyProperties(excel, addDTO);
|
||||
|
||||
// 验证数据
|
||||
validateIntermediaryData(addDTO);
|
||||
|
||||
CcdiIntermediaryBlacklist intermediary = new CcdiIntermediaryBlacklist();
|
||||
BeanUtils.copyProperties(addDTO, intermediary);
|
||||
|
||||
intermediaryMapper.insert(intermediary);
|
||||
successNum++;
|
||||
successMsg.append("<br/>").append(successNum).append("、").append(addDTO.getName()).append(" 导入成功");
|
||||
} catch (Exception e) {
|
||||
failureNum++;
|
||||
failureMsg.append("<br/>").append(failureNum).append("、").append(excel.getName()).append(" 导入失败:");
|
||||
failureMsg.append(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
if (failureNum > 0) {
|
||||
failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:");
|
||||
throw new RuntimeException(failureMsg.toString());
|
||||
} else {
|
||||
successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条");
|
||||
return successMsg.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据中介类型获取详情(返回不同类型)
|
||||
*
|
||||
* @param intermediaryId 中介ID
|
||||
* @return 个人返回 CcdiIntermediaryPersonDetailVO,机构返回 CcdiIntermediaryEntityDetailVO
|
||||
*/
|
||||
@Override
|
||||
public Object selectIntermediaryDetailById(Long intermediaryId) {
|
||||
CcdiIntermediaryBlacklist intermediary = intermediaryMapper.selectById(intermediaryId);
|
||||
if (intermediary == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 根据中介类型返回不同的 VO
|
||||
if ("1".equals(intermediary.getIntermediaryType())) {
|
||||
// 个人类型
|
||||
return convertToPersonDetailVO(intermediary);
|
||||
} else {
|
||||
// 机构类型
|
||||
return convertToEntityDetailVO(intermediary);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入个人中介数据(批量插入优化版)
|
||||
*
|
||||
* @param excelList Excel实体列表
|
||||
* @param isUpdateSupport 是否更新支持
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public String importPersonIntermediary(List<CcdiIntermediaryPersonExcel> excelList, Boolean isUpdateSupport) {
|
||||
if (excelList == null || excelList.isEmpty()) {
|
||||
return "至少需要一条数据";
|
||||
}
|
||||
|
||||
// 批量处理:先验证所有数据
|
||||
List<CcdiIntermediaryBlacklist> toInsertList = new ArrayList<>();
|
||||
List<CcdiIntermediaryBlacklist> toUpdateList = new ArrayList<>();
|
||||
List<String> errorMessages = new ArrayList<>();
|
||||
|
||||
// 批量查询已存在的记录(用于唯一性校验或更新支持)
|
||||
Set<String> existingCertNos = new HashSet<>();
|
||||
Map<String, Long> certNoToIdMap = new HashMap<>();
|
||||
for (CcdiIntermediaryPersonExcel excel : excelList) {
|
||||
if (StringUtils.isNotEmpty(excel.getCertificateNo())) {
|
||||
existingCertNos.add(excel.getCertificateNo());
|
||||
}
|
||||
}
|
||||
if (!existingCertNos.isEmpty()) {
|
||||
LambdaQueryWrapper<CcdiIntermediaryBlacklist> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(CcdiIntermediaryBlacklist::getIntermediaryType, "1")
|
||||
.in(CcdiIntermediaryBlacklist::getCertificateNo, existingCertNos)
|
||||
.select(CcdiIntermediaryBlacklist::getIntermediaryId, CcdiIntermediaryBlacklist::getCertificateNo);
|
||||
List<CcdiIntermediaryBlacklist> existingList = intermediaryMapper.selectList(wrapper);
|
||||
for (CcdiIntermediaryBlacklist existing : existingList) {
|
||||
certNoToIdMap.put(existing.getCertificateNo(), existing.getIntermediaryId());
|
||||
}
|
||||
}
|
||||
|
||||
// 如果不是更新模式,先进行唯一性校验
|
||||
if (!isUpdateSupport) {
|
||||
for (CcdiIntermediaryPersonExcel excel : excelList) {
|
||||
if (StringUtils.isNotEmpty(excel.getCertificateNo()) && certNoToIdMap.containsKey(excel.getCertificateNo())) {
|
||||
throw new RuntimeException("证件号 " + excel.getCertificateNo() + " 已存在,请勿重复导入");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理每条数据
|
||||
for (int i = 0; i < excelList.size(); i++) {
|
||||
CcdiIntermediaryPersonExcel excel = excelList.get(i);
|
||||
try {
|
||||
// 验证数据
|
||||
validatePersonIntermediaryData(excel);
|
||||
|
||||
// 转换为实体
|
||||
CcdiIntermediaryBlacklist intermediary = new CcdiIntermediaryBlacklist();
|
||||
intermediary.setName(excel.getName());
|
||||
intermediary.setCertificateNo(excel.getCertificateNo());
|
||||
intermediary.setIntermediaryType("1");
|
||||
intermediary.setStatus("0");
|
||||
intermediary.setDataSource("IMPORT");
|
||||
intermediary.setRemark(excel.getRemark());
|
||||
|
||||
// 个人专属字段
|
||||
intermediary.setIndivType(excel.getIndivType());
|
||||
intermediary.setIndivSubType(excel.getIndivSubType());
|
||||
intermediary.setIndivGender(excel.getIndivGender());
|
||||
intermediary.setIndivCertType(StringUtils.isNotEmpty(excel.getIndivCertType()) ? excel.getIndivCertType() : "身份证");
|
||||
intermediary.setIndivPhone(excel.getIndivPhone());
|
||||
intermediary.setIndivWechat(excel.getIndivWechat());
|
||||
intermediary.setIndivAddress(excel.getIndivAddress());
|
||||
intermediary.setIndivCompany(excel.getIndivCompany());
|
||||
intermediary.setIndivPosition(excel.getIndivPosition());
|
||||
intermediary.setIndivRelatedId(excel.getIndivRelatedId());
|
||||
intermediary.setIndivRelation(excel.getIndivRelation());
|
||||
|
||||
// 检查是否需要更新
|
||||
if (isUpdateSupport && StringUtils.isNotEmpty(excel.getCertificateNo()) && certNoToIdMap.containsKey(excel.getCertificateNo())) {
|
||||
intermediary.setIntermediaryId(certNoToIdMap.get(excel.getCertificateNo()));
|
||||
toUpdateList.add(intermediary);
|
||||
} else {
|
||||
toInsertList.add(intermediary);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
errorMessages.add("第" + (i + 1) + "行导入失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 批量执行数据库操作
|
||||
int successNum = 0;
|
||||
int failureNum = errorMessages.size();
|
||||
|
||||
// 批量插入
|
||||
if (!toInsertList.isEmpty()) {
|
||||
intermediaryMapper.batchInsert(toInsertList);
|
||||
successNum += toInsertList.size();
|
||||
}
|
||||
|
||||
// 批量更新
|
||||
if (!toUpdateList.isEmpty()) {
|
||||
intermediaryMapper.batchUpdate(toUpdateList);
|
||||
successNum += toUpdateList.size();
|
||||
}
|
||||
|
||||
// 构建失败消息
|
||||
StringBuilder failureMsg = new StringBuilder();
|
||||
for (String error : errorMessages) {
|
||||
failureMsg.append("<br/>").append(error);
|
||||
}
|
||||
|
||||
// 返回结果
|
||||
if (failureNum > 0) {
|
||||
failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:");
|
||||
throw new RuntimeException(failureMsg.toString());
|
||||
} else {
|
||||
return "恭喜您,数据已全部导入成功!共 " + successNum + " 条";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入机构中介数据(批量插入优化版)
|
||||
*
|
||||
* @param excelList Excel实体列表
|
||||
* @param isUpdateSupport 是否更新支持
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public String importEntityIntermediary(List<CcdiIntermediaryEntityExcel> excelList, Boolean isUpdateSupport) {
|
||||
if (excelList == null || excelList.isEmpty()) {
|
||||
return "至少需要一条数据";
|
||||
}
|
||||
|
||||
// 批量处理:先验证所有数据
|
||||
List<CcdiIntermediaryBlacklist> toInsertList = new ArrayList<>();
|
||||
List<CcdiIntermediaryBlacklist> toUpdateList = new ArrayList<>();
|
||||
List<String> errorMessages = new ArrayList<>();
|
||||
|
||||
// 批量查询已存在的记录(用于唯一性校验或更新支持)
|
||||
Set<String> existingCreditCodes = new HashSet<>();
|
||||
Map<String, Long> creditCodeToIdMap = new HashMap<>();
|
||||
for (CcdiIntermediaryEntityExcel excel : excelList) {
|
||||
if (StringUtils.isNotEmpty(excel.getCorpCreditCode())) {
|
||||
existingCreditCodes.add(excel.getCorpCreditCode());
|
||||
}
|
||||
}
|
||||
if (!existingCreditCodes.isEmpty()) {
|
||||
LambdaQueryWrapper<CcdiIntermediaryBlacklist> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(CcdiIntermediaryBlacklist::getIntermediaryType, "2")
|
||||
.in(CcdiIntermediaryBlacklist::getCorpCreditCode, existingCreditCodes)
|
||||
.select(CcdiIntermediaryBlacklist::getIntermediaryId, CcdiIntermediaryBlacklist::getCorpCreditCode);
|
||||
List<CcdiIntermediaryBlacklist> existingList = intermediaryMapper.selectList(wrapper);
|
||||
for (CcdiIntermediaryBlacklist existing : existingList) {
|
||||
creditCodeToIdMap.put(existing.getCorpCreditCode(), existing.getIntermediaryId());
|
||||
}
|
||||
}
|
||||
|
||||
// 如果不是更新模式,先进行唯一性校验
|
||||
if (!isUpdateSupport) {
|
||||
for (CcdiIntermediaryEntityExcel excel : excelList) {
|
||||
if (StringUtils.isNotEmpty(excel.getCorpCreditCode()) && creditCodeToIdMap.containsKey(excel.getCorpCreditCode())) {
|
||||
throw new RuntimeException("统一社会信用代码 " + excel.getCorpCreditCode() + " 已存在,请勿重复导入");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
||||
|
||||
// 处理每条数据
|
||||
for (int i = 0; i < excelList.size(); i++) {
|
||||
CcdiIntermediaryEntityExcel excel = excelList.get(i);
|
||||
try {
|
||||
// 验证数据
|
||||
validateEntityIntermediaryData(excel);
|
||||
|
||||
// 转换为实体
|
||||
CcdiIntermediaryBlacklist intermediary = new CcdiIntermediaryBlacklist();
|
||||
intermediary.setName(excel.getName());
|
||||
// 对于机构中介,使用统一社会信用代码作为证件号
|
||||
intermediary.setCertificateNo(excel.getCorpCreditCode());
|
||||
intermediary.setIntermediaryType("2");
|
||||
intermediary.setStatus("0");
|
||||
intermediary.setDataSource("IMPORT");
|
||||
intermediary.setRemark(excel.getRemark());
|
||||
|
||||
// 机构专属字段
|
||||
intermediary.setCorpCreditCode(excel.getCorpCreditCode());
|
||||
intermediary.setCorpType(excel.getCorpType());
|
||||
intermediary.setCorpNature(excel.getCorpNature());
|
||||
intermediary.setCorpIndustryCategory(excel.getCorpIndustryCategory());
|
||||
intermediary.setCorpIndustry(excel.getCorpIndustry());
|
||||
|
||||
// 解析成立日期
|
||||
if (StringUtils.isNotEmpty(excel.getCorpEstablishDate())) {
|
||||
try {
|
||||
intermediary.setCorpEstablishDate(sdf.parse(excel.getCorpEstablishDate()));
|
||||
} catch (Exception e) {
|
||||
// 忽略日期解析错误
|
||||
}
|
||||
}
|
||||
|
||||
intermediary.setCorpAddress(excel.getCorpAddress());
|
||||
intermediary.setCorpLegalRep(excel.getCorpLegalRep());
|
||||
intermediary.setCorpLegalCertType(excel.getCorpLegalCertType());
|
||||
intermediary.setCorpLegalCertNo(excel.getCorpLegalCertNo());
|
||||
intermediary.setCorpShareholder1(excel.getCorpShareholder1());
|
||||
intermediary.setCorpShareholder2(excel.getCorpShareholder2());
|
||||
intermediary.setCorpShareholder3(excel.getCorpShareholder3());
|
||||
intermediary.setCorpShareholder4(excel.getCorpShareholder4());
|
||||
intermediary.setCorpShareholder5(excel.getCorpShareholder5());
|
||||
|
||||
// 检查是否需要更新
|
||||
if (isUpdateSupport && StringUtils.isNotEmpty(excel.getCorpCreditCode()) && creditCodeToIdMap.containsKey(excel.getCorpCreditCode())) {
|
||||
intermediary.setIntermediaryId(creditCodeToIdMap.get(excel.getCorpCreditCode()));
|
||||
toUpdateList.add(intermediary);
|
||||
} else {
|
||||
toInsertList.add(intermediary);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
errorMessages.add("第" + (i + 1) + "行导入失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 批量执行数据库操作
|
||||
int successNum = 0;
|
||||
int failureNum = errorMessages.size();
|
||||
|
||||
// 批量插入
|
||||
if (!toInsertList.isEmpty()) {
|
||||
intermediaryMapper.batchInsert(toInsertList);
|
||||
successNum += toInsertList.size();
|
||||
}
|
||||
|
||||
// 批量更新
|
||||
if (!toUpdateList.isEmpty()) {
|
||||
intermediaryMapper.batchUpdate(toUpdateList);
|
||||
successNum += toUpdateList.size();
|
||||
}
|
||||
|
||||
// 构建失败消息
|
||||
StringBuilder failureMsg = new StringBuilder();
|
||||
for (String error : errorMessages) {
|
||||
failureMsg.append("<br/>").append(error);
|
||||
}
|
||||
|
||||
// 返回结果
|
||||
if (failureNum > 0) {
|
||||
failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:");
|
||||
throw new RuntimeException(failureMsg.toString());
|
||||
} else {
|
||||
return "恭喜您,数据已全部导入成功!共 " + successNum + " 条";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证个人中介数据
|
||||
*/
|
||||
private void validatePersonIntermediaryData(CcdiIntermediaryPersonExcel excel) {
|
||||
if (StringUtils.isEmpty(excel.getName())) {
|
||||
throw new RuntimeException("姓名不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(excel.getCertificateNo())) {
|
||||
throw new RuntimeException("证件号码不能为空");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证机构中介数据
|
||||
*/
|
||||
private void validateEntityIntermediaryData(CcdiIntermediaryEntityExcel excel) {
|
||||
if (StringUtils.isEmpty(excel.getName())) {
|
||||
throw new RuntimeException("机构名称不能为空");
|
||||
}
|
||||
// 验证统一社会信用代码不能为空(因为会用作 certificate_no 字段)
|
||||
if (StringUtils.isEmpty(excel.getCorpCreditCode())) {
|
||||
throw new RuntimeException("统一社会信用代码不能为空");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为个人详情 VO
|
||||
*/
|
||||
private CcdiIntermediaryPersonDetailVO convertToPersonDetailVO(CcdiIntermediaryBlacklist intermediary) {
|
||||
if (intermediary == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
CcdiIntermediaryPersonDetailVO vo = new CcdiIntermediaryPersonDetailVO();
|
||||
// 复制基础字段
|
||||
vo.setIntermediaryId(intermediary.getIntermediaryId());
|
||||
vo.setName(intermediary.getName());
|
||||
vo.setCertificateNo(intermediary.getCertificateNo());
|
||||
vo.setIntermediaryType(intermediary.getIntermediaryType());
|
||||
vo.setStatus(intermediary.getStatus());
|
||||
vo.setRemark(intermediary.getRemark());
|
||||
vo.setDataSource(intermediary.getDataSource());
|
||||
vo.setCreateBy(intermediary.getCreateBy());
|
||||
vo.setCreateTime(intermediary.getCreateTime());
|
||||
vo.setUpdateBy(intermediary.getUpdateBy());
|
||||
vo.setUpdateTime(intermediary.getUpdateTime());
|
||||
|
||||
// 复制个人专属字段
|
||||
vo.setIndivType(intermediary.getIndivType());
|
||||
vo.setIndivSubType(intermediary.getIndivSubType());
|
||||
vo.setIndivGender(intermediary.getIndivGender());
|
||||
vo.setIndivCertType(intermediary.getIndivCertType());
|
||||
vo.setIndivPhone(intermediary.getIndivPhone());
|
||||
vo.setIndivWechat(intermediary.getIndivWechat());
|
||||
vo.setIndivAddress(intermediary.getIndivAddress());
|
||||
vo.setIndivCompany(intermediary.getIndivCompany());
|
||||
vo.setIndivPosition(intermediary.getIndivPosition());
|
||||
vo.setIndivRelatedId(intermediary.getIndivRelatedId());
|
||||
vo.setIndivRelation(intermediary.getIndivRelation());
|
||||
|
||||
// 设置枚举类型的名称
|
||||
vo.setIntermediaryTypeName(IntermediaryType.PERSON.getDesc());
|
||||
vo.setStatusName(IntermediaryStatus.getDescByCode(intermediary.getStatus()));
|
||||
vo.setDataSourceName(DataSource.getDescByCode(intermediary.getDataSource()));
|
||||
vo.setIndivGenderName(Gender.getDescByCode(intermediary.getIndivGender()));
|
||||
|
||||
return vo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为机构详情 VO
|
||||
*/
|
||||
private CcdiIntermediaryEntityDetailVO convertToEntityDetailVO(CcdiIntermediaryBlacklist intermediary) {
|
||||
if (intermediary == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
CcdiIntermediaryEntityDetailVO vo = new CcdiIntermediaryEntityDetailVO();
|
||||
// 复制基础字段
|
||||
vo.setIntermediaryId(intermediary.getIntermediaryId());
|
||||
vo.setName(intermediary.getName());
|
||||
vo.setCertificateNo(intermediary.getCertificateNo());
|
||||
vo.setIntermediaryType(intermediary.getIntermediaryType());
|
||||
vo.setStatus(intermediary.getStatus());
|
||||
vo.setRemark(intermediary.getRemark());
|
||||
vo.setDataSource(intermediary.getDataSource());
|
||||
vo.setCreateBy(intermediary.getCreateBy());
|
||||
vo.setCreateTime(intermediary.getCreateTime());
|
||||
vo.setUpdateBy(intermediary.getUpdateBy());
|
||||
vo.setUpdateTime(intermediary.getUpdateTime());
|
||||
|
||||
// 复制机构专属字段
|
||||
vo.setCorpCreditCode(intermediary.getCorpCreditCode());
|
||||
vo.setCorpType(intermediary.getCorpType());
|
||||
vo.setCorpNature(intermediary.getCorpNature());
|
||||
vo.setCorpIndustryCategory(intermediary.getCorpIndustryCategory());
|
||||
vo.setCorpIndustry(intermediary.getCorpIndustry());
|
||||
vo.setCorpEstablishDate(intermediary.getCorpEstablishDate());
|
||||
vo.setCorpAddress(intermediary.getCorpAddress());
|
||||
vo.setCorpLegalRep(intermediary.getCorpLegalRep());
|
||||
vo.setCorpLegalCertType(intermediary.getCorpLegalCertType());
|
||||
vo.setCorpLegalCertNo(intermediary.getCorpLegalCertNo());
|
||||
vo.setCorpShareholder1(intermediary.getCorpShareholder1());
|
||||
vo.setCorpShareholder2(intermediary.getCorpShareholder2());
|
||||
vo.setCorpShareholder3(intermediary.getCorpShareholder3());
|
||||
vo.setCorpShareholder4(intermediary.getCorpShareholder4());
|
||||
vo.setCorpShareholder5(intermediary.getCorpShareholder5());
|
||||
|
||||
// 设置枚举类型的名称
|
||||
vo.setIntermediaryTypeName(IntermediaryType.ENTITY.getDesc());
|
||||
vo.setStatusName(IntermediaryStatus.getDescByCode(intermediary.getStatus()));
|
||||
vo.setDataSourceName(DataSource.getDescByCode(intermediary.getDataSource()));
|
||||
|
||||
return vo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建查询条件
|
||||
*/
|
||||
private LambdaQueryWrapper<CcdiIntermediaryBlacklist> buildQueryWrapper(CcdiIntermediaryBlacklistQueryDTO queryDTO) {
|
||||
LambdaQueryWrapper<CcdiIntermediaryBlacklist> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.like(StringUtils.isNotEmpty(queryDTO.getName()), CcdiIntermediaryBlacklist::getName, queryDTO.getName())
|
||||
.like(StringUtils.isNotEmpty(queryDTO.getCertificateNo()), CcdiIntermediaryBlacklist::getCertificateNo, queryDTO.getCertificateNo())
|
||||
.eq(StringUtils.isNotEmpty(queryDTO.getIntermediaryType()), CcdiIntermediaryBlacklist::getIntermediaryType, queryDTO.getIntermediaryType())
|
||||
.eq(StringUtils.isNotEmpty(queryDTO.getStatus()), CcdiIntermediaryBlacklist::getStatus, queryDTO.getStatus())
|
||||
.orderByDesc(CcdiIntermediaryBlacklist::getCreateTime);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证中介数据
|
||||
*/
|
||||
private void validateIntermediaryData(CcdiIntermediaryBlacklistAddDTO addDTO) {
|
||||
// 验证必填字段
|
||||
if (StringUtils.isEmpty(addDTO.getName())) {
|
||||
throw new RuntimeException("姓名/机构名称不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(addDTO.getIntermediaryType())) {
|
||||
throw new RuntimeException("中介类型不能为空");
|
||||
}
|
||||
|
||||
// 验证中介类型
|
||||
if (!"1".equals(addDTO.getIntermediaryType()) && !"2".equals(addDTO.getIntermediaryType())) {
|
||||
throw new RuntimeException("中介类型只能填写'个人'或'机构'");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为VO对象
|
||||
*/
|
||||
private CcdiIntermediaryBlacklistVO convertToVO(CcdiIntermediaryBlacklist intermediary) {
|
||||
if (intermediary == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
CcdiIntermediaryBlacklistVO vo = new CcdiIntermediaryBlacklistVO();
|
||||
BeanUtils.copyProperties(intermediary, vo);
|
||||
|
||||
vo.setIntermediaryTypeName(IntermediaryType.getDescByCode(intermediary.getIntermediaryType()));
|
||||
vo.setStatusName(IntermediaryStatus.getDescByCode(intermediary.getStatus()));
|
||||
|
||||
return vo;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
package com.ruoyi.ccdi.service.impl;
|
||||
|
||||
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.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.mapper.CcdiBizIntermediaryMapper;
|
||||
import com.ruoyi.ccdi.mapper.CcdiEnterpriseBaseInfoMapper;
|
||||
import com.ruoyi.ccdi.mapper.CcdiIntermediaryMapper;
|
||||
import com.ruoyi.ccdi.service.ICcdiIntermediaryService;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 中介Service业务层处理
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2026-02-04
|
||||
*/
|
||||
@Service
|
||||
public class CcdiIntermediaryServiceImpl implements ICcdiIntermediaryService {
|
||||
|
||||
@Resource
|
||||
private CcdiBizIntermediaryMapper bizIntermediaryMapper;
|
||||
|
||||
@Resource
|
||||
private CcdiEnterpriseBaseInfoMapper enterpriseBaseInfoMapper;
|
||||
|
||||
@Resource
|
||||
private CcdiIntermediaryMapper intermediaryMapper;
|
||||
|
||||
/**
|
||||
* 分页查询中介列表
|
||||
* 使用XML联合查询实现,支持个人中介和实体中介的灵活查询
|
||||
* 使用MyBatis Plus分页插件自动处理分页
|
||||
*
|
||||
* @param page 分页对象
|
||||
* @param queryDTO 查询条件
|
||||
* @return 中介VO分页结果
|
||||
*/
|
||||
@Override
|
||||
public Page<CcdiIntermediaryVO> selectIntermediaryPage(Page<CcdiIntermediaryVO> page, CcdiIntermediaryQueryDTO queryDTO) {
|
||||
// 直接调用Mapper的联合查询方法,MyBatis Plus会自动处理分页
|
||||
return intermediaryMapper.selectIntermediaryList(page, queryDTO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询个人中介详情
|
||||
*
|
||||
* @param bizId 人员ID
|
||||
* @return 个人中介详情VO
|
||||
*/
|
||||
@Override
|
||||
public CcdiIntermediaryPersonDetailVO selectIntermediaryPersonDetail(String bizId) {
|
||||
CcdiBizIntermediary person = bizIntermediaryMapper.selectById(bizId);
|
||||
if (person == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
CcdiIntermediaryPersonDetailVO vo = new CcdiIntermediaryPersonDetailVO();
|
||||
BeanUtils.copyProperties(person, vo);
|
||||
// 设置中介类型为个人
|
||||
vo.setIntermediaryType("1");
|
||||
return vo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询实体中介详情
|
||||
*
|
||||
* @param socialCreditCode 统一社会信用代码
|
||||
* @return 实体中介详情VO
|
||||
*/
|
||||
@Override
|
||||
public CcdiIntermediaryEntityDetailVO selectIntermediaryEntityDetail(String socialCreditCode) {
|
||||
CcdiEnterpriseBaseInfo entity = enterpriseBaseInfoMapper.selectById(socialCreditCode);
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
CcdiIntermediaryEntityDetailVO vo = new CcdiIntermediaryEntityDetailVO();
|
||||
BeanUtils.copyProperties(entity, vo);
|
||||
// 设置中介类型为实体
|
||||
vo.setIntermediaryType("2");
|
||||
// 设置业务ID(使用socialCreditCode作为bizId,前端判断是否为新增模式)
|
||||
vo.setBizId(socialCreditCode);
|
||||
return vo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增个人中介
|
||||
*
|
||||
* @param addDTO 新增DTO
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public int insertIntermediaryPerson(CcdiIntermediaryPersonAddDTO addDTO) {
|
||||
// 检查人员ID唯一性
|
||||
if (!checkPersonIdUnique(addDTO.getPersonId(), null)) {
|
||||
throw new RuntimeException("该证件号已存在");
|
||||
}
|
||||
|
||||
CcdiBizIntermediary person = new CcdiBizIntermediary();
|
||||
BeanUtils.copyProperties(addDTO, person);
|
||||
person.setDataSource("MANUAL");
|
||||
|
||||
return bizIntermediaryMapper.insert(person);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改个人中介
|
||||
*
|
||||
* @param editDTO 编辑DTO
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public int updateIntermediaryPerson(CcdiIntermediaryPersonEditDTO editDTO) {
|
||||
// 检查人员ID唯一性(排除自己)
|
||||
if (StringUtils.isNotEmpty(editDTO.getPersonId())) {
|
||||
if (!checkPersonIdUnique(editDTO.getPersonId(), editDTO.getBizId())) {
|
||||
throw new RuntimeException("该证件号已存在");
|
||||
}
|
||||
}
|
||||
|
||||
CcdiBizIntermediary person = new CcdiBizIntermediary();
|
||||
BeanUtils.copyProperties(editDTO, person);
|
||||
|
||||
return bizIntermediaryMapper.updateById(person);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增实体中介
|
||||
*
|
||||
* @param addDTO 新增DTO
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public int insertIntermediaryEntity(CcdiIntermediaryEntityAddDTO addDTO) {
|
||||
// 检查统一社会信用代码唯一性
|
||||
if (StringUtils.isNotEmpty(addDTO.getSocialCreditCode())) {
|
||||
if (!checkSocialCreditCodeUnique(addDTO.getSocialCreditCode(), null)) {
|
||||
throw new RuntimeException("该统一社会信用代码已存在");
|
||||
}
|
||||
}
|
||||
|
||||
CcdiEnterpriseBaseInfo entity = new CcdiEnterpriseBaseInfo();
|
||||
BeanUtils.copyProperties(addDTO, entity);
|
||||
entity.setRiskLevel("1");
|
||||
entity.setEntSource("INTERMEDIARY");
|
||||
entity.setDataSource("MANUAL");
|
||||
|
||||
return enterpriseBaseInfoMapper.insert(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改实体中介
|
||||
*
|
||||
* @param editDTO 编辑DTO
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public int updateIntermediaryEntity(CcdiIntermediaryEntityEditDTO editDTO) {
|
||||
CcdiEnterpriseBaseInfo entity = new CcdiEnterpriseBaseInfo();
|
||||
BeanUtils.copyProperties(editDTO, entity);
|
||||
|
||||
return enterpriseBaseInfoMapper.updateById(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除中介
|
||||
*
|
||||
* @param ids 需要删除的ID数组
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public int deleteIntermediaryByIds(String[] ids) {
|
||||
int count = 0;
|
||||
for (String id : ids) {
|
||||
// 判断是个人还是实体(个人ID长度较长,实体统一社会信用代码18位)
|
||||
if (id.length() > 18) {
|
||||
// 个人中介
|
||||
count += bizIntermediaryMapper.deleteById(id);
|
||||
} else {
|
||||
// 实体中介
|
||||
count += enterpriseBaseInfoMapper.deleteById(id);
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验人员ID唯一性
|
||||
*
|
||||
* @param personId 人员ID
|
||||
* @param bizId 排除的人员ID
|
||||
* @return true=唯一, false=不唯一
|
||||
*/
|
||||
@Override
|
||||
public boolean checkPersonIdUnique(String personId, String bizId) {
|
||||
LambdaQueryWrapper<CcdiBizIntermediary> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(CcdiBizIntermediary::getPersonId, personId);
|
||||
if (StringUtils.isNotEmpty(bizId)) {
|
||||
wrapper.ne(CcdiBizIntermediary::getBizId, bizId);
|
||||
}
|
||||
return bizIntermediaryMapper.selectCount(wrapper) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验统一社会信用代码唯一性
|
||||
*
|
||||
* @param socialCreditCode 统一社会信用代码
|
||||
* @param excludeId 排除的ID
|
||||
* @return true=唯一, false=不唯一
|
||||
*/
|
||||
@Override
|
||||
public boolean checkSocialCreditCodeUnique(String socialCreditCode, String excludeId) {
|
||||
LambdaQueryWrapper<CcdiEnterpriseBaseInfo> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(CcdiEnterpriseBaseInfo::getSocialCreditCode, socialCreditCode);
|
||||
if (StringUtils.isNotEmpty(excludeId)) {
|
||||
wrapper.ne(CcdiEnterpriseBaseInfo::getSocialCreditCode, excludeId);
|
||||
}
|
||||
return enterpriseBaseInfoMapper.selectCount(wrapper) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入个人中介数据(批量操作)
|
||||
* 优化:使用批量查询替代循环中的单条查询,减少数据库交互次数
|
||||
*
|
||||
* @param list Excel实体列表
|
||||
* @param updateSupport 是否更新支持
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public String importIntermediaryPerson(List<CcdiIntermediaryPersonExcel> list, boolean updateSupport) {
|
||||
if (StringUtils.isNull(list) || list.isEmpty()) {
|
||||
return "至少需要一条数据";
|
||||
}
|
||||
|
||||
int successNum = 0;
|
||||
int failureNum = 0;
|
||||
StringBuilder successMsg = new StringBuilder();
|
||||
StringBuilder failureMsg = new StringBuilder();
|
||||
|
||||
// 待插入和更新的列表
|
||||
List<CcdiBizIntermediary> insertList = new ArrayList<>();
|
||||
List<CcdiBizIntermediary> updateList = new ArrayList<>();
|
||||
List<String> personIds = new ArrayList<>();
|
||||
|
||||
// 第一轮:收集所有personId
|
||||
for (CcdiIntermediaryPersonExcel excel : list) {
|
||||
if (StringUtils.isNotEmpty(excel.getPersonId())) {
|
||||
personIds.add(excel.getPersonId());
|
||||
}
|
||||
}
|
||||
|
||||
// 第二轮:批量查询已存在的记录(一次查询替代N次查询)
|
||||
java.util.Map<String, String> personIdToBizIdMap = new java.util.HashMap<>();
|
||||
if (!personIds.isEmpty()) {
|
||||
LambdaQueryWrapper<CcdiBizIntermediary> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.select(CcdiBizIntermediary::getBizId, CcdiBizIntermediary::getPersonId);
|
||||
wrapper.in(CcdiBizIntermediary::getPersonId, personIds);
|
||||
List<CcdiBizIntermediary> existingList = bizIntermediaryMapper.selectList(wrapper);
|
||||
|
||||
// 建立personId到bizId的映射
|
||||
for (CcdiBizIntermediary existing : existingList) {
|
||||
personIdToBizIdMap.put(existing.getPersonId(), existing.getBizId());
|
||||
}
|
||||
}
|
||||
|
||||
// 第三轮:数据验证和分类(使用Map进行快速判断,避免重复查询)
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
try {
|
||||
CcdiIntermediaryPersonExcel excel = list.get(i);
|
||||
|
||||
// 验证数据
|
||||
if (StringUtils.isEmpty(excel.getName())) {
|
||||
throw new RuntimeException("姓名不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(excel.getPersonId())) {
|
||||
throw new RuntimeException("证件号码不能为空");
|
||||
}
|
||||
|
||||
// 转换为实体
|
||||
CcdiBizIntermediary person = new CcdiBizIntermediary();
|
||||
BeanUtils.copyProperties(excel, person);
|
||||
person.setPersonType("中介");
|
||||
person.setDataSource("IMPORT");
|
||||
|
||||
// 使用Map快速判断是否存在
|
||||
String existingBizId = personIdToBizIdMap.get(excel.getPersonId());
|
||||
if (existingBizId != null) {
|
||||
// 记录已存在
|
||||
if (updateSupport) {
|
||||
// 需要更新,设置bizId
|
||||
person.setBizId(existingBizId);
|
||||
updateList.add(person);
|
||||
} else {
|
||||
throw new RuntimeException("该证件号已存在");
|
||||
}
|
||||
} else {
|
||||
// 新数据,加入插入列表
|
||||
insertList.add(person);
|
||||
}
|
||||
|
||||
successNum++;
|
||||
successMsg.append("<br/>").append(successNum).append("、").append(excel.getName()).append(" 导入成功");
|
||||
} catch (Exception e) {
|
||||
failureNum++;
|
||||
failureMsg.append("<br/>").append(failureNum).append("、").append(list.get(i).getName()).append(" 导入失败:");
|
||||
failureMsg.append(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 构建返回消息
|
||||
StringBuilder resultMsg = new StringBuilder();
|
||||
|
||||
if (failureNum > 0) {
|
||||
resultMsg.append("很抱歉,导入失败!共 ").append(failureNum).append(" 条数据格式不正确,错误如下:");
|
||||
resultMsg.append(failureMsg);
|
||||
}
|
||||
|
||||
// 第四轮:批量处理
|
||||
try {
|
||||
// 批量插入新记录
|
||||
if (!insertList.isEmpty()) {
|
||||
bizIntermediaryMapper.insertBatch(insertList);
|
||||
}
|
||||
|
||||
// 批量更新已存在的记录
|
||||
if (!updateList.isEmpty()) {
|
||||
bizIntermediaryMapper.updateBatch(updateList);
|
||||
}
|
||||
|
||||
// 只在有失败的情况下才返回成功信息,否则返回简洁的成功消息
|
||||
if (failureNum > 0) {
|
||||
resultMsg.append("<br/><br/>成功导入 ").append(successNum).append(" 条数据");
|
||||
} else {
|
||||
resultMsg.append("恭喜您,数据已全部导入成功!共 ").append(successNum).append(" 条");
|
||||
}
|
||||
return resultMsg.toString();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("批量操作失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入实体中介数据(批量操作)
|
||||
* 优化:使用批量查询替代循环中的单条查询,减少数据库交互次数
|
||||
*
|
||||
* @param list Excel实体列表
|
||||
* @param updateSupport 是否更新支持
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public String importIntermediaryEntity(List<CcdiIntermediaryEntityExcel> list, boolean updateSupport) {
|
||||
if (StringUtils.isNull(list) || list.isEmpty()) {
|
||||
return "至少需要一条数据";
|
||||
}
|
||||
|
||||
int successNum = 0;
|
||||
int failureNum = 0;
|
||||
StringBuilder successMsg = new StringBuilder();
|
||||
StringBuilder failureMsg = new StringBuilder();
|
||||
|
||||
// 待插入和更新的列表
|
||||
List<CcdiEnterpriseBaseInfo> insertList = new ArrayList<>();
|
||||
List<CcdiEnterpriseBaseInfo> updateList = new ArrayList<>();
|
||||
List<String> socialCreditCodes = new ArrayList<>();
|
||||
|
||||
// 第一轮:收集所有socialCreditCode
|
||||
for (CcdiIntermediaryEntityExcel excel : list) {
|
||||
if (StringUtils.isNotEmpty(excel.getSocialCreditCode())) {
|
||||
socialCreditCodes.add(excel.getSocialCreditCode());
|
||||
}
|
||||
}
|
||||
|
||||
// 第二轮:批量查询已存在的记录(一次查询替代N次查询)
|
||||
java.util.Map<String, CcdiEnterpriseBaseInfo> existingEntityMap = new java.util.HashMap<>();
|
||||
if (!socialCreditCodes.isEmpty()) {
|
||||
LambdaQueryWrapper<CcdiEnterpriseBaseInfo> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.in(CcdiEnterpriseBaseInfo::getSocialCreditCode, socialCreditCodes);
|
||||
List<CcdiEnterpriseBaseInfo> existingList = enterpriseBaseInfoMapper.selectList(wrapper);
|
||||
|
||||
// 建立socialCreditCode到实体的映射
|
||||
for (CcdiEnterpriseBaseInfo existing : existingList) {
|
||||
existingEntityMap.put(existing.getSocialCreditCode(), existing);
|
||||
}
|
||||
}
|
||||
|
||||
// 第三轮:数据验证和分类(使用Map进行快速判断,避免重复查询)
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
try {
|
||||
CcdiIntermediaryEntityExcel excel = list.get(i);
|
||||
|
||||
// 验证数据
|
||||
if (StringUtils.isEmpty(excel.getEnterpriseName())) {
|
||||
throw new RuntimeException("机构名称不能为空");
|
||||
}
|
||||
|
||||
// 转换为实体
|
||||
CcdiEnterpriseBaseInfo entity = new CcdiEnterpriseBaseInfo();
|
||||
BeanUtils.copyProperties(excel, entity);
|
||||
entity.setRiskLevel("1");
|
||||
entity.setEntSource("INTERMEDIARY");
|
||||
entity.setDataSource("IMPORT");
|
||||
|
||||
// 使用Map快速判断是否存在
|
||||
if (StringUtils.isNotEmpty(excel.getSocialCreditCode())) {
|
||||
CcdiEnterpriseBaseInfo existingEntity = existingEntityMap.get(excel.getSocialCreditCode());
|
||||
if (existingEntity != null) {
|
||||
// 记录已存在
|
||||
if (updateSupport) {
|
||||
// 需要更新,直接使用socialCreditCode作为主键
|
||||
updateList.add(entity);
|
||||
} else {
|
||||
throw new RuntimeException("该统一社会信用代码已存在");
|
||||
}
|
||||
} else {
|
||||
// 新数据,加入插入列表
|
||||
insertList.add(entity);
|
||||
}
|
||||
} else {
|
||||
// 没有统一社会信用代码,直接加入插入列表
|
||||
insertList.add(entity);
|
||||
}
|
||||
|
||||
successNum++;
|
||||
successMsg.append("<br/>").append(successNum).append("、").append(excel.getEnterpriseName()).append(" 导入成功");
|
||||
} catch (Exception e) {
|
||||
failureNum++;
|
||||
failureMsg.append("<br/>").append(failureNum).append("、").append(list.get(i).getEnterpriseName()).append(" 导入失败:");
|
||||
failureMsg.append(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 构建返回消息
|
||||
StringBuilder resultMsg = new StringBuilder();
|
||||
|
||||
if (failureNum > 0) {
|
||||
resultMsg.append("很抱歉,导入失败!共 ").append(failureNum).append(" 条数据格式不正确,错误如下:");
|
||||
resultMsg.append(failureMsg);
|
||||
}
|
||||
|
||||
// 第四轮:批量处理
|
||||
try {
|
||||
// 批量插入新记录
|
||||
if (!insertList.isEmpty()) {
|
||||
enterpriseBaseInfoMapper.insertBatch(insertList);
|
||||
}
|
||||
|
||||
// 批量更新已存在的记录
|
||||
if (!updateList.isEmpty()) {
|
||||
enterpriseBaseInfoMapper.updateBatch(updateList);
|
||||
}
|
||||
|
||||
// 只在有失败的情况下才返回成功信息,否则返回简洁的成功消息
|
||||
if (failureNum > 0) {
|
||||
resultMsg.append("<br/><br/>成功导入 ").append(successNum).append(" 条数据");
|
||||
} else {
|
||||
resultMsg.append("恭喜您,数据已全部导入成功!共 ").append(successNum).append(" 条");
|
||||
}
|
||||
return resultMsg.toString();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("批量操作失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
package com.ruoyi.ccdi.utils.converter;
|
||||
|
||||
import com.alibaba.excel.converters.Converter;
|
||||
import com.alibaba.excel.enums.CellDataTypeEnum;
|
||||
import com.alibaba.excel.metadata.GlobalConfiguration;
|
||||
import com.alibaba.excel.metadata.data.ReadCellData;
|
||||
import com.alibaba.excel.metadata.data.WriteCellData;
|
||||
import com.alibaba.excel.metadata.property.ExcelContentProperty;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 员工状态转换器
|
||||
* 0=在职, 1=离职
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class EmployeeStatusConverter implements Converter<String> {
|
||||
|
||||
private static final Map<String, String> CODE_TO_DESC = new HashMap<>();
|
||||
private static final Map<String, String> DESC_TO_CODE = new HashMap<>();
|
||||
|
||||
static {
|
||||
CODE_TO_DESC.put("0", "在职");
|
||||
CODE_TO_DESC.put("1", "离职");
|
||||
DESC_TO_CODE.put("在职", "0");
|
||||
DESC_TO_CODE.put("离职", "1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> supportJavaTypeKey() {
|
||||
return String.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CellDataTypeEnum supportExcelTypeKey() {
|
||||
return CellDataTypeEnum.STRING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty,
|
||||
GlobalConfiguration globalConfiguration) {
|
||||
String value = cellData.getStringValue();
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
// 支持中文和代码两种格式
|
||||
if (DESC_TO_CODE.containsKey(value)) {
|
||||
return DESC_TO_CODE.get(value);
|
||||
}
|
||||
// 如果是纯数字,直接返回
|
||||
if (value.matches("\\d")) {
|
||||
return value;
|
||||
}
|
||||
throw new IllegalArgumentException("无效的员工状态: " + value + ", 请使用: 在职/离职 或 0/1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public WriteCellData<?> convertToExcelData(String value, ExcelContentProperty contentProperty,
|
||||
GlobalConfiguration globalConfiguration) {
|
||||
String desc = CODE_TO_DESC.getOrDefault(value, value);
|
||||
return new WriteCellData<>(desc);
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package com.ruoyi.ccdi.utils.handler;
|
||||
|
||||
import com.alibaba.excel.write.handler.SheetWriteHandler;
|
||||
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
|
||||
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
|
||||
import org.apache.poi.ss.usermodel.DataValidation;
|
||||
import org.apache.poi.ss.usermodel.DataValidationHelper;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.apache.poi.ss.util.CellRangeAddressList;
|
||||
|
||||
/**
|
||||
* 员工状态下拉框处理器
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class EmployeeStatusSheetWriteHandler implements SheetWriteHandler {
|
||||
|
||||
@Override
|
||||
public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
|
||||
Sheet sheet = writeSheetHolder.getSheet();
|
||||
Workbook workbook = writeWorkbookHolder.getWorkbook();
|
||||
DataValidationHelper helper = sheet.getDataValidationHelper();
|
||||
|
||||
// 创建下拉框数据列表
|
||||
String[] statusList = {"在职", "离职"};
|
||||
|
||||
// 设置状态下拉框,从第2行开始(第1行是表头),第7列(状态列,索引为6)
|
||||
CellRangeAddressList addressList = new CellRangeAddressList(1, 10000, 6, 6);
|
||||
|
||||
// 创建显式列表约束
|
||||
DataValidation validation = helper.createValidation(
|
||||
helper.createExplicitListConstraint(statusList),
|
||||
addressList
|
||||
);
|
||||
|
||||
// 设置提示信息
|
||||
validation.createPromptBox("状态选择", "请选择员工状态:在职或离职");
|
||||
validation.setShowPromptBox(true);
|
||||
|
||||
// 设置错误提示
|
||||
validation.createErrorBox("状态错误", "请从下拉框中选择有效的状态值!");
|
||||
validation.setShowErrorBox(true);
|
||||
|
||||
sheet.addValidationData(validation);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?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">
|
||||
|
||||
<!-- 批量插入个人中介 -->
|
||||
<insert id="insertBatch" parameterType="java.util.List">
|
||||
INSERT INTO ccdi_biz_intermediary (
|
||||
biz_id, person_type, person_sub_type, relation_type,
|
||||
name, gender, id_type, person_id, mobile, wechat_no,
|
||||
contact_address, company, social_credit_code, position,
|
||||
related_num_id, data_source, remark,
|
||||
created_by, updated_by, create_time, update_time
|
||||
) VALUES
|
||||
<foreach collection="list" item="item" separator=",">
|
||||
(
|
||||
#{item.bizId}, #{item.personType}, #{item.personSubType}, #{item.relationType},
|
||||
#{item.name}, #{item.gender}, #{item.idType}, #{item.personId}, #{item.mobile}, #{item.wechatNo},
|
||||
#{item.contactAddress}, #{item.company}, #{item.socialCreditCode}, #{item.position},
|
||||
#{item.relatedNumId}, #{item.dataSource}, #{item.remark},
|
||||
#{item.createdBy}, #{item.updatedBy}, #{item.createTime}, #{item.updateTime}
|
||||
)
|
||||
</foreach>
|
||||
</insert>
|
||||
|
||||
<!-- 批量更新个人中介 -->
|
||||
<update id="updateBatch" parameterType="java.util.List">
|
||||
<foreach collection="list" item="item" separator=";">
|
||||
UPDATE ccdi_biz_intermediary
|
||||
<set>
|
||||
<if test="item.personType != null">person_type = #{item.personType},</if>
|
||||
<if test="item.personSubType != null">person_sub_type = #{item.personSubType},</if>
|
||||
<if test="item.relationType != null">relation_type = #{item.relationType},</if>
|
||||
<if test="item.name != null and item.name != ''">name = #{item.name},</if>
|
||||
<if test="item.gender != null">gender = #{item.gender},</if>
|
||||
<if test="item.idType != null">id_type = #{item.idType},</if>
|
||||
<if test="item.personId != null and item.personId != ''">person_id = #{item.personId},</if>
|
||||
<if test="item.mobile != null">mobile = #{item.mobile},</if>
|
||||
<if test="item.wechatNo != null">wechat_no = #{item.wechatNo},</if>
|
||||
<if test="item.contactAddress != null">contact_address = #{item.contactAddress},</if>
|
||||
<if test="item.company != null">company = #{item.company},</if>
|
||||
<if test="item.socialCreditCode != null">social_credit_code = #{item.socialCreditCode},</if>
|
||||
<if test="item.position != null">position = #{item.position},</if>
|
||||
<if test="item.relatedNumId != null">related_num_id = #{item.relatedNumId},</if>
|
||||
<if test="item.dataSource != null">data_source = #{item.dataSource},</if>
|
||||
<if test="item.remark != null">remark = #{item.remark},</if>
|
||||
<if test="item.updatedBy != null">updated_by = #{item.updatedBy},</if>
|
||||
update_time = #{item.updateTime}
|
||||
</set>
|
||||
WHERE biz_id = #{item.bizId}
|
||||
</foreach>
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,60 @@
|
||||
<?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.CcdiEnterpriseBaseInfoMapper">
|
||||
|
||||
<!-- 批量插入实体中介 -->
|
||||
<insert id="insertBatch" parameterType="java.util.List">
|
||||
INSERT INTO ccdi_enterprise_base_info (
|
||||
social_credit_code, enterprise_name, enterprise_type, enterprise_nature,
|
||||
industry_class, industry_name, establish_date, register_address,
|
||||
legal_representative, legal_cert_type, legal_cert_no,
|
||||
shareholder1, shareholder2, shareholder3, shareholder4, shareholder5,
|
||||
status, risk_level, ent_source, data_source,
|
||||
created_by, updated_by, create_time, update_time
|
||||
) VALUES
|
||||
<foreach collection="list" item="item" separator=",">
|
||||
(
|
||||
#{item.socialCreditCode}, #{item.enterpriseName}, #{item.enterpriseType}, #{item.enterpriseNature},
|
||||
#{item.industryClass}, #{item.industryName}, #{item.establishDate}, #{item.registerAddress},
|
||||
#{item.legalRepresentative}, #{item.legalCertType}, #{item.legalCertNo},
|
||||
#{item.shareholder1}, #{item.shareholder2}, #{item.shareholder3}, #{item.shareholder4}, #{item.shareholder5},
|
||||
#{item.status}, #{item.riskLevel}, #{item.entSource}, #{item.dataSource},
|
||||
#{item.createdBy}, #{item.updatedBy}, #{item.createTime}, #{item.updateTime}
|
||||
)
|
||||
</foreach>
|
||||
</insert>
|
||||
|
||||
<!-- 批量更新实体中介 -->
|
||||
<update id="updateBatch" parameterType="java.util.List">
|
||||
<foreach collection="list" item="item" separator=";">
|
||||
UPDATE ccdi_enterprise_base_info
|
||||
<set>
|
||||
<if test="item.enterpriseName != null and item.enterpriseName != ''">enterprise_name = #{item.enterpriseName},</if>
|
||||
<if test="item.enterpriseType != null">enterprise_type = #{item.enterpriseType},</if>
|
||||
<if test="item.enterpriseNature != null">enterprise_nature = #{item.enterpriseNature},</if>
|
||||
<if test="item.industryClass != null">industry_class = #{item.industryClass},</if>
|
||||
<if test="item.industryName != null">industry_name = #{item.industryName},</if>
|
||||
<if test="item.establishDate != null">establish_date = #{item.establishDate},</if>
|
||||
<if test="item.registerAddress != null">register_address = #{item.registerAddress},</if>
|
||||
<if test="item.legalRepresentative != null">legal_representative = #{item.legalRepresentative},</if>
|
||||
<if test="item.legalCertType != null">legal_cert_type = #{item.legalCertType},</if>
|
||||
<if test="item.legalCertNo != null">legal_cert_no = #{item.legalCertNo},</if>
|
||||
<if test="item.shareholder1 != null">shareholder1 = #{item.shareholder1},</if>
|
||||
<if test="item.shareholder2 != null">shareholder2 = #{item.shareholder2},</if>
|
||||
<if test="item.shareholder3 != null">shareholder3 = #{item.shareholder3},</if>
|
||||
<if test="item.shareholder4 != null">shareholder4 = #{item.shareholder4},</if>
|
||||
<if test="item.shareholder5 != null">shareholder5 = #{item.shareholder5},</if>
|
||||
<if test="item.status != null">status = #{item.status},</if>
|
||||
<if test="item.riskLevel != null">risk_level = #{item.riskLevel},</if>
|
||||
<if test="item.entSource != null">ent_source = #{item.entSource},</if>
|
||||
<if test="item.dataSource != null">data_source = #{item.dataSource},</if>
|
||||
<if test="item.updatedBy != null">updated_by = #{item.updatedBy},</if>
|
||||
update_time = #{item.updateTime}
|
||||
</set>
|
||||
WHERE social_credit_code = #{item.socialCreditCode}
|
||||
</foreach>
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
@@ -1,134 +0,0 @@
|
||||
<?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.CcdiIntermediaryBlacklistMapper">
|
||||
|
||||
<!-- 批量插入中介黑名单数据 -->
|
||||
<insert id="batchInsert" parameterType="java.util.List">
|
||||
INSERT INTO ccdi_intermediary_blacklist (
|
||||
name,
|
||||
certificate_no,
|
||||
intermediary_type,
|
||||
status,
|
||||
remark,
|
||||
indiv_type,
|
||||
indiv_sub_type,
|
||||
indiv_gender,
|
||||
indiv_cert_type,
|
||||
indiv_phone,
|
||||
indiv_wechat,
|
||||
indiv_address,
|
||||
indiv_company,
|
||||
indiv_position,
|
||||
indiv_related_id,
|
||||
indiv_relation,
|
||||
corp_credit_code,
|
||||
corp_type,
|
||||
corp_nature,
|
||||
corp_industry_category,
|
||||
corp_industry,
|
||||
corp_establish_date,
|
||||
corp_address,
|
||||
corp_legal_rep,
|
||||
corp_legal_cert_type,
|
||||
corp_legal_cert_no,
|
||||
corp_shareholder_1,
|
||||
corp_shareholder_2,
|
||||
corp_shareholder_3,
|
||||
corp_shareholder_4,
|
||||
corp_shareholder_5,
|
||||
data_source,
|
||||
create_by,
|
||||
create_time,
|
||||
update_by,
|
||||
update_time
|
||||
) VALUES
|
||||
<foreach collection="list" item="item" separator=",">
|
||||
(
|
||||
#{item.name},
|
||||
#{item.certificateNo},
|
||||
#{item.intermediaryType},
|
||||
#{item.status},
|
||||
#{item.remark},
|
||||
#{item.indivType},
|
||||
#{item.indivSubType},
|
||||
#{item.indivGender},
|
||||
#{item.indivCertType},
|
||||
#{item.indivPhone},
|
||||
#{item.indivWechat},
|
||||
#{item.indivAddress},
|
||||
#{item.indivCompany},
|
||||
#{item.indivPosition},
|
||||
#{item.indivRelatedId},
|
||||
#{item.indivRelation},
|
||||
#{item.corpCreditCode},
|
||||
#{item.corpType},
|
||||
#{item.corpNature},
|
||||
#{item.corpIndustryCategory},
|
||||
#{item.corpIndustry},
|
||||
#{item.corpEstablishDate},
|
||||
#{item.corpAddress},
|
||||
#{item.corpLegalRep},
|
||||
#{item.corpLegalCertType},
|
||||
#{item.corpLegalCertNo},
|
||||
#{item.corpShareholder1},
|
||||
#{item.corpShareholder2},
|
||||
#{item.corpShareholder3},
|
||||
#{item.corpShareholder4},
|
||||
#{item.corpShareholder5},
|
||||
#{item.dataSource},
|
||||
#{item.createBy},
|
||||
#{item.createTime},
|
||||
#{item.updateBy},
|
||||
#{item.updateTime}
|
||||
)
|
||||
</foreach>
|
||||
</insert>
|
||||
|
||||
<!-- 批量更新中介黑名单数据 -->
|
||||
<update id="batchUpdate" parameterType="java.util.List">
|
||||
<foreach collection="list" item="item" separator=";">
|
||||
UPDATE ccdi_intermediary_blacklist
|
||||
<set>
|
||||
<if test="item.name != null">name = #{item.name},</if>
|
||||
<if test="item.certificateNo != null">certificate_no = #{item.certificateNo},</if>
|
||||
<if test="item.intermediaryType != null">intermediary_type = #{item.intermediaryType},</if>
|
||||
<if test="item.status != null">status = #{item.status},</if>
|
||||
<if test="item.remark != null">remark = #{item.remark},</if>
|
||||
<if test="item.indivType != null">indiv_type = #{item.indivType},</if>
|
||||
<if test="item.indivSubType != null">indiv_sub_type = #{item.indivSubType},</if>
|
||||
<if test="item.indivGender != null">indiv_gender = #{item.indivGender},</if>
|
||||
<if test="item.indivCertType != null">indiv_cert_type = #{item.indivCertType},</if>
|
||||
<if test="item.indivPhone != null">indiv_phone = #{item.indivPhone},</if>
|
||||
<if test="item.indivWechat != null">indiv_wechat = #{item.indivWechat},</if>
|
||||
<if test="item.indivAddress != null">indiv_address = #{item.indivAddress},</if>
|
||||
<if test="item.indivCompany != null">indiv_company = #{item.indivCompany},</if>
|
||||
<if test="item.indivPosition != null">indiv_position = #{item.indivPosition},</if>
|
||||
<if test="item.indivRelatedId != null">indiv_related_id = #{item.indivRelatedId},</if>
|
||||
<if test="item.indivRelation != null">indiv_relation = #{item.indivRelation},</if>
|
||||
<if test="item.corpCreditCode != null">corp_credit_code = #{item.corpCreditCode},</if>
|
||||
<if test="item.corpType != null">corp_type = #{item.corpType},</if>
|
||||
<if test="item.corpNature != null">corp_nature = #{item.corpNature},</if>
|
||||
<if test="item.corpIndustryCategory != null">corp_industry_category = #{item.corpIndustryCategory},</if>
|
||||
<if test="item.corpIndustry != null">corp_industry = #{item.corpIndustry},</if>
|
||||
<if test="item.corpEstablishDate != null">corp_establish_date = #{item.corpEstablishDate},</if>
|
||||
<if test="item.corpAddress != null">corp_address = #{item.corpAddress},</if>
|
||||
<if test="item.corpLegalRep != null">corp_legal_rep = #{item.corpLegalRep},</if>
|
||||
<if test="item.corpLegalCertType != null">corp_legal_cert_type = #{item.corpLegalCertType},</if>
|
||||
<if test="item.corpLegalCertNo != null">corp_legal_cert_no = #{item.corpLegalCertNo},</if>
|
||||
<if test="item.corpShareholder1 != null">corp_shareholder_1 = #{item.corpShareholder1},</if>
|
||||
<if test="item.corpShareholder2 != null">corp_shareholder_2 = #{item.corpShareholder2},</if>
|
||||
<if test="item.corpShareholder3 != null">corp_shareholder_3 = #{item.corpShareholder3},</if>
|
||||
<if test="item.corpShareholder4 != null">corp_shareholder_4 = #{item.corpShareholder4},</if>
|
||||
<if test="item.corpShareholder5 != null">corp_shareholder_5 = #{item.corpShareholder5},</if>
|
||||
<if test="item.dataSource != null">data_source = #{item.dataSource},</if>
|
||||
<if test="item.certificateNo != null">certificate_no = #{item.certificateNo},</if>
|
||||
update_by = #{item.updateBy},
|
||||
update_time = #{item.updateTime}
|
||||
</set>
|
||||
WHERE intermediary_id = #{item.intermediaryId}
|
||||
</foreach>
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,60 @@
|
||||
<?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.CcdiIntermediaryMapper">
|
||||
|
||||
<!--
|
||||
中介黑名单联合查询
|
||||
支持按中介类型筛选: 1=个人中介, 2=实体中介, null=全部
|
||||
使用MyBatis Plus分页插件自动处理分页
|
||||
-->
|
||||
<select id="selectIntermediaryList" resultType="com.ruoyi.ccdi.domain.vo.CcdiIntermediaryVO">
|
||||
SELECT * FROM (
|
||||
<!-- 查询个人中介 -->
|
||||
SELECT
|
||||
biz_id as id,
|
||||
name,
|
||||
person_id as certificate_no,
|
||||
'1' as intermediary_type,
|
||||
person_type,
|
||||
company,
|
||||
data_source,
|
||||
create_time,
|
||||
update_time
|
||||
FROM ccdi_biz_intermediary
|
||||
|
||||
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,
|
||||
update_time
|
||||
FROM ccdi_enterprise_base_info
|
||||
WHERE risk_level = '1' AND ent_source = 'INTERMEDIARY'
|
||||
) 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 update_time DESC
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -1,5 +1,5 @@
|
||||
# 页面标题
|
||||
VUE_APP_TITLE = 若依管理系统
|
||||
VUE_APP_TITLE = 纪检初核系统
|
||||
|
||||
# 开发环境配置
|
||||
ENV = 'development'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# 页面标题
|
||||
VUE_APP_TITLE = 若依管理系统
|
||||
VUE_APP_TITLE = 纪检初核系统
|
||||
|
||||
# 生产环境配置
|
||||
ENV = 'production'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# 页面标题
|
||||
VUE_APP_TITLE = 若依管理系统
|
||||
VUE_APP_TITLE = 纪检初核系统
|
||||
|
||||
BABEL_ENV = production
|
||||
|
||||
|
||||
@@ -10,16 +10,6 @@ export function getIndivTypeOptions() {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询人员子类型选项
|
||||
*/
|
||||
export function getIndivSubTypeOptions() {
|
||||
return request({
|
||||
url: '/ccdi/enum/indivSubType',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询性别选项
|
||||
*/
|
||||
|
||||
@@ -9,20 +9,19 @@ export function listIntermediary(query) {
|
||||
})
|
||||
}
|
||||
|
||||
// 查询中介黑名单详细
|
||||
export function getIntermediary(intermediaryId) {
|
||||
// 查询个人中介详细
|
||||
export function getPersonIntermediary(bizId) {
|
||||
return request({
|
||||
url: '/ccdi/intermediary/' + intermediaryId,
|
||||
url: '/ccdi/intermediary/person/' + bizId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增中介黑名单
|
||||
export function addIntermediary(data) {
|
||||
// 查询实体中介详细
|
||||
export function getEntityIntermediary(socialCreditCode) {
|
||||
return request({
|
||||
url: '/ccdi/intermediary',
|
||||
method: 'post',
|
||||
data: data
|
||||
url: '/ccdi/intermediary/entity/' + socialCreditCode,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -4,11 +4,10 @@
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="姓名/机构名称" align="center" prop="name" :show-overflow-tooltip="true"/>
|
||||
<el-table-column label="证件号" align="center" prop="certificateNo" :show-overflow-tooltip="true"/>
|
||||
<el-table-column label="中介类型" align="center" prop="intermediaryTypeName" width="100"/>
|
||||
<el-table-column label="状态" align="center" prop="status" width="100">
|
||||
<el-table-column label="中介类型" align="center" prop="intermediaryType" width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-tag v-if="scope.row.status === '0'" type="success">正常</el-tag>
|
||||
<el-tag v-else type="danger">停用</el-tag>
|
||||
<span v-if="scope.row.intermediaryType === '1'">个人</span>
|
||||
<span v-else-if="scope.row.intermediaryType === '2'">实体</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
||||
|
||||
@@ -2,54 +2,67 @@
|
||||
<el-dialog title="中介黑名单详情" :visible.sync="visible" width="800px" append-to-body>
|
||||
<el-descriptions :column="2" border>
|
||||
<!-- 核心字段 -->
|
||||
<el-descriptions-item label="中介ID">{{ detailData.intermediaryId }}</el-descriptions-item>
|
||||
<el-descriptions-item label="中介类型">{{ detailData.intermediaryTypeName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="姓名/机构名称">{{ detailData.name }}</el-descriptions-item>
|
||||
<el-descriptions-item label="证件号/信用代码">{{ detailData.certificateNo || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="状态">
|
||||
<el-tag v-if="detailData.status === '0'" type="success">正常</el-tag>
|
||||
<el-tag v-else type="danger">停用</el-tag>
|
||||
<el-descriptions-item label="中介类型">
|
||||
<span v-if="detailData.intermediaryType === '1'">个人</span>
|
||||
<span v-else-if="detailData.intermediaryType === '2'">实体</span>
|
||||
<span v-else>-</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="姓名/机构名称">{{ detailData.name || detailData.enterpriseName || '-' }}</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>
|
||||
<el-descriptions-item label="数据来源">{{ detailData.dataSourceName || '-' }}</el-descriptions-item>
|
||||
|
||||
<!-- 个人类型专属字段 -->
|
||||
<template v-if="detailData.intermediaryType === '1'">
|
||||
<el-descriptions-item label="人员类型">{{ detailData.indivType || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="人员子类型">{{ detailData.indivSubType || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="性别">{{ detailData.indivGenderName || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="证件类型">{{ detailData.indivCertType || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="手机号码">{{ detailData.indivPhone || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="微信号">{{ detailData.indivWechat || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="联系地址" :span="2">{{ detailData.indivAddress || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="所在公司">{{ detailData.indivCompany || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="职位">{{ detailData.indivPosition || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="关联人员ID">{{ detailData.indivRelatedId || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="关联关系">{{ detailData.indivRelation || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="人员类型">{{ detailData.personType || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="人员子类型">{{ detailData.personSubType || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="性别">
|
||||
<span v-if="detailData.gender === 'M'">男</span>
|
||||
<span v-else-if="detailData.gender === 'F'">女</span>
|
||||
<span v-else-if="detailData.gender === 'O'">其他</span>
|
||||
<span v-else>{{ detailData.gender || '-' }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="证件类型">{{ detailData.idType || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="手机号码">{{ detailData.mobile || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="微信号">{{ detailData.wechatNo || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="联系地址" :span="2">{{ detailData.contactAddress || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="所在公司">{{ detailData.company || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="职位">{{ detailData.position || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="企业统一信用码">{{ detailData.socialCreditCode || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="关系类型">{{ detailData.relationType || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="关联人员ID">{{ detailData.relatedNumId || '-' }}</el-descriptions-item>
|
||||
</template>
|
||||
|
||||
<!-- 机构类型专属字段 -->
|
||||
<template v-if="detailData.intermediaryType === '2'">
|
||||
<el-descriptions-item label="统一社会信用代码" :span="2">{{ detailData.corpCreditCode || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="主体类型">{{ detailData.corpType || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="企业性质">{{ detailData.corpNature || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="行业分类">{{ detailData.corpIndustryCategory || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="所属行业">{{ detailData.corpIndustry || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="成立日期">{{ detailData.corpEstablishDate || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="注册地址" :span="2">{{ detailData.corpAddress || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="法定代表人">{{ detailData.corpLegalRep || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="法定代表人证件类型">{{ detailData.corpLegalCertType || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="法定代表人证件号码" :span="2">{{ detailData.corpLegalCertNo || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="股东1">{{ detailData.corpShareholder1 || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="股东2">{{ detailData.corpShareholder2 || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="股东3">{{ detailData.corpShareholder3 || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="股东4">{{ detailData.corpShareholder4 || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="股东5">{{ detailData.corpShareholder5 || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="统一社会信用代码" :span="2">{{ detailData.socialCreditCode || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="主体类型">{{ detailData.enterpriseType || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="企业性质">{{ detailData.enterpriseNature || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="行业分类">{{ detailData.industryClass || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="所属行业">{{ detailData.industryName || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="成立日期">{{ detailData.establishDate || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="注册地址" :span="2">{{ detailData.registerAddress || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="法定代表人">{{ detailData.legalRepresentative || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="法定代表人证件类型">{{ detailData.legalCertType || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="法定代表人证件号码" :span="2">{{ detailData.legalCertNo || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="股东1">{{ detailData.shareholder1 || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="股东2">{{ detailData.shareholder2 || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="股东3">{{ detailData.shareholder3 || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="股东4">{{ detailData.shareholder4 || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="股东5">{{ detailData.shareholder5 || '-' }}</el-descriptions-item>
|
||||
</template>
|
||||
|
||||
<!-- 通用字段 -->
|
||||
<el-descriptions-item label="数据来源">
|
||||
<span v-if="detailData.dataSource === 'MANUAL'">手动录入</span>
|
||||
<span v-else-if="detailData.dataSource === 'SYSTEM'">系统同步</span>
|
||||
<span v-else-if="detailData.dataSource === 'IMPORT'">批量导入</span>
|
||||
<span v-else-if="detailData.dataSource === 'API'">接口获取</span>
|
||||
<span v-else>{{ detailData.dataSource || '-' }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="备注" :span="2">{{ detailData.remark || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="创建时间">{{ detailData.createTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="创建人">{{ detailData.createBy || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="创建时间">{{ detailData.createTime || '-' }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="visible = false">关 闭</el-button>
|
||||
|
||||
@@ -43,15 +43,15 @@
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="证件号" prop="certificateNo">
|
||||
<el-input v-model="form.certificateNo" placeholder="请输入证件号码" maxlength="50" clearable/>
|
||||
<el-form-item label="证件号" prop="personId">
|
||||
<el-input v-model="form.personId" placeholder="请输入证件号码" maxlength="50" clearable/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="人员类型">
|
||||
<el-select v-model="form.indivType" placeholder="请选择人员类型" clearable style="width: 100%">
|
||||
<el-select v-model="form.personType" placeholder="请选择人员类型" clearable style="width: 100%">
|
||||
<el-option
|
||||
v-for="item in indivTypeOptions"
|
||||
:key="item.value"
|
||||
@@ -63,21 +63,14 @@
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="人员子类型">
|
||||
<el-select v-model="form.indivSubType" placeholder="请选择人员子类型" clearable style="width: 100%">
|
||||
<el-option
|
||||
v-for="item in indivSubTypeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
<el-input v-model="form.personSubType" placeholder="请输入人员子类型" maxlength="100" clearable/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="性别">
|
||||
<el-select v-model="form.indivGender" placeholder="请选择性别" clearable style="width: 100%">
|
||||
<el-select v-model="form.gender" placeholder="请选择性别" clearable style="width: 100%">
|
||||
<el-option
|
||||
v-for="item in genderOptions"
|
||||
:key="item.value"
|
||||
@@ -89,7 +82,7 @@
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="证件类型">
|
||||
<el-select v-model="form.indivCertType" placeholder="请选择证件类型" clearable style="width: 100%">
|
||||
<el-select v-model="form.idType" placeholder="请选择证件类型" clearable style="width: 100%">
|
||||
<el-option
|
||||
v-for="item in certTypeOptions"
|
||||
:key="item.value"
|
||||
@@ -103,39 +96,46 @@
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="手机号码">
|
||||
<el-input v-model="form.indivPhone" placeholder="请输入手机号码" maxlength="20" clearable/>
|
||||
<el-input v-model="form.mobile" placeholder="请输入手机号码" maxlength="20" clearable/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="微信号">
|
||||
<el-input v-model="form.indivWechat" placeholder="请输入微信号" maxlength="50" clearable/>
|
||||
<el-input v-model="form.wechatNo" placeholder="请输入微信号" maxlength="50" clearable/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item label="联系地址">
|
||||
<el-input v-model="form.indivAddress" placeholder="请输入联系地址" maxlength="200" clearable/>
|
||||
<el-input v-model="form.contactAddress" placeholder="请输入联系地址" maxlength="200" clearable/>
|
||||
</el-form-item>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="所在公司">
|
||||
<el-input v-model="form.indivCompany" placeholder="请输入所在公司" maxlength="100" clearable/>
|
||||
<el-input v-model="form.company" placeholder="请输入所在公司" maxlength="200" clearable/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="职位">
|
||||
<el-input v-model="form.indivPosition" placeholder="请输入职位" maxlength="100" clearable/>
|
||||
<el-input v-model="form.position" placeholder="请输入职位" maxlength="100" clearable/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="关联人员ID">
|
||||
<el-input v-model="form.indivRelatedId" placeholder="请输入关联人员ID" maxlength="20" clearable/>
|
||||
<el-form-item label="企业统一信用码">
|
||||
<el-input v-model="form.socialCreditCode" placeholder="请输入企业统一信用码" maxlength="50" clearable/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="关联人员ID">
|
||||
<el-input v-model="form.relatedNumId" placeholder="请输入关联人员ID" maxlength="50" clearable/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="关联关系">
|
||||
<el-select v-model="form.indivRelation" placeholder="请选择关联关系" clearable style="width: 100%">
|
||||
<el-select v-model="form.relationType" placeholder="请选择关联关系" clearable style="width: 100%">
|
||||
<el-option
|
||||
v-for="item in relationTypeOptions"
|
||||
:key="item.value"
|
||||
@@ -168,17 +168,16 @@
|
||||
>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="机构名称" prop="name">
|
||||
<el-input v-model="form.name" placeholder="请输入机构名称" maxlength="100" clearable/>
|
||||
<el-form-item label="机构名称" prop="enterpriseName">
|
||||
<el-input v-model="form.enterpriseName" placeholder="请输入机构名称" maxlength="200" clearable/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="证件号" prop="certificateNo">
|
||||
<el-form-item label="证件号" prop="socialCreditCode">
|
||||
<el-input
|
||||
v-model="form.certificateNo"
|
||||
@input="handleCertificateNoChange"
|
||||
placeholder="统一社会信用代码(18位)"
|
||||
maxlength="18"
|
||||
v-model="form.socialCreditCode"
|
||||
placeholder="统一社会信用代码"
|
||||
maxlength="50"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
@@ -187,7 +186,7 @@
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="主体类型">
|
||||
<el-select v-model="form.corpType" placeholder="请选择主体类型" clearable style="width: 100%">
|
||||
<el-select v-model="form.enterpriseType" placeholder="请选择主体类型" clearable style="width: 100%">
|
||||
<el-option
|
||||
v-for="item in corpTypeOptions"
|
||||
:key="item.value"
|
||||
@@ -199,7 +198,7 @@
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="企业性质">
|
||||
<el-select v-model="form.corpNature" placeholder="请选择企业性质" clearable style="width: 100%">
|
||||
<el-select v-model="form.enterpriseNature" placeholder="请选择企业性质" clearable style="width: 100%">
|
||||
<el-option
|
||||
v-for="item in corpNatureOptions"
|
||||
:key="item.value"
|
||||
@@ -214,7 +213,7 @@
|
||||
<el-col :span="12">
|
||||
<el-form-item label="成立日期">
|
||||
<el-date-picker
|
||||
v-model="form.corpEstablishDate"
|
||||
v-model="form.establishDate"
|
||||
type="date"
|
||||
placeholder="选择成立日期"
|
||||
value-format="yyyy-MM-dd"
|
||||
@@ -224,64 +223,71 @@
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="行业分类">
|
||||
<el-input v-model="form.corpIndustryCategory" placeholder="请输入行业分类" maxlength="100" clearable/>
|
||||
<el-input v-model="form.industryClass" placeholder="请输入行业分类" maxlength="100" clearable/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="所属行业">
|
||||
<el-input v-model="form.corpIndustry" placeholder="请输入所属行业" maxlength="100" clearable/>
|
||||
<el-input v-model="form.industryName" placeholder="请输入所属行业" maxlength="100" clearable/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item label="注册地址">
|
||||
<el-input v-model="form.corpAddress" type="textarea" placeholder="请输入注册地址" maxlength="500" :rows="2"/>
|
||||
<el-input v-model="form.registerAddress" type="textarea" placeholder="请输入注册地址" maxlength="500" :rows="2"/>
|
||||
</el-form-item>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="法定代表人">
|
||||
<el-input v-model="form.corpLegalRep" placeholder="请输入法定代表人" maxlength="50" clearable/>
|
||||
<el-input v-model="form.legalRepresentative" placeholder="请输入法定代表人" maxlength="100" clearable/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="法定代表人证件类型">
|
||||
<el-input v-model="form.corpLegalCertType" placeholder="请输入证件类型" maxlength="30" clearable/>
|
||||
<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>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item label="法定代表人证件号码">
|
||||
<el-input v-model="form.corpLegalCertNo" placeholder="请输入法定代表人证件号码" maxlength="30" clearable/>
|
||||
<el-input v-model="form.legalCertNo" placeholder="请输入法定代表人证件号码" maxlength="50" clearable/>
|
||||
</el-form-item>
|
||||
<el-divider content-position="left">股东信息</el-divider>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="股东1">
|
||||
<el-input v-model="form.corpShareholder1" placeholder="请输入股东1" maxlength="30" clearable/>
|
||||
<el-input v-model="form.shareholder1" placeholder="请输入股东1" maxlength="100" clearable/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="股东2">
|
||||
<el-input v-model="form.corpShareholder2" placeholder="请输入股东2" maxlength="30" clearable/>
|
||||
<el-input v-model="form.shareholder2" placeholder="请输入股东2" maxlength="100" clearable/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="股东3">
|
||||
<el-input v-model="form.corpShareholder3" placeholder="请输入股东3" maxlength="30" clearable/>
|
||||
<el-input v-model="form.shareholder3" placeholder="请输入股东3" maxlength="100" clearable/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="股东4">
|
||||
<el-input v-model="form.corpShareholder4" placeholder="请输入股东4" maxlength="30" clearable/>
|
||||
<el-input v-model="form.shareholder4" placeholder="请输入股东4" maxlength="100" clearable/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="股东5">
|
||||
<el-input v-model="form.corpShareholder5" placeholder="请输入股东5" maxlength="30" clearable/>
|
||||
<el-input v-model="form.shareholder5" placeholder="请输入股东5" maxlength="100" clearable/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@@ -329,10 +335,6 @@ export default {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
indivSubTypeOptions: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
genderOptions: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
@@ -370,7 +372,7 @@ export default {
|
||||
{ required: true, message: "姓名不能为空", trigger: "blur" },
|
||||
{ max: 100, message: "姓名长度不能超过100个字符", trigger: "blur" }
|
||||
],
|
||||
certificateNo: [
|
||||
personId: [
|
||||
{ required: true, message: "证件号不能为空", trigger: "blur" },
|
||||
{ max: 50, message: "证件号长度不能超过50个字符", trigger: "blur" }
|
||||
],
|
||||
@@ -380,13 +382,13 @@ export default {
|
||||
},
|
||||
// 机构类型验证规则
|
||||
corpRules: {
|
||||
name: [
|
||||
enterpriseName: [
|
||||
{ required: true, message: "机构名称不能为空", trigger: "blur" },
|
||||
{ max: 100, message: "机构名称长度不能超过100个字符", trigger: "blur" }
|
||||
{ max: 200, message: "机构名称长度不能超过200个字符", trigger: "blur" }
|
||||
],
|
||||
certificateNo: [
|
||||
{ required: true, message: "证件号不能为空", trigger: "blur" },
|
||||
{ max: 18, message: "统一社会信用代码长度为18位", trigger: "blur" }
|
||||
socialCreditCode: [
|
||||
{ required: true, message: "统一社会信用代码不能为空", trigger: "blur" },
|
||||
{ max: 50, message: "统一社会信用代码长度不能超过50个字符", trigger: "blur" }
|
||||
],
|
||||
remark: [
|
||||
{ max: 500, message: "备注长度不能超过500个字符", trigger: "blur" }
|
||||
@@ -397,7 +399,7 @@ export default {
|
||||
computed: {
|
||||
// 判断是否为新增模式
|
||||
isAddMode() {
|
||||
return !this.form || !this.form.intermediaryId;
|
||||
return !this.form || !this.form.bizId;
|
||||
},
|
||||
// 根据选择的类型返回分隔线文本
|
||||
getTypeDividerText() {
|
||||
@@ -426,7 +428,7 @@ export default {
|
||||
*/
|
||||
initDialogState() {
|
||||
// 始终基于当前的 form 状态判断
|
||||
const isAdd = !this.form || !this.form.intermediaryId;
|
||||
const isAdd = !this.form || !this.form.bizId;
|
||||
|
||||
if (isAdd) {
|
||||
// 新增模式:重置选择状态
|
||||
@@ -466,16 +468,6 @@ export default {
|
||||
}, 50);
|
||||
},
|
||||
|
||||
/**
|
||||
* 处理机构类型证件号变更
|
||||
* 同步到统一社会信用代码字段
|
||||
*/
|
||||
handleCertificateNoChange(value) {
|
||||
if (this.form.intermediaryType === '2') {
|
||||
this.form.corpCreditCode = value;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交表单
|
||||
*/
|
||||
@@ -488,12 +480,6 @@ export default {
|
||||
|
||||
// 根据类型验证不同的表单
|
||||
const formRef = this.form.intermediaryType === '1' ? 'indivForm' : 'corpForm';
|
||||
const rules = this.form.intermediaryType === '1' ? this.indivRules : this.corpRules;
|
||||
|
||||
// 机构类型:同步证件号到统一社会信用代码
|
||||
if (this.form.intermediaryType === '2') {
|
||||
this.form.corpCreditCode = this.form.certificateNo;
|
||||
}
|
||||
|
||||
this.$refs[formRef].validate(valid => {
|
||||
if (valid) {
|
||||
|
||||
@@ -148,9 +148,9 @@ export default {
|
||||
},
|
||||
handleDownloadTemplate() {
|
||||
if (this.formData.importType === 'person') {
|
||||
this.download('dpc/intermediary/importPersonTemplate', {}, `个人中介黑名单模板_${new Date().getTime()}.xlsx`);
|
||||
this.download('ccdi/intermediary/importPersonTemplate', {}, `个人中介黑名单模板_${new Date().getTime()}.xlsx`);
|
||||
} else {
|
||||
this.download('dpc/intermediary/importEntityTemplate', {}, `机构中介黑名单模板_${new Date().getTime()}.xlsx`);
|
||||
this.download('ccdi/intermediary/importEntityTemplate', {}, `机构中介黑名单模板_${new Date().getTime()}.xlsx`);
|
||||
}
|
||||
},
|
||||
handleFileUploadProgress() {
|
||||
@@ -166,10 +166,26 @@ export default {
|
||||
this.isUploading = false;
|
||||
this.visible = false;
|
||||
this.$emit("success");
|
||||
|
||||
// 解析后端返回的消息,只展示错误部分
|
||||
let displayMessage = response.msg;
|
||||
|
||||
// 如果消息包含"恭喜您,数据已全部导入成功",说明全部成功,不展示详细列表
|
||||
if (displayMessage.includes('恭喜您,数据已全部导入成功')) {
|
||||
// 全部成功,使用简洁提示
|
||||
displayMessage = '导入成功!';
|
||||
}
|
||||
// 如果消息包含"很抱歉,导入失败",说明有错误,只展示错误部分
|
||||
else if (displayMessage.includes('很抱歉,导入失败')) {
|
||||
// 只保留错误部分,移除成功统计信息
|
||||
const lines = displayMessage.split('<br/><br/>');
|
||||
displayMessage = lines[0]; // 只取错误部分
|
||||
}
|
||||
|
||||
this.$msgbox({
|
||||
title: '导入结果',
|
||||
dangerouslyUseHTMLString: true,
|
||||
message: `<div style="overflow-y: auto; max-height: 60vh; padding-right: 10px; line-height: 1.6;">${response.msg}</div>`,
|
||||
message: `<div style="overflow-y: auto; max-height: 60vh; padding-right: 10px; line-height: 1.6;">${displayMessage}</div>`,
|
||||
confirmButtonText: '确定',
|
||||
customClass: 'import-result-dialog'
|
||||
});
|
||||
|
||||
@@ -22,14 +22,7 @@
|
||||
<el-select v-model="queryParams.intermediaryType" placeholder="中介类型" clearable style="width: 240px">
|
||||
<el-option label="全部" value="" />
|
||||
<el-option label="个人" value="1" />
|
||||
<el-option label="机构" value="2" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-select v-model="queryParams.status" placeholder="状态" clearable style="width: 240px">
|
||||
<el-option label="全部" value="" />
|
||||
<el-option label="正常" value="0" />
|
||||
<el-option label="停用" value="1" />
|
||||
<el-option label="实体" value="2" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
|
||||
@@ -51,7 +51,6 @@
|
||||
:title="title"
|
||||
:form="form"
|
||||
:indiv-type-options="indivTypeOptions"
|
||||
:indiv-sub-type-options="indivSubTypeOptions"
|
||||
:gender-options="genderOptions"
|
||||
:cert-type-options="certTypeOptions"
|
||||
:relation-type-options="relationTypeOptions"
|
||||
@@ -82,7 +81,8 @@ import {
|
||||
addEntityIntermediary,
|
||||
addPersonIntermediary,
|
||||
delIntermediary,
|
||||
getIntermediary,
|
||||
getEntityIntermediary,
|
||||
getPersonIntermediary,
|
||||
listIntermediary,
|
||||
updateEntityIntermediary,
|
||||
updatePersonIntermediary
|
||||
@@ -92,7 +92,6 @@ import {
|
||||
getCorpNatureOptions,
|
||||
getCorpTypeOptions,
|
||||
getGenderOptions,
|
||||
getIndivSubTypeOptions,
|
||||
getIndivTypeOptions,
|
||||
getRelationTypeOptions
|
||||
} from "@/api/ccdiEnum";
|
||||
@@ -129,8 +128,7 @@ export default {
|
||||
pageSize: 10,
|
||||
name: null,
|
||||
certificateNo: null,
|
||||
intermediaryType: null,
|
||||
status: null
|
||||
intermediaryType: null
|
||||
},
|
||||
form: {},
|
||||
upload: {
|
||||
@@ -138,7 +136,6 @@ export default {
|
||||
title: ""
|
||||
},
|
||||
indivTypeOptions: [],
|
||||
indivSubTypeOptions: [],
|
||||
genderOptions: [],
|
||||
certTypeOptions: [],
|
||||
relationTypeOptions: [],
|
||||
@@ -156,9 +153,6 @@ export default {
|
||||
getIndivTypeOptions().then(response => {
|
||||
this.indivTypeOptions = response.data;
|
||||
});
|
||||
getIndivSubTypeOptions().then(response => {
|
||||
this.indivSubTypeOptions = response.data;
|
||||
});
|
||||
getGenderOptions().then(response => {
|
||||
this.genderOptions = response.data;
|
||||
});
|
||||
@@ -191,7 +185,7 @@ export default {
|
||||
},
|
||||
/** 多选框选中数据 */
|
||||
handleSelectionChange(selection) {
|
||||
this.ids = selection.map(item => item.intermediaryId);
|
||||
this.ids = selection.map(item => item.id);
|
||||
this.single = selection.length !== 1;
|
||||
this.multiple = !selection.length;
|
||||
},
|
||||
@@ -204,40 +198,42 @@ export default {
|
||||
/** 表单重置 */
|
||||
reset() {
|
||||
this.form = {
|
||||
intermediaryId: null,
|
||||
bizId: null,
|
||||
name: null,
|
||||
certificateNo: null,
|
||||
intermediaryType: "1",
|
||||
status: "0",
|
||||
remark: null,
|
||||
indivType: null,
|
||||
indivSubType: null,
|
||||
indivGender: null,
|
||||
indivCertType: null,
|
||||
indivPhone: null,
|
||||
indivWechat: null,
|
||||
indivAddress: null,
|
||||
indivCompany: null,
|
||||
indivPosition: null,
|
||||
indivRelatedId: null,
|
||||
indivRelation: null,
|
||||
corpCreditCode: null,
|
||||
corpType: null,
|
||||
corpNature: null,
|
||||
corpIndustryCategory: null,
|
||||
corpIndustry: null,
|
||||
corpEstablishDate: null,
|
||||
corpAddress: null,
|
||||
corpLegalRep: null,
|
||||
corpLegalCertType: null,
|
||||
corpLegalCertNo: null,
|
||||
corpShareholder1: null,
|
||||
corpShareholder2: null,
|
||||
corpShareholder3: null,
|
||||
corpShareholder4: null,
|
||||
corpShareholder5: null
|
||||
// 个人中介字段
|
||||
personId: null,
|
||||
personType: null,
|
||||
personSubType: null,
|
||||
relationType: null,
|
||||
gender: null,
|
||||
idType: null,
|
||||
mobile: null,
|
||||
wechatNo: null,
|
||||
contactAddress: null,
|
||||
company: null,
|
||||
socialCreditCode: null,
|
||||
position: null,
|
||||
relatedNumId: null,
|
||||
// 实体中介字段
|
||||
enterpriseName: null,
|
||||
enterpriseType: null,
|
||||
enterpriseNature: null,
|
||||
industryClass: null,
|
||||
industryName: null,
|
||||
establishDate: null,
|
||||
registerAddress: null,
|
||||
legalRepresentative: null,
|
||||
legalCertType: null,
|
||||
legalCertNo: null,
|
||||
shareholder1: null,
|
||||
shareholder2: null,
|
||||
shareholder3: null,
|
||||
shareholder4: null,
|
||||
shareholder5: null
|
||||
};
|
||||
// 注意:不调用 this.resetForm("form")
|
||||
// 注意:不调用 this.resetForm("form")
|
||||
// EditDialog 组件会在 visible 变化时自动处理表单验证状态的重置
|
||||
},
|
||||
/** 取消按钮 */
|
||||
@@ -247,25 +243,42 @@ export default {
|
||||
},
|
||||
/** 查看详情操作 */
|
||||
handleDetail(row) {
|
||||
const intermediaryId = row.intermediaryId;
|
||||
getIntermediary(intermediaryId).then(response => {
|
||||
if (row.intermediaryType === '1') {
|
||||
// 个人中介 - 使用row.id作为bizId
|
||||
getPersonIntermediary(row.id).then(response => {
|
||||
this.detailData = response.data;
|
||||
this.detailOpen = true;
|
||||
});
|
||||
} else {
|
||||
// 实体中介 - 使用row.id作为socialCreditCode
|
||||
getEntityIntermediary(row.id).then(response => {
|
||||
this.detailData = response.data;
|
||||
this.detailOpen = true;
|
||||
});
|
||||
}
|
||||
},
|
||||
/** 修改按钮操作 */
|
||||
handleUpdate(row) {
|
||||
this.reset();
|
||||
const intermediaryId = row.intermediaryId || this.ids[0];
|
||||
getIntermediary(intermediaryId).then(response => {
|
||||
if (row.intermediaryType === '1') {
|
||||
// 个人中介 - 使用row.id作为bizId
|
||||
getPersonIntermediary(row.id).then(response => {
|
||||
this.form = response.data;
|
||||
this.open = true;
|
||||
this.title = "修改中介黑名单";
|
||||
});
|
||||
} else {
|
||||
// 实体中介 - 使用row.id作为socialCreditCode
|
||||
getEntityIntermediary(row.id).then(response => {
|
||||
this.form = response.data;
|
||||
this.open = true;
|
||||
this.title = "修改中介黑名单";
|
||||
});
|
||||
}
|
||||
},
|
||||
/** 提交按钮 */
|
||||
submitForm() {
|
||||
if (this.form.intermediaryId != null) {
|
||||
if (this.form.bizId != null) {
|
||||
// 修改模式:根据中介类型调用不同的接口
|
||||
if (this.form.intermediaryType === '1') {
|
||||
// 个人中介
|
||||
@@ -303,9 +316,12 @@ export default {
|
||||
},
|
||||
/** 删除按钮操作 */
|
||||
handleDelete(row) {
|
||||
const intermediaryIds = row.intermediaryId || this.ids;
|
||||
this.$modal.confirm('是否确认删除中介黑名单编号为"' + intermediaryIds + '"的数据项?').then(function() {
|
||||
return delIntermediary(intermediaryIds);
|
||||
const bizIds = row.id || this.ids.join(',');
|
||||
const confirmMsg = row.id
|
||||
? `确认删除中介"${row.name}"(证件号:${row.certificateNo})吗?`
|
||||
: `确认删除选中的 ${this.ids.length} 条中介数据吗?`;
|
||||
this.$modal.confirm(confirmMsg).then(function() {
|
||||
return delIntermediary(bizIds);
|
||||
}).then(() => {
|
||||
this.getList();
|
||||
this.$modal.msgSuccess("删除成功");
|
||||
|
||||
@@ -96,6 +96,12 @@
|
||||
icon="el-icon-s-data"
|
||||
@click="handleEnter(scope.row)"
|
||||
>进入项目</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-refresh"
|
||||
@click="handleReAnalyze(scope.row)"
|
||||
>重新分析</el-button>
|
||||
</template>
|
||||
|
||||
<!-- 已完成项目 -->
|
||||
|
||||
@@ -7,7 +7,7 @@ function resolve(dir) {
|
||||
|
||||
const CompressionPlugin = require('compression-webpack-plugin')
|
||||
|
||||
const name = process.env.VUE_APP_TITLE || '若依管理系统' // 网页标题
|
||||
const name = process.env.VUE_APP_TITLE || '纪检初核系统' // 网页标题
|
||||
|
||||
const baseUrl = 'http://localhost:8080' // 后端接口
|
||||
|
||||
|
||||
36
sql/dpc_intermediary_relation_type_dict_20260205.sql
Normal file
36
sql/dpc_intermediary_relation_type_dict_20260205.sql
Normal file
@@ -0,0 +1,36 @@
|
||||
-- ============================================================
|
||||
-- 中介黑名单关系类型字典补充脚本
|
||||
-- 功能:为个人中介添加关系类型字典
|
||||
-- 作者:ruoyi
|
||||
-- 日期:2026-02-05
|
||||
-- ============================================================
|
||||
|
||||
USE `discipline-prelim-check`;
|
||||
|
||||
-- ============================================================
|
||||
-- 关系类型字典(ccdi_relation_type)
|
||||
-- ============================================================
|
||||
DELETE FROM sys_dict_data WHERE dict_type = 'ccdi_relation_type';
|
||||
DELETE FROM sys_dict_type WHERE dict_type = 'ccdi_relation_type';
|
||||
|
||||
INSERT INTO sys_dict_type (dict_name, dict_type, status, create_by, create_time, remark)
|
||||
VALUES ('关系类型', 'ccdi_relation_type', '0', 'admin', NOW(), '中介黑名单-人员关系类型');
|
||||
|
||||
INSERT INTO sys_dict_data (dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark)
|
||||
VALUES
|
||||
(1, '配偶', '配偶', 'ccdi_relation_type', '', 'default', 'N', '0', 'admin', NOW(), NULL),
|
||||
(2, '父亲', '父亲', 'ccdi_relation_type', '', 'default', 'N', '0', 'admin', NOW(), NULL),
|
||||
(3, '母亲', '母亲', 'ccdi_relation_type', '', 'default', 'N', '0', 'admin', NOW(), NULL),
|
||||
(4, '子女', '子女', 'ccdi_relation_type', '', 'default', 'N', '0', 'admin', NOW(), NULL),
|
||||
(5, '兄弟', '兄弟', 'ccdi_relation_type', '', 'default', 'N', '0', 'admin', NOW(), NULL),
|
||||
(6, '姐妹', '姐妹', 'ccdi_relation_type', '', 'default', 'N', '0', 'admin', NOW(), NULL),
|
||||
(7, '合伙人', '合伙人', 'ccdi_relation_type', '', 'default', 'N', '0', 'admin', NOW(), NULL),
|
||||
(8, '同事', '同事', 'ccdi_relation_type', '', 'default', 'N', '0', 'admin', NOW(), NULL),
|
||||
(9, '其他', '其他', 'ccdi_relation_type', '', 'default', 'N', '0', 'admin', NOW(), NULL);
|
||||
|
||||
-- ============================================================
|
||||
-- 执行完成后操作说明
|
||||
-- ============================================================
|
||||
-- 1. 执行完成后,请通过系统管理 > 字典管理验证字典数据
|
||||
-- 2. 重要:在字典类型页面点击"刷新缓存"按钮,确保字典数据加载到 Redis
|
||||
-- 3. 验证字典缓存是否生效(可通过测试模板下载确认下拉框是否显示)
|
||||
246
sql/menu-intermediary.sql
Normal file
246
sql/menu-intermediary.sql
Normal file
@@ -0,0 +1,246 @@
|
||||
-- =====================================================
|
||||
-- 中介黑名单管理菜单SQL
|
||||
-- 功能: 为中介黑名单管理模块创建菜单和权限配置
|
||||
-- 版本: 2.0
|
||||
-- 日期: 2026-02-04
|
||||
-- =====================================================
|
||||
|
||||
-- 1. 创建主菜单 (中介黑名单)
|
||||
-- 父级菜单: 2000 (业务管理, 请根据实际情况调整)
|
||||
-- 菜单类型: M (目录)
|
||||
INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, query, perms, icon, menu_type, status, visible, create_by, create_time, update_by, update_time, remark)
|
||||
VALUES (
|
||||
'中介黑名单',
|
||||
2000,
|
||||
5,
|
||||
'intermediary',
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
'peoples',
|
||||
'M',
|
||||
'0',
|
||||
'0',
|
||||
'admin',
|
||||
NOW(),
|
||||
'',
|
||||
NULL,
|
||||
'中介黑名单管理目录'
|
||||
);
|
||||
|
||||
-- 获取刚插入的菜单ID
|
||||
SET @menu_id = LAST_INSERT_ID();
|
||||
|
||||
-- 2. 创建子菜单 (中介黑名单管理)
|
||||
-- 菜单类型: C (菜单)
|
||||
INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, query, perms, icon, menu_type, status, visible, create_by, create_time, update_by, update_time, remark)
|
||||
VALUES (
|
||||
'中介管理',
|
||||
@menu_id,
|
||||
1,
|
||||
'intermediaryIndex',
|
||||
'ccdi/intermediary/index',
|
||||
NULL,
|
||||
NULL,
|
||||
'user',
|
||||
'C',
|
||||
'0',
|
||||
'0',
|
||||
'admin',
|
||||
NOW(),
|
||||
'',
|
||||
NULL,
|
||||
'中介黑名单管理菜单'
|
||||
);
|
||||
|
||||
SET @intermediary_menu_id = LAST_INSERT_ID();
|
||||
|
||||
-- 3. 创建按钮权限
|
||||
-- 查询权限
|
||||
INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, query, perms, icon, menu_type, status, visible, create_by, create_time, update_by, update_time, remark)
|
||||
VALUES (
|
||||
'中介查询',
|
||||
@intermediary_menu_id,
|
||||
1,
|
||||
'',
|
||||
NULL,
|
||||
NULL,
|
||||
'ccdi:intermediary:query',
|
||||
'#',
|
||||
'F',
|
||||
'0',
|
||||
'0',
|
||||
'admin',
|
||||
NOW(),
|
||||
'',
|
||||
NULL,
|
||||
''
|
||||
);
|
||||
|
||||
-- 列表权限
|
||||
INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, query, perms, icon, menu_type, status, visible, create_by, create_time, update_by, update_time, remark)
|
||||
VALUES (
|
||||
'中介列表',
|
||||
@intermediary_menu_id,
|
||||
2,
|
||||
'',
|
||||
NULL,
|
||||
NULL,
|
||||
'ccdi:intermediary:list',
|
||||
'#',
|
||||
'F',
|
||||
'0',
|
||||
'0',
|
||||
'admin',
|
||||
NOW(),
|
||||
'',
|
||||
NULL,
|
||||
''
|
||||
);
|
||||
|
||||
-- 新增权限
|
||||
INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, query, perms, icon, menu_type, status, visible, create_by, create_time, update_by, update_time, remark)
|
||||
VALUES (
|
||||
'中介新增',
|
||||
@intermediary_menu_id,
|
||||
3,
|
||||
'',
|
||||
NULL,
|
||||
NULL,
|
||||
'ccdi:intermediary:add',
|
||||
'#',
|
||||
'F',
|
||||
'0',
|
||||
'0',
|
||||
'admin',
|
||||
NOW(),
|
||||
'',
|
||||
NULL,
|
||||
''
|
||||
);
|
||||
|
||||
-- 修改权限
|
||||
INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, query, perms, icon, menu_type, status, visible, create_by, create_time, update_by, update_time, remark)
|
||||
VALUES (
|
||||
'中介修改',
|
||||
@intermediary_menu_id,
|
||||
4,
|
||||
'',
|
||||
NULL,
|
||||
NULL,
|
||||
'ccdi:intermediary:edit',
|
||||
'#',
|
||||
'F',
|
||||
'0',
|
||||
'0',
|
||||
'admin',
|
||||
NOW(),
|
||||
'',
|
||||
NULL,
|
||||
''
|
||||
);
|
||||
|
||||
-- 删除权限
|
||||
INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, query, perms, icon, menu_type, status, visible, create_by, create_time, update_by, update_time, remark)
|
||||
VALUES (
|
||||
'中介删除',
|
||||
@intermediary_menu_id,
|
||||
5,
|
||||
'',
|
||||
NULL,
|
||||
NULL,
|
||||
'ccdi:intermediary:remove',
|
||||
'#',
|
||||
'F',
|
||||
'0',
|
||||
'0',
|
||||
'admin',
|
||||
NOW(),
|
||||
'',
|
||||
NULL,
|
||||
''
|
||||
);
|
||||
|
||||
-- 导出权限
|
||||
INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, query, perms, icon, menu_type, status, visible, create_by, create_time, update_by, update_time, remark)
|
||||
VALUES (
|
||||
'中介导出',
|
||||
@intermediary_menu_id,
|
||||
6,
|
||||
'',
|
||||
NULL,
|
||||
NULL,
|
||||
'ccdi:intermediary:export',
|
||||
'#',
|
||||
'F',
|
||||
'0',
|
||||
'0',
|
||||
'admin',
|
||||
NOW(),
|
||||
'',
|
||||
NULL,
|
||||
''
|
||||
);
|
||||
|
||||
-- 导入权限
|
||||
INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, query, perms, icon, menu_type, status, visible, create_by, create_time, update_by, update_time, remark)
|
||||
VALUES (
|
||||
'中介导入',
|
||||
@intermediary_menu_id,
|
||||
7,
|
||||
'',
|
||||
NULL,
|
||||
NULL,
|
||||
'ccdi:intermediary:import',
|
||||
'#',
|
||||
'F',
|
||||
'0',
|
||||
'0',
|
||||
'admin',
|
||||
NOW(),
|
||||
'',
|
||||
NULL,
|
||||
''
|
||||
);
|
||||
|
||||
-- =====================================================
|
||||
-- 说明:
|
||||
-- 1. 本SQL创建了完整的菜单结构:
|
||||
-- - 一级菜单: 中介黑名单 (目录)
|
||||
-- - 二级菜单: 中介管理 (菜单页面)
|
||||
-- - 三级菜单: 各种按钮权限
|
||||
--
|
||||
-- 2. 权限标识:
|
||||
-- - ccdi:intermediary:query (查询)
|
||||
-- - ccdi:intermediary:list (列表)
|
||||
-- - ccdi:intermediary:add (新增)
|
||||
-- - ccdi:intermediary:edit (修改)
|
||||
-- - ccdi:intermediary:remove (删除)
|
||||
-- - ccdi:intermediary:export (导出)
|
||||
-- - ccdi:intermediary:import (导入)
|
||||
--
|
||||
-- 3. 使用说明:
|
||||
-- - 执行本SQL后,需要在角色管理中为相应角色分配权限
|
||||
-- - 建议为admin角色分配所有权限
|
||||
-- - 前端路由会根据权限自动显示菜单
|
||||
--
|
||||
-- 4. 注意事项:
|
||||
-- - parent_id=2000 是业务管理的父级菜单,请根据实际情况调整
|
||||
-- - 组件路径 'ccdi/intermediary/index' 需要与前端Vue组件路径一致
|
||||
-- - 如果父级菜单不存在,需要先创建父级菜单或修改parent_id
|
||||
-- =====================================================
|
||||
|
||||
-- 查询创建的菜单 (用于验证)
|
||||
SELECT
|
||||
menu_id AS '菜单ID',
|
||||
menu_name AS '菜单名称',
|
||||
parent_id AS '父级菜单ID',
|
||||
order_num AS '显示顺序',
|
||||
perms AS '权限标识',
|
||||
menu_type AS '菜单类型',
|
||||
status AS '状态',
|
||||
visible AS '可见',
|
||||
create_time AS '创建时间'
|
||||
FROM sys_menu
|
||||
WHERE menu_name LIKE '%中介%' OR perms LIKE '%intermediary%'
|
||||
ORDER BY parent_id, order_num;
|
||||
Reference in New Issue
Block a user