diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 8326344..4a45d57 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -25,7 +25,12 @@ "Bash(javac:*)", "Bash(unzip:*)", "Bash(chcp:*)", - "Skill(superpowers:brainstorming)" + "Skill(superpowers:brainstorming)", + "Bash(pip install:*)", + "Skill(superpowers:using-superpowers)", + "Bash(tree:*)", + "Skill(docx)", + "Bash(bash:*)" ] }, "enabledMcpjsonServers": [ diff --git a/CLAUDE.md b/CLAUDE.md index 5cf45ef..a6672bf 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -35,16 +35,18 @@ ### 前端代码 - 在添加页面和组件后,注意与数据库中菜单表进行联动修改 +- 前端组件代码需要组件化,复杂的组件需要进行拆分为单独的文件 ## 运行 - 使用mcp:dpc_intermediary_blacklist进行数据库相关操作 -- 使用根目录中的ry.bat控制后端的启动,不要自行在命令行中启动后端 +- 不要在命令行中启动后端进行测试 - 测试方式为生成可执行的测试脚本 - 测试脚本在运行完成后需要保存所有接口输出并生成测试用例报告 - /login/test接口可以传入username和password获取token,用于测试验证接口的功能。 用于测试的账号:username: admin password admin123 - swagger-ui的地址为/swagger-ui/index.html +- 在向doc文件夹添加文件时需要分门别类添加,根据 This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. diff --git a/doc/README.md b/doc/README.md new file mode 100644 index 0000000..769b763 --- /dev/null +++ b/doc/README.md @@ -0,0 +1,66 @@ +# 文档目录结构 + +本目录包含纪检初核系统的各类文档、测试数据和脚本。 + +## 目录说明 + +### 📁 docs/ +项目文档目录 +- `纪检初核系统功能说明书-V1.0.docx/md` - 系统功能说明书 +- `纪检初核系统模块划分方案.md` - 模块划分方案 +- `若依环境使用手册.docx` - 若依框架使用手册 +- `中介黑名单弹窗优化设计.md` - UI设计文档 +- `EasyExcel字典下拉框使用说明.md` - Excel导入使用说明 + +### 📁 api/ +API接口文档目录 +- `员工信息管理API文档.md` - 员工信息管理模块API +- `中介黑名单管理API文档.md` - 中介黑名单管理模块API + +### 📁 scripts/ +测试脚本目录 +- `test_import.py` - 导入功能测试脚本 +- `test_import_simple.py` - 简单导入测试脚本 +- `test_uniqueness_validation.py` - 唯一性校验测试脚本 +- `generate_test_data.py` - 测试数据生成脚本 + +### 📁 test-data/ +测试数据目录 +- `个人中介黑名单模板_1769667622015.xlsx` - 导入模板 +- `个人中介黑名单测试数据_1000条.xlsx` - 测试数据(第1批) +- `个人中介黑名单测试数据_1000条_第2批.xlsx` - 测试数据(第2批) +- `中介人员信息表.csv` - 中介人员数据 +- `中介主体信息表.csv` - 中介主体数据 + +### 📁 other/ +其他文件目录 +- `纪检初核系统-离线演示包/` - 离线演示包(解压版) +- `纪检初核系统-离线演示包.zip` - 离线演示包(压缩版) +- `ScreenShot_*.png` - 截图文件 + +### 📁 modules/ +模块设计文档目录 +- `01-项目管理模块/` - 项目管理模块文档 +- `02-项目工作台/` - 项目工作台模块文档 +- `03-信息维护模块.md` - 信息维护模块文档 +- `04-参数配置模块.md` - 参数配置模块文档 +- `05-系统管理模块.md` - 系统管理模块文档 + +## 使用说明 + +### 生成测试数据 +```bash +cd doc/scripts +python generate_test_data.py +``` + +### 运行测试脚本 +```bash +cd doc/scripts +python test_uniqueness_validation.py +``` + +### 导入测试数据 +1. 从 `test-data/` 目录下载对应的Excel文件 +2. 在系统页面点击"导入"按钮 +3. 选择文件并上传 diff --git a/doc/中介黑名单管理API文档.md b/doc/api/中介黑名单管理API文档.md similarity index 62% rename from doc/中介黑名单管理API文档.md rename to doc/api/中介黑名单管理API文档.md index b7c9906..f1b86ca 100644 --- a/doc/中介黑名单管理API文档.md +++ b/doc/api/中介黑名单管理API文档.md @@ -134,7 +134,9 @@ ### 3. 新增中介黑名单 -**接口地址**: `POST /dpc/intermediary` +#### 3.1 新增个人中介黑名单 + +**接口地址**: `POST /dpc/intermediary/person` **权限要求**: `dpc:intermediary:add` @@ -143,7 +145,15 @@ { "name": "张三", "certificateNo": "110101199001011234", - "intermediaryType": "1", + "indivType": "中介", + "indivSubType": "本人", + "indivGender": "M", + "indivCertType": "身份证", + "indivPhone": "13800138000", + "indivWechat": "zhangsan", + "indivAddress": "北京市朝阳区", + "indivCompany": "XX公司", + "indivPosition": "经纪人", "status": "0", "remark": "测试数据" } @@ -153,9 +163,19 @@ | 字段名 | 类型 | 必填 | 说明 | |--------|------|------|------| -| name | String | 是 | 姓名/机构名称 | -| certificateNo | String | 是 | 证件号/统一社会信用代码 | -| intermediaryType | String | 是 | 中介类型(1=个人, 2=机构) | +| name | String | 是 | 姓名 | +| certificateNo | String | 是 | 证件号 | +| indivType | String | 否 | 人员类型 | +| indivSubType | String | 否 | 人员子类型 | +| indivGender | String | 否 | 性别(M男 F女 O其他) | +| indivCertType | String | 否 | 证件类型 | +| indivPhone | String | 否 | 手机号码 | +| indivWechat | String | 否 | 微信号 | +| indivAddress | String | 否 | 联系地址 | +| indivCompany | String | 否 | 所在公司 | +| indivPosition | String | 否 | 职位/职务 | +| indivRelatedId | String | 否 | 关联人员ID | +| indivRelation | String | 否 | 关联关系 | | status | String | 是 | 状态(0=正常, 1=停用) | | remark | String | 否 | 备注 | @@ -167,11 +187,72 @@ } ``` +#### 3.2 新增机构中介黑名单 + +**接口地址**: `POST /dpc/intermediary/entity` + +**权限要求**: `dpc:intermediary:add` + +**请求体**: +```json +{ + "name": "XX中介公司", + "corpCreditCode": "91110000XXXXXXXXXX", + "corpType": "有限责任公司", + "corpNature": "民企", + "corpIndustryCategory": "房地产", + "corpIndustry": "房地产业", + "corpEstablishDate": "2020-01-01", + "corpAddress": "北京市朝阳区", + "corpLegalRep": "张三", + "corpLegalCertType": "身份证", + "corpLegalCertNo": "110101199001011234", + "corpShareholder1": "李四", + "corpShareholder2": "王五", + "status": "0", + "remark": "测试数据" +} +``` + +**字段说明**: + +| 字段名 | 类型 | 必填 | 说明 | +|--------|------|------|------| +| name | String | 是 | 机构名称 | +| corpCreditCode | String | 是 | 统一社会信用代码 | +| corpType | String | 否 | 主体类型 | +| corpNature | String | 否 | 企业性质 | +| corpIndustryCategory | String | 否 | 行业分类 | +| corpIndustry | String | 否 | 所属行业 | +| corpEstablishDate | Date | 否 | 成立日期 | +| corpAddress | String | 否 | 注册地址 | +| corpLegalRep | String | 否 | 法定代表人 | +| corpLegalCertType | String | 否 | 法定代表人证件类型 | +| corpLegalCertNo | String | 否 | 法定代表人证件号码 | +| corpShareholder1-5 | String | 否 | 股东信息 | +| status | String | 是 | 状态(0=正常, 1=停用) | +| remark | String | 否 | 备注 | + +**响应示例**: +```json +{ + "code": 200, + "msg": "操作成功" +} +``` + +**注意**: +- 中介类型由系统自动设置,无需手动传递 +- 新增个人中介时,机构专属字段会被自动忽略 +- 新增机构中介时,证件号自动使用统一社会信用代码 + --- ### 4. 修改中介黑名单 -**接口地址**: `PUT /dpc/intermediary` +#### 4.1 修改个人中介黑名单 + +**接口地址**: `PUT /dpc/intermediary/person` **权限要求**: `dpc:intermediary:edit` @@ -181,13 +262,42 @@ "intermediaryId": 1, "name": "张三", "certificateNo": "110101199001011234", - "intermediaryType": "1", + "indivType": "中介", + "indivSubType": "本人", + "indivGender": "M", + "indivCertType": "身份证", + "indivPhone": "13800138000", + "indivWechat": "zhangsan", + "indivAddress": "北京市朝阳区", + "indivCompany": "XX公司", + "indivPosition": "经纪人", + "indivRelatedId": null, + "indivRelation": null, "status": "0", "remark": "测试数据" } ``` -**字段说明**: 与新增接口相同,intermediaryId 为必填项。 +**字段说明**: + +| 字段名 | 类型 | 必填 | 说明 | +|--------|------|------|------| +| intermediaryId | Long | 是 | 中介ID | +| name | String | 是 | 姓名 | +| certificateNo | String | 否 | 证件号 | +| indivType | String | 否 | 人员类型 | +| indivSubType | String | 否 | 人员子类型 | +| indivGender | String | 否 | 性别(M男 F女 O其他) | +| indivCertType | String | 否 | 证件类型 | +| indivPhone | String | 否 | 手机号码 | +| indivWechat | String | 否 | 微信号 | +| indivAddress | String | 否 | 联系地址 | +| indivCompany | String | 否 | 所在公司 | +| indivPosition | String | 否 | 职位/职务 | +| indivRelatedId | String | 否 | 关联人员ID | +| indivRelation | String | 否 | 关联关系 | +| status | String | 是 | 状态(0=正常, 1=停用) | +| remark | String | 否 | 备注 | **响应示例**: ```json @@ -197,6 +307,72 @@ } ``` +#### 4.2 修改机构中介黑名单 + +**接口地址**: `PUT /dpc/intermediary/entity` + +**权限要求**: `dpc:intermediary:edit` + +**请求体**: +```json +{ + "intermediaryId": 2, + "name": "XX中介公司", + "certificateNo": "91110000XXXXXXXXXX", + "corpCreditCode": "91110000XXXXXXXXXX", + "corpType": "有限责任公司", + "corpNature": "民企", + "corpIndustryCategory": "房地产", + "corpIndustry": "房地产业", + "corpEstablishDate": "2020-01-01", + "corpAddress": "北京市朝阳区", + "corpLegalRep": "张三", + "corpLegalCertType": "身份证", + "corpLegalCertNo": "110101199001011234", + "corpShareholder1": "李四", + "corpShareholder2": "王五", + "corpShareholder3": null, + "corpShareholder4": null, + "corpShareholder5": null, + "status": "0", + "remark": "测试数据" +} +``` + +**字段说明**: + +| 字段名 | 类型 | 必填 | 说明 | +|--------|------|------|------| +| intermediaryId | Long | 是 | 中介ID | +| name | String | 是 | 机构名称 | +| certificateNo | String | 否 | 证件号(统一社会信用代码) | +| corpCreditCode | String | 否 | 统一社会信用代码 | +| corpType | String | 否 | 主体类型 | +| corpNature | String | 否 | 企业性质 | +| corpIndustryCategory | String | 否 | 行业分类 | +| corpIndustry | String | 否 | 所属行业 | +| corpEstablishDate | Date | 否 | 成立日期 | +| corpAddress | String | 否 | 注册地址 | +| corpLegalRep | String | 否 | 法定代表人 | +| corpLegalCertType | String | 否 | 法定代表人证件类型 | +| corpLegalCertNo | String | 否 | 法定代表人证件号码 | +| corpShareholder1-5 | String | 否 | 股东信息 | +| status | String | 是 | 状态(0=正常, 1=停用) | +| remark | String | 否 | 备注 | + +**响应示例**: +```json +{ + "code": 200, + "msg": "操作成功" +} +``` + +**注意**: +- 中介类型(intermediaryType)不允许修改,系统会自动根据接口设置正确的类型 +- 使用个人中介接口时,机构专属字段会被自动清空 +- 使用机构中介接口时,个人专属字段会被自动清空 + --- ### 5. 删除中介黑名单 @@ -402,3 +578,5 @@ |------|------|------| | 1.0.0 | 2026-01-29 | 初始版本,支持个人和机构分类管理 | | 1.1.0 | 2026-01-29 | 添加字典下拉框功能,分离个人/机构模板 | +| 1.2.0 | 2026-01-29 | 修改接口分离:新增个人/机构专用修改接口,修复中介类型修改问题 | +| 1.3.0 | 2026-01-29 | 新增接口分离:新增个人/机构专用新增接口,统一接口设计 | diff --git a/doc/api/中介黑名单管理API测试报告.md b/doc/api/中介黑名单管理API测试报告.md new file mode 100644 index 0000000..81482fa --- /dev/null +++ b/doc/api/中介黑名单管理API测试报告.md @@ -0,0 +1,271 @@ +# 中介黑名单管理API测试报告 + +## 测试概述 + +**测试时间:** 2026-01-29 16:43:11 +**测试环境:** http://localhost:8080 +**测试账号:** admin +**测试脚本:** [test_intermediary_blacklist.sh](../scripts/test_intermediary_blacklist.sh) +**测试通过率:** 100.00% + +## 测试结果汇总 + +| 指标 | 数值 | +|------|------| +| 测试场景总数 | 11 | +| 通过数量 | 11 | +| 失败数量 | 0 | +| 通过率 | 100.00% | + +## 测试用例详情 + +### 1. 登录测试 + +**接口:** `POST /login/test` +**描述:** 使用测试账号登录获取认证token + +**请求参数:** +```json +{ + "username": "admin", + "password": "admin123" +} +``` + +**测试结果:** ✅ 通过 +- 成功获取token +- token格式正确 + +--- + +### 2. 查询中介黑名单列表 + +**接口:** `GET /dpc/intermediary/list` +**描述:** 分页查询中介黑名单列表 + +**请求参数:** +- pageNum: 1 +- pageSize: 10 + +**测试结果:** ✅ 通过 +- 返回分页数据结构正确 +- 包含 total 和 rows 字段 +- 数据格式符合预期 + +--- + +### 3. 新增个人中介黑名单 + +**接口:** `POST /dpc/intermediary` +**描述:** 新增个人类型的中介黑名单记录 + +**请求参数:** +```json +{ + "name": "测试个人中介_20260129_164311", + "certificateNo": "TESTCERT20260129_164311", + "intermediaryType": "1", + "remark": "自动化测试数据" +} +``` + +**测试结果:** ✅ 通过 +- 成功创建记录 +- 返回状态码 200 +- 成功获取到新创建的ID: 2005 + +--- + +### 4. 新增机构中介黑名单 + +**接口:** `POST /dpc/intermediary` +**描述:** 新增机构类型的中介黑名单记录 + +**请求参数:** +```json +{ + "name": "测试机构中介_20260129_164311", + "certificateNo": "TESTORG20260129_164311", + "intermediaryType": "2", + "remark": "自动化测试机构数据" +} +``` + +**测试结果:** ✅ 通过 +- 成功创建记录 +- 返回状态码 200 +- 成功获取到新创建的ID: 2006 + +--- + +### 5. 获取中介详情 + +**接口:** `GET /dpc/intermediary/{intermediaryId}` +**描述:** 根据ID获取中介详细信息 + +**请求参数:** +- intermediaryId: 2005 + +**测试结果:** ✅ 通过 +- 成功获取详情信息 +- 返回完整的数据结构 +- 包含所有必要字段 + +--- + +### 6. 修改中介黑名单 + +**接口:** `PUT /dpc/intermediary` +**描述:** 修改已存在的中介信息 + +**请求参数:** +```json +{ + "intermediaryId": 2005, + "name": "测试个人中介_修改", + "certificateNo": "TESTCERT20260129_164311", + "intermediaryType": "1", + "status": "1", + "remark": "修改后的自动化测试数据" +} +``` + +**测试结果:** ✅ 通过 +- 成功更新记录 +- 返回状态码 200 +- 数据修改生效 + +--- + +### 7. 导出中介黑名单列表 + +**接口:** `POST /dpc/intermediary/export` +**描述:** 导出中介黑名单数据为Excel文件 + +**请求参数:** +```json +{} +``` + +**测试结果:** ✅ 通过 +- 成功导出Excel文件 +- 文件格式正确 +- 文件保存至: test_output/test6_export.xlsx + +--- + +### 8. 下载个人中介导入模板 + +**接口:** `POST /dpc/intermediary/importPersonTemplate` +**描述:** 下载个人中介导入Excel模板 + +**测试结果:** ✅ 通过 +- 成功下载模板文件 +- 文件格式正确 +- 文件保存至: test_output/test7_person_template.xlsx + +--- + +### 9. 下载机构中介导入模板 + +**接口:** `POST /dpc/intermediary/importEntityTemplate` +**描述:** 下载机构中介导入Excel模板 + +**测试结果:** ✅ 通过 +- 成功下载模板文件 +- 文件格式正确 +- 文件保存至: test_output/test8_entity_template.xlsx + +--- + +### 10. 条件查询(按中介类型) + +**接口:** `GET /dpc/intermediary/list` +**描述:** 按中介类型筛选查询 + +**请求参数:** +- pageNum: 1 +- pageSize: 10 +- intermediaryType: 1 (个人) + +**测试结果:** ✅ 通过 +- 查询结果正确 +- 数据筛选生效 +- 返回指定类型的数据 + +--- + +### 11. 条件查询(按状态) + +**接口:** `GET /dpc/intermediary/list` +**描述:** 按状态筛选查询 + +**请求参数:** +- pageNum: 1 +- pageSize: 10 +- status: 1 + +**测试结果:** ✅ 通过 +- 查询结果正确 +- 数据筛选生效 +- 返回指定状态的数据 + +--- + +### 12. 删除中介黑名单 + +**接口:** `DELETE /dpc/intermediary/{intermediaryIds}` +**描述:** 批量删除中介黑名单记录 + +**请求参数:** +- intermediaryIds: 2005,2006 + +**测试结果:** ✅ 通过 +- 成功删除记录 +- 返回状态码 200 +- 数据删除生效 + +--- + +## 测试文件清单 + +### 响应JSON文件 +- `test1_list_response.json` - 查询列表响应 +- `test2_add_person_response.json` - 新增个人中介响应 +- `test3_add_entity_response.json` - 新增机构中介响应 +- `test4_get_info_response.json` - 获取详情响应 +- `test5_edit_response.json` - 修改中介响应 +- `test9_remove_response.json` - 删除中介响应 +- `test10_query_by_type_response.json` - 按类型查询响应 +- `test11_query_by_status_response.json` - 按状态查询响应 + +### Excel文件 +- `test6_export.xlsx` - 导出的数据文件 +- `test7_person_template.xlsx` - 个人中介导入模板 +- `test8_entity_template.xlsx` - 机构中介导入模板 + +### 报告文件 +- `test_report_20260129_164311.txt` - 详细测试日志 + +## 结论 + +**所有测试用例均已通过,中介黑名单管理API功能完整且运行正常。** + +### 主要验证点 +1. ✅ 认证授权机制正常 +2. ✅ CRUD操作功能完整 +3. ✅ 分页查询功能正常 +4. ✅ 条件筛选功能正常 +5. ✅ 文件导入导出功能正常 +6. ✅ 批量操作功能正常 + +### 建议 +1. 建议在实际部署前进行压力测试 +2. 建议添加更多的边界条件测试用例 +3. 建议完善错误码和错误信息的文档 + +--- + +**报告生成时间:** 2026-01-29 16:43:11 +**测试工具:** curl + bash +**报告生成者:** Claude Code diff --git a/doc/员工信息管理API文档.md b/doc/api/员工信息管理API文档.md similarity index 100% rename from doc/员工信息管理API文档.md rename to doc/api/员工信息管理API文档.md diff --git a/doc/EasyExcel字典下拉框使用说明.md b/doc/docs/EasyExcel字典下拉框使用说明.md similarity index 100% rename from doc/EasyExcel字典下拉框使用说明.md rename to doc/docs/EasyExcel字典下拉框使用说明.md diff --git a/doc/docs/中介黑名单弹窗优化设计.md b/doc/docs/中介黑名单弹窗优化设计.md new file mode 100644 index 0000000..da39525 --- /dev/null +++ b/doc/docs/中介黑名单弹窗优化设计.md @@ -0,0 +1,153 @@ +# 中介黑名单弹窗优化设计 + +## 需求概述 + +优化中介黑名单的添加弹窗交互流程: +1. 点击新增后先选择中介类型(个人/机构) +2. 然后弹出对应类型的信息输入窗口 +3. 不需要tab栏,直接显示对应类型的表单 +4. 机构类型只需输入一次证件号,该值同时作为"证件号"和"统一社会信用代码" + +## 设计方案 + +### 1. 交互流程 + +**新增操作流程:** + +1. 用户点击"新增"按钮 +2. 弹出一个简洁的对话框,顶部有两个大卡片式按钮:【个人】和【机构】 +3. 用户点击其中一个类型按钮 +4. 对应的表单立即展开显示在下方(无需确认操作) +5. 用户填写信息后点击"确定"提交 + +**修改操作:** +- 修改时直接显示原有数据的表单,不允许切换类型 + +### 2. 界面布局 + +``` +┌─────────────────────────────────────┐ +│ 添加中介黑名单 │ +├─────────────────────────────────────┤ +│ │ +│ ┌─────────┐ ┌─────────┐ │ +│ │ 个人 │ │ 机构 │ │ ← 大卡片式选择按钮(仅新增时显示) +│ └─────────┘ └─────────┘ │ +│ │ +│ ──────────────────────────────── │ ← 分隔线 +│ │ +│ [对应类型的表单字段] │ +│ • 姓名/机构名称 │ +│ • 证件号 │ +│ • 机构类型:统一社会信用代码 │ +│ • 其他选填字段... │ +│ │ +├─────────────────────────────────────┤ +│ [ 确定 ] [ 取消 ] │ +└─────────────────────────────────────┘ +``` + +### 3. 表单字段 + +**个人类型表单字段:** +- 姓名/机构名称*(必填) +- 证件号*(必填) +- 人员类型 +- 人员子类型 +- 性别 +- 证件类型 +- 手机号码 +- 微信号 +- 联系地址 +- 所在公司 +- 职位 +- 关联人员ID +- 关联关系 +- 备注 + +**机构类型表单字段:** +- 姓名/机构名称*(必填) +- 证件号*(必填,自动同步到统一社会信用代码) +- 主体类型 +- 企业性质 +- 成立日期 +- 行业分类 +- 所属行业 +- 注册地址 +- 法定代表人 +- 法定代表人证件类型 +- 法定代表人证件号码 +- 股东1-5 +- 备注 + +### 4. 表单验证规则 + +**个人类型验证:** +```javascript +rules: { + name: [ + { required: true, message: "姓名不能为空", trigger: "blur" }, + { max: 100, message: "姓名长度不能超过100个字符", trigger: "blur" } + ], + certificateNo: [ + { required: true, message: "证件号不能为空", trigger: "blur" }, + { max: 50, message: "证件号长度不能超过50个字符", trigger: "blur" } + ], + remark: [ + { max: 500, message: "备注长度不能超过500个字符", trigger: "blur" } + ] +} +``` + +**机构类型验证:** +```javascript +rules: { + name: [ + { required: true, message: "机构名称不能为空", trigger: "blur" }, + { max: 100, message: "机构名称长度不能超过100个字符", trigger: "blur" } + ], + certificateNo: [ + { required: true, message: "证件号不能为空", trigger: "blur" }, + { max: 18, message: "统一社会信用代码长度为18位", trigger: "blur" } + ], + remark: [ + { max: 500, message: "备注长度不能超过500个字符", trigger: "blur" } + ] +} +``` + +### 5. 边界情况处理 + +| 场景 | 处理方式 | +|------|----------| +| 用户点击新增后未选择类型就点确定 | 禁用"确定"按钮,直到选择类型 | +| 用户选择类型后想重新选择 | 只有关闭弹窗重新打开才能选择 | +| 修改操作时类型锁定 | 隐藏类型选择器,直接显示对应表单 | +| 表单验证失败 | 高亮显示错误字段,滚动到第一个错误位置 | +| 网络请求失败 | 显示错误提示,弹窗保持打开状态 | + +### 6. 用户体验优化 + +1. **视觉反馈**: + - 类型选择按钮在未选中时有hover效果 + - 选中后按钮变为高亮状态,其他按钮变灰 + - 表单展开有淡入动画 + +2. **输入提示**: + - 个人类型的证件号字段下方显示提示:"请输入证件号码" + - 机构类型的证件号字段下方显示提示:"统一社会信用代码(18位)" + +3. **表单布局**: + - 保持两列布局,充分利用空间 + - 必填项(姓名、证件号)标记红色星号 + +### 7. 技术实现要点 + +**状态管理:** +- 新增模式:`isAddMode: true`,显示类型选择器 +- 修改模式:`isAddMode: false`,隐藏类型选择器 +- 已选类型:`selectedType: '1' | '2' | null` + +**数据同步:** +- 机构类型提交时,将 `form.certificateNo` 的值同时赋给 `form.corpCreditCode` + diff --git a/doc/纪检初核系统功能说明书-V1.0.docx b/doc/docs/纪检初核系统功能说明书-V1.0.docx similarity index 100% rename from doc/纪检初核系统功能说明书-V1.0.docx rename to doc/docs/纪检初核系统功能说明书-V1.0.docx diff --git a/doc/纪检初核系统功能说明书-V1.0.md b/doc/docs/纪检初核系统功能说明书-V1.0.md similarity index 100% rename from doc/纪检初核系统功能说明书-V1.0.md rename to doc/docs/纪检初核系统功能说明书-V1.0.md diff --git a/doc/纪检初核系统功能说明书-V1.0.with.image.md b/doc/docs/纪检初核系统功能说明书-V1.0.with.image.md similarity index 100% rename from doc/纪检初核系统功能说明书-V1.0.with.image.md rename to doc/docs/纪检初核系统功能说明书-V1.0.with.image.md diff --git a/doc/纪检初核系统模块划分方案.md b/doc/docs/纪检初核系统模块划分方案.md similarity index 100% rename from doc/纪检初核系统模块划分方案.md rename to doc/docs/纪检初核系统模块划分方案.md diff --git a/doc/若依环境使用手册.docx b/doc/docs/若依环境使用手册.docx similarity index 100% rename from doc/若依环境使用手册.docx rename to doc/docs/若依环境使用手册.docx diff --git a/doc/other/ScreenShot_2026-01-29_155814_876.png b/doc/other/ScreenShot_2026-01-29_155814_876.png new file mode 100644 index 0000000..703505e Binary files /dev/null and b/doc/other/ScreenShot_2026-01-29_155814_876.png differ diff --git a/doc/other/中介黑名单导入功能修复说明.md b/doc/other/中介黑名单导入功能修复说明.md new file mode 100644 index 0000000..285ed7f --- /dev/null +++ b/doc/other/中介黑名单导入功能修复说明.md @@ -0,0 +1,162 @@ +# 中介黑名单导入功能修复说明 + +## 问题描述 + +在导入机构中介黑名单数据时,出现以下错误: + +``` +Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException: Column 'certificate_no' cannot be null +``` + +## 问题原因 + +1. **数据库约束**:`dpc_intermediary_blacklist` 表的 `certificate_no` 字段设置为 `NOT NULL`,不允许存储 null 值。 + +2. **代码缺陷**:在 `DpcIntermediaryBlacklistServiceImpl.java` 的 `importEntityIntermediary` 方法中,导入机构中介时只设置了 `corpCreditCode`(统一社会信用代码),但没有设置 `certificateNo` 字段,导致该字段为 null。 + +3. **批量插入失败**:`batchInsert` 方法明确插入 `certificate_no` 字段,当值为 null 时违反数据库约束。 + +## 解决方案 + +### 1. 代码修改 + +**文件**:[DpcIntermediaryBlacklistServiceImpl.java](d:\discipline-prelim-check\discipline-prelim-check\ruoyi-dpc\src\main\java\com\ruoyi\dpc\service\impl\DpcIntermediaryBlacklistServiceImpl.java) + +**修改位置**:第 390-394 行 + +**修改前**: +```java +// 转换为实体 +DpcIntermediaryBlacklist intermediary = new DpcIntermediaryBlacklist(); +intermediary.setName(excel.getName()); +intermediary.setIntermediaryType("2"); +``` + +**修改后**: +```java +// 转换为实体 +DpcIntermediaryBlacklist intermediary = new DpcIntermediaryBlacklist(); +intermediary.setName(excel.getName()); +// 对于机构中介,使用统一社会信用代码作为证件号 +intermediary.setCertificateNo(excel.getCorpCreditCode()); +intermediary.setIntermediaryType("2"); +``` + +### 2. 验证逻辑增强 + +**文件**:[DpcIntermediaryBlacklistServiceImpl.java](d:\discipline-prelim-check\discipline-prelim-check\ruoyi-dpc\src\main\java\com\ruoyi\dpc\service\impl\DpcIntermediaryBlacklistServiceImpl.java) + +**修改位置**:第 484-488 行 + +**修改前**: +```java +private void validateEntityIntermediaryData(DpcIntermediaryEntityExcel excel) { + if (StringUtils.isEmpty(excel.getName())) { + throw new RuntimeException("机构名称不能为空"); + } +} +``` + +**修改后**: +```java +private void validateEntityIntermediaryData(DpcIntermediaryEntityExcel excel) { + if (StringUtils.isEmpty(excel.getName())) { + throw new RuntimeException("机构名称不能为空"); + } + // 验证统一社会信用代码不能为空(因为会用作 certificate_no 字段) + if (StringUtils.isEmpty(excel.getCorpCreditCode())) { + throw new RuntimeException("统一社会信用代码不能为空"); + } +} +``` + +### 3. 批量更新 XML 配置优化 + +**文件**:[DpcIntermediaryBlacklistMapper.xml](d:\discipline-prelim-check\discipline-prelim-check\ruoyi-dpc\src\main\resources\mapper\dpc\DpcIntermediaryBlacklistMapper.xml) + +**修改位置**:第 125-127 行 + +**修改前**: +```xml +data_source = #{item.dataSource}, +update_by = #{item.updateBy}, +update_time = #{item.updateTime} +``` + +**修改后**: +```xml +data_source = #{item.dataSource}, +certificate_no = #{item.certificateNo}, +update_by = #{item.updateBy}, +update_time = #{item.updateTime} +``` + +## 设计说明 + +### 为什么使用统一社会信用代码作为证件号? + +1. **数据一致性**:统一社会信用代码本身就是机构的法定证件号,将其同时存储在 `certificate_no` 字段中可以保持数据的一致性。 + +2. **查询便利**:`certificate_no` 字段有索引,设置后可以快速查询机构中介。 + +3. **兼容性好**:个人中介和机构中介都使用 `certificate_no` 字段,查询逻辑更统一。 + +4. **不破坏现有结构**:不需要修改数据库表结构,只修改代码逻辑。 + +## 测试验证 + +### 测试用例 + +1. **个人中介导入**:正常导入个人中介数据,验证 `certificate_no` 字段正确存储身份证号。 + +2. **机构中介导入**:导入机构中介数据,验证 `certificate_no` 字段正确存储统一社会信用代码。 + +3. **统一社会信用代码为空**:验证当统一社会信用代码为空时,导入被正确拒绝并给出错误提示。 + +4. **批量更新**:验证批量更新时 `certificate_no` 字段能够正确更新。 + +### 测试脚本 + +测试脚本位于:[doc/test-data/test_import_fix.py](d:\discipline-prelim-check\discipline-prelim-check\doc\test-data\test_import_fix.py) + +运行测试: +```bash +python doc/test-data/test_import_fix.py +``` + +## 影响范围 + +### 已影响的功能 +- 机构中介批量导入功能 + +### 不影响的功能 +- 个人中介导入功能 +- 手动新增中介功能 +- 中介查询功能 +- 中介导出功能 + +## 注意事项 + +1. **数据迁移**:如果数据库中已存在机构中介数据且 `certificate_no` 为 null,需要执行以下 SQL 进行数据修复: + +```sql +UPDATE dpc_intermediary_blacklist +SET certificate_no = corp_credit_code +WHERE intermediary_type = '2' AND certificate_no IS NULL AND corp_credit_code IS NOT NULL; +``` + +2. **Excel 模板**:确保导入模板中统一社会信用代码字段设置为必填项。 + +3. **前端验证**:建议在前端表单中也添加统一社会信用代码的必填验证。 + +## 修改文件列表 + +1. [DpcIntermediaryBlacklistServiceImpl.java](d:\discipline-prelim-check\discipline-prelim-check\ruoyi-dpc\src\main\java\com\ruoyi\dpc\service\impl\DpcIntermediaryBlacklistServiceImpl.java) - 服务层实现 +2. [DpcIntermediaryBlacklistMapper.xml](d:\discipline-prelim-check\discipline-prelim-check\ruoyi-dpc\src\main\resources\mapper\dpc\DpcIntermediaryBlacklistMapper.xml) - MyBatis 映射文件 +3. [test_import_fix.py](d:\discipline-prelim-check\discipline-prelim-check\doc\test-data\test_import_fix.py) - 测试脚本 + +## 版本历史 + +| 版本 | 日期 | 作者 | 说明 | +|------|------|------|------| +| 1.0 | 2026-01-29 | ruoyi | 初始版本,修复机构中介导入时 certificate_no 为 null 的问题 | diff --git a/doc/纪检初核系统-离线演示包.zip b/doc/other/纪检初核系统-离线演示包.zip similarity index 100% rename from doc/纪检初核系统-离线演示包.zip rename to doc/other/纪检初核系统-离线演示包.zip diff --git a/doc/纪检初核系统-离线演示包/env/2203.js b/doc/other/纪检初核系统-离线演示包/env/2203.js similarity index 100% rename from doc/纪检初核系统-离线演示包/env/2203.js rename to doc/other/纪检初核系统-离线演示包/env/2203.js diff --git a/doc/纪检初核系统-离线演示包/extra/TAG_V3NXya0fYxmDs8mWSM69pSHMU20260127T00_20260127T001110126Z b/doc/other/纪检初核系统-离线演示包/extra/TAG_V3NXya0fYxmDs8mWSM69pSHMU20260127T00_20260127T001110126Z similarity index 100% rename from doc/纪检初核系统-离线演示包/extra/TAG_V3NXya0fYxmDs8mWSM69pSHMU20260127T00_20260127T001110126Z rename to doc/other/纪检初核系统-离线演示包/extra/TAG_V3NXya0fYxmDs8mWSM69pSHMU20260127T00_20260127T001110126Z diff --git a/doc/纪检初核系统-离线演示包/extra/data.0.js b/doc/other/纪检初核系统-离线演示包/extra/data.0.js similarity index 100% rename from doc/纪检初核系统-离线演示包/extra/data.0.js rename to doc/other/纪检初核系统-离线演示包/extra/data.0.js diff --git a/doc/纪检初核系统-离线演示包/extra/data.1.js b/doc/other/纪检初核系统-离线演示包/extra/data.1.js similarity index 100% rename from doc/纪检初核系统-离线演示包/extra/data.1.js rename to doc/other/纪检初核系统-离线演示包/extra/data.1.js diff --git a/doc/纪检初核系统-离线演示包/extra/data.2.js b/doc/other/纪检初核系统-离线演示包/extra/data.2.js similarity index 100% rename from doc/纪检初核系统-离线演示包/extra/data.2.js rename to doc/other/纪检初核系统-离线演示包/extra/data.2.js diff --git a/doc/纪检初核系统-离线演示包/index.html b/doc/other/纪检初核系统-离线演示包/index.html similarity index 100% rename from doc/纪检初核系统-离线演示包/index.html rename to doc/other/纪检初核系统-离线演示包/index.html diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/3.h4vam-vendor-5567a1235ac230e00561.js b/doc/other/纪检初核系统-离线演示包/mb-proto2/3.h4vam-vendor-5567a1235ac230e00561.js similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/3.h4vam-vendor-5567a1235ac230e00561.js rename to doc/other/纪检初核系统-离线演示包/mb-proto2/3.h4vam-vendor-5567a1235ac230e00561.js diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/4.ekpaa-vendor-4a8c0d8af0989de4a89f.js b/doc/other/纪检初核系统-离线演示包/mb-proto2/4.ekpaa-vendor-4a8c0d8af0989de4a89f.js similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/4.ekpaa-vendor-4a8c0d8af0989de4a89f.js rename to doc/other/纪检初核系统-离线演示包/mb-proto2/4.ekpaa-vendor-4a8c0d8af0989de4a89f.js diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/4.n9fxu-vendor-121f3fbb2320541a30bc.js b/doc/other/纪检初核系统-离线演示包/mb-proto2/4.n9fxu-vendor-121f3fbb2320541a30bc.js similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/4.n9fxu-vendor-121f3fbb2320541a30bc.js rename to doc/other/纪检初核系统-离线演示包/mb-proto2/4.n9fxu-vendor-121f3fbb2320541a30bc.js diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/5.7b24m-vendor-c6215ade32c4d6e04f4c.js b/doc/other/纪检初核系统-离线演示包/mb-proto2/5.7b24m-vendor-c6215ade32c4d6e04f4c.js similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/5.7b24m-vendor-c6215ade32c4d6e04f4c.js rename to doc/other/纪检初核系统-离线演示包/mb-proto2/5.7b24m-vendor-c6215ade32c4d6e04f4c.js diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/5.fxqum-vendor-f8aaf1fb2db7ed4b19df.js b/doc/other/纪检初核系统-离线演示包/mb-proto2/5.fxqum-vendor-f8aaf1fb2db7ed4b19df.js similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/5.fxqum-vendor-f8aaf1fb2db7ed4b19df.js rename to doc/other/纪检初核系统-离线演示包/mb-proto2/5.fxqum-vendor-f8aaf1fb2db7ed4b19df.js diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/6.3688a-vendor-0d07687f4be09b8b3eca.js b/doc/other/纪检初核系统-离线演示包/mb-proto2/6.3688a-vendor-0d07687f4be09b8b3eca.js similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/6.3688a-vendor-0d07687f4be09b8b3eca.js rename to doc/other/纪检初核系统-离线演示包/mb-proto2/6.3688a-vendor-0d07687f4be09b8b3eca.js diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/6.3688a-vendor-16f3ece222913e7058d1.css b/doc/other/纪检初核系统-离线演示包/mb-proto2/6.3688a-vendor-16f3ece222913e7058d1.css similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/6.3688a-vendor-16f3ece222913e7058d1.css rename to doc/other/纪检初核系统-离线演示包/mb-proto2/6.3688a-vendor-16f3ece222913e7058d1.css diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mate60.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mate60.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mate60.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mate60.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mate60_pro.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mate60_pro.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mate60_pro.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mate60_pro.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mate70.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mate70.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mate70.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mate70.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mate70_pro.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mate70_pro.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mate70_pro.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mate70_pro.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mate70_pro_plus.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mate70_pro_plus.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mate70_pro_plus.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mate70_pro_plus.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mateX5_expand.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mateX5_expand.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mateX5_expand.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mateX5_expand.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mateX5_fold.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mateX5_fold.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mateX5_fold.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mateX5_fold.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mateXT_one_screen.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mateXT_one_screen.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mateXT_one_screen.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mateXT_one_screen.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mateXT_three_screen.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mateXT_three_screen.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mateXT_three_screen.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mateXT_three_screen.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mateXT_two_screen.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mateXT_two_screen.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mateXT_two_screen.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mateXT_two_screen.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mate_book_14s.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mate_book_14s.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mate_book_14s.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mate_book_14s.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mate_book_16s.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mate_book_16s.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mate_book_16s.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mate_book_16s.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mate_pad_pro_11.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mate_pad_pro_11.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mate_pad_pro_11.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mate_pad_pro_11.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mate_pad_pro_13_2.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mate_pad_pro_13_2.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mate_pad_pro_13_2.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_mate_pad_pro_13_2.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_watch_gt4_41.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_watch_gt4_41.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_watch_gt4_41.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_watch_gt4_41.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_watch_gt4_46.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_watch_gt4_46.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_watch_gt4_46.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_watch_gt4_46.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_watch_gt5_41.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_watch_gt5_41.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_watch_gt5_41.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_watch_gt5_41.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_watch_gt5_46.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_watch_gt5_46.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_watch_gt5_46.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_watch_gt5_46.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_wristband_8.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_wristband_8.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_wristband_8.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_wristband_8.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_wristband_9.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_wristband_9.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_wristband_9.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Huawei_wristband_9.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Xiaomi_14.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Xiaomi_14.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Xiaomi_14.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Xiaomi_14.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Xiaomi_15.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Xiaomi_15.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Xiaomi_15.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Xiaomi_15.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Xiaomi_wristband_8.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Xiaomi_wristband_8.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Xiaomi_wristband_8.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Xiaomi_wristband_8.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Xiaomi_wristband_9.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Xiaomi_wristband_9.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/Xiaomi_wristband_9.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/Xiaomi_wristband_9.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/apple_watch_38.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/apple_watch_38.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/apple_watch_38.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/apple_watch_38.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/apple_watch_40.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/apple_watch_40.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/apple_watch_40.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/apple_watch_40.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/apple_watch_42.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/apple_watch_42.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/apple_watch_42.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/apple_watch_42.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/apple_watch_44.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/apple_watch_44.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/apple_watch_44.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/apple_watch_44.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/apple_watch_9_41.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/apple_watch_9_41.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/apple_watch_9_41.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/apple_watch_9_41.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/apple_watch_9_45.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/apple_watch_9_45.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/apple_watch_9_45.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/apple_watch_9_45.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/apple_watch_se_40.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/apple_watch_se_40.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/apple_watch_se_40.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/apple_watch_se_40.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/apple_watch_se_44.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/apple_watch_se_44.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/apple_watch_se_44.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/apple_watch_se_44.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/apple_watch_ultra_2_49.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/apple_watch_ultra_2_49.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/apple_watch_ultra_2_49.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/apple_watch_ultra_2_49.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/car_play.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/car_play.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/car_play.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/car_play.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/desktop.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/desktop.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/desktop.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/desktop.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/desktop_1920.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/desktop_1920.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/desktop_1920.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/desktop_1920.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/google_pixel_2.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/google_pixel_2.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/google_pixel_2.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/google_pixel_2.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/google_pixel_2_xl.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/google_pixel_2_xl.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/google_pixel_2_xl.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/google_pixel_2_xl.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/huawei_p40.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/huawei_p40.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/huawei_p40.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/huawei_p40.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/huawei_p40_v2.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/huawei_p40_v2.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/huawei_p40_v2.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/huawei_p40_v2.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/huawei_p9.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/huawei_p9.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/huawei_p9.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/huawei_p9.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/imac.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/imac.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/imac.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/imac.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/imac_2023.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/imac_2023.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/imac_2023.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/imac_2023.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/industrial_hmi_16_10.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/industrial_hmi_16_10.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/industrial_hmi_16_10.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/industrial_hmi_16_10.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/industrial_hmi_16_9.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/industrial_hmi_16_9.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/industrial_hmi_16_9.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/industrial_hmi_16_9.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/industrial_hmi_4_3.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/industrial_hmi_4_3.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/industrial_hmi_4_3.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/industrial_hmi_4_3.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/ipad.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/ipad.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/ipad.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/ipad.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/ipad_2023.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/ipad_2023.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/ipad_2023.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/ipad_2023.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/ipad_mini.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/ipad_mini.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/ipad_mini.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/ipad_mini.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/ipad_pro.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/ipad_pro.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/ipad_pro.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/ipad_pro.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/ipad_pro_11.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/ipad_pro_11.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/ipad_pro_11.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/ipad_pro_11.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/ipad_pro_12.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/ipad_pro_12.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/ipad_pro_12.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/ipad_pro_12.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_11.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_11.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_11.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_11.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_12.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_12.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_12.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_12.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_12_pro_max.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_12_pro_max.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_12_pro_max.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_12_pro_max.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_13.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_13.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_13.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_13.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_13_mini.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_13_mini.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_13_mini.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_13_mini.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_13_pro_max.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_13_pro_max.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_13_pro_max.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_13_pro_max.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_14.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_14.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_14.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_14.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_14_plus.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_14_plus.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_14_plus.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_14_plus.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_14_pro_max.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_14_pro_max.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_14_pro_max.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_14_pro_max.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_15.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_15.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_15.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_15.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_15_plus.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_15_plus.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_15_plus.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_15_plus.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_15_pro.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_15_pro.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_15_pro.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_15_pro.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_15_pro_max.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_15_pro_max.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_15_pro_max.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_15_pro_max.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_16.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_16.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_16.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_16.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_16_plus.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_16_plus.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_16_plus.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_16_plus.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_16_pro.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_16_pro.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_16_pro.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_16_pro.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_16_pro_max.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_16_pro_max.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_16_pro_max.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_16_pro_max.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_17.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_17.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_17.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_17.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_17_pro.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_17_pro.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_17_pro.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_17_pro.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_17_pro_max.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_17_pro_max.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_17_pro_max.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_17_pro_max.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_7.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_7.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_7.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_7.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_7_plus.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_7_plus.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_7_plus.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_7_plus.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_air.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_air.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_air.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_air.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_se.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_se.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_se.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_se.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_x.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_x.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_x.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_x.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_xs_max.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_xs_max.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_xs_max.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/iphone_xs_max.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/mac_book_air_13.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/mac_book_air_13.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/mac_book_air_13.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/mac_book_air_13.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/mac_book_pro.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/mac_book_pro.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/mac_book_pro.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/mac_book_pro.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/mac_book_pro_14.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/mac_book_pro_14.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/mac_book_pro_14.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/mac_book_pro_14.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/mac_book_pro_16.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/mac_book_pro_16.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/mac_book_pro_16.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/mac_book_pro_16.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/nexus_5.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/nexus_5.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/nexus_5.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/nexus_5.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/samsung_galaxy_s23.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/samsung_galaxy_s23.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/samsung_galaxy_s23.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/samsung_galaxy_s23.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/samsung_s7.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/samsung_s7.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/samsung_s7.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/samsung_s7.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/sony_w850c.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/sony_w850c.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/sony_w850c.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/sony_w850c.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/devices/tesla_car_play_hmi.png b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/tesla_car_play_hmi.png similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/devices/tesla_car_play_hmi.png rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/devices/tesla_car_play_hmi.png diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/mktWM/watermark_m.svg b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/mktWM/watermark_m.svg similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/mktWM/watermark_m.svg rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/mktWM/watermark_m.svg diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/images/mktWM/watermark_s.svg b/doc/other/纪检初核系统-离线演示包/mb-proto2/images/mktWM/watermark_s.svg similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/images/mktWM/watermark_s.svg rename to doc/other/纪检初核系统-离线演示包/mb-proto2/images/mktWM/watermark_s.svg diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/lazy-lib-dl-906655530ecd54e72602.js b/doc/other/纪检初核系统-离线演示包/mb-proto2/lazy-lib-dl-906655530ecd54e72602.js similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/lazy-lib-dl-906655530ecd54e72602.js rename to doc/other/纪检初核系统-离线演示包/mb-proto2/lazy-lib-dl-906655530ecd54e72602.js diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/lazy-lib-fontkit-94d1920236ee8aff3185.js b/doc/other/纪检初核系统-离线演示包/mb-proto2/lazy-lib-fontkit-94d1920236ee8aff3185.js similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/lazy-lib-fontkit-94d1920236ee8aff3185.js rename to doc/other/纪检初核系统-离线演示包/mb-proto2/lazy-lib-fontkit-94d1920236ee8aff3185.js diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/lazy-lib-i18n-4c3a2d14ad63ee44927b.js b/doc/other/纪检初核系统-离线演示包/mb-proto2/lazy-lib-i18n-4c3a2d14ad63ee44927b.js similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/lazy-lib-i18n-4c3a2d14ad63ee44927b.js rename to doc/other/纪检初核系统-离线演示包/mb-proto2/lazy-lib-i18n-4c3a2d14ad63ee44927b.js diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/lazy-lib-paper-5a9908939d850d4cae67.js b/doc/other/纪检初核系统-离线演示包/mb-proto2/lazy-lib-paper-5a9908939d850d4cae67.js similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/lazy-lib-paper-5a9908939d850d4cae67.js rename to doc/other/纪检初核系统-离线演示包/mb-proto2/lazy-lib-paper-5a9908939d850d4cae67.js diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/lazy-lib-rehype-013772de7c49f3c667fa.js b/doc/other/纪检初核系统-离线演示包/mb-proto2/lazy-lib-rehype-013772de7c49f3c667fa.js similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/lazy-lib-rehype-013772de7c49f3c667fa.js rename to doc/other/纪检初核系统-离线演示包/mb-proto2/lazy-lib-rehype-013772de7c49f3c667fa.js diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/preview-html-zip-40b1c65b44de21c4ab8a.js b/doc/other/纪检初核系统-离线演示包/mb-proto2/preview-html-zip-40b1c65b44de21c4ab8a.js similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/preview-html-zip-40b1c65b44de21c4ab8a.js rename to doc/other/纪检初核系统-离线演示包/mb-proto2/preview-html-zip-40b1c65b44de21c4ab8a.js diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/preview-html-zip-f0d9de76208db26b1137.css b/doc/other/纪检初核系统-离线演示包/mb-proto2/preview-html-zip-f0d9de76208db26b1137.css similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/preview-html-zip-f0d9de76208db26b1137.css rename to doc/other/纪检初核系统-离线演示包/mb-proto2/preview-html-zip-f0d9de76208db26b1137.css diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/res-custom-41be04f25a7d92ab86c8.woff b/doc/other/纪检初核系统-离线演示包/mb-proto2/res-custom-41be04f25a7d92ab86c8.woff similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/res-custom-41be04f25a7d92ab86c8.woff rename to doc/other/纪检初核系统-离线演示包/mb-proto2/res-custom-41be04f25a7d92ab86c8.woff diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/res-dora-6079e0b71b8a8652eb1b.woff b/doc/other/纪检初核系统-离线演示包/mb-proto2/res-dora-6079e0b71b8a8652eb1b.woff similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/res-dora-6079e0b71b8a8652eb1b.woff rename to doc/other/纪检初核系统-离线演示包/mb-proto2/res-dora-6079e0b71b8a8652eb1b.woff diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/res-font-awesome-f691f37e57f04c152e23.woff b/doc/other/纪检初核系统-离线演示包/mb-proto2/res-font-awesome-f691f37e57f04c152e23.woff similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/res-font-awesome-f691f37e57f04c152e23.woff rename to doc/other/纪检初核系统-离线演示包/mb-proto2/res-font-awesome-f691f37e57f04c152e23.woff diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/res-material-83bebaf37c09c7e1c3ee.woff b/doc/other/纪检初核系统-离线演示包/mb-proto2/res-material-83bebaf37c09c7e1c3ee.woff similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/res-material-83bebaf37c09c7e1c3ee.woff rename to doc/other/纪检初核系统-离线演示包/mb-proto2/res-material-83bebaf37c09c7e1c3ee.woff diff --git a/doc/纪检初核系统-离线演示包/mb-proto2/res-mb-icons-9615a49d65d72a59aa3a.woff b/doc/other/纪检初核系统-离线演示包/mb-proto2/res-mb-icons-9615a49d65d72a59aa3a.woff similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-proto2/res-mb-icons-9615a49d65d72a59aa3a.woff rename to doc/other/纪检初核系统-离线演示包/mb-proto2/res-mb-icons-9615a49d65d72a59aa3a.woff diff --git a/doc/纪检初核系统-离线演示包/mb-static/2308/core-js-3.32.1/modern.js b/doc/other/纪检初核系统-离线演示包/mb-static/2308/core-js-3.32.1/modern.js similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-static/2308/core-js-3.32.1/modern.js rename to doc/other/纪检初核系统-离线演示包/mb-static/2308/core-js-3.32.1/modern.js diff --git a/doc/纪检初核系统-离线演示包/mb-static/2410/echarts-map/loadMap.js b/doc/other/纪检初核系统-离线演示包/mb-static/2410/echarts-map/loadMap.js similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-static/2410/echarts-map/loadMap.js rename to doc/other/纪检初核系统-离线演示包/mb-static/2410/echarts-map/loadMap.js diff --git a/doc/纪检初核系统-离线演示包/mb-static/2509/loading-logo.gif b/doc/other/纪检初核系统-离线演示包/mb-static/2509/loading-logo.gif similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-static/2509/loading-logo.gif rename to doc/other/纪检初核系统-离线演示包/mb-static/2509/loading-logo.gif diff --git a/doc/纪检初核系统-离线演示包/mb-static/2509/loading.gif b/doc/other/纪检初核系统-离线演示包/mb-static/2509/loading.gif similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-static/2509/loading.gif rename to doc/other/纪检初核系统-离线演示包/mb-static/2509/loading.gif diff --git a/doc/纪检初核系统-离线演示包/mb-static/2509/logo-rect-dark.svg b/doc/other/纪检初核系统-离线演示包/mb-static/2509/logo-rect-dark.svg similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-static/2509/logo-rect-dark.svg rename to doc/other/纪检初核系统-离线演示包/mb-static/2509/logo-rect-dark.svg diff --git a/doc/纪检初核系统-离线演示包/mb-static/2509/logo-rect-light.svg b/doc/other/纪检初核系统-离线演示包/mb-static/2509/logo-rect-light.svg similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-static/2509/logo-rect-light.svg rename to doc/other/纪检初核系统-离线演示包/mb-static/2509/logo-rect-light.svg diff --git a/doc/纪检初核系统-离线演示包/mb-static/2509/logo-rect.svg b/doc/other/纪检初核系统-离线演示包/mb-static/2509/logo-rect.svg similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-static/2509/logo-rect.svg rename to doc/other/纪检初核系统-离线演示包/mb-static/2509/logo-rect.svg diff --git a/doc/纪检初核系统-离线演示包/mb-static/2509/logo-text.svg b/doc/other/纪检初核系统-离线演示包/mb-static/2509/logo-text.svg similarity index 100% rename from doc/纪检初核系统-离线演示包/mb-static/2509/logo-text.svg rename to doc/other/纪检初核系统-离线演示包/mb-static/2509/logo-text.svg diff --git a/doc/纪检初核系统-离线演示包/uploads7/images/14128/141282287/v2_smx0cl.png b/doc/other/纪检初核系统-离线演示包/uploads7/images/14128/141282287/v2_smx0cl.png similarity index 100% rename from doc/纪检初核系统-离线演示包/uploads7/images/14128/141282287/v2_smx0cl.png rename to doc/other/纪检初核系统-离线演示包/uploads7/images/14128/141282287/v2_smx0cl.png diff --git a/doc/纪检初核系统-离线演示包/总览模式.html b/doc/other/纪检初核系统-离线演示包/总览模式.html similarity index 100% rename from doc/纪检初核系统-离线演示包/总览模式.html rename to doc/other/纪检初核系统-离线演示包/总览模式.html diff --git a/doc/纪检初核系统-离线演示包/标注模式.html b/doc/other/纪检初核系统-离线演示包/标注模式.html similarity index 100% rename from doc/纪检初核系统-离线演示包/标注模式.html rename to doc/other/纪检初核系统-离线演示包/标注模式.html diff --git a/doc/纪检初核系统-离线演示包/演示模式.html b/doc/other/纪检初核系统-离线演示包/演示模式.html similarity index 100% rename from doc/纪检初核系统-离线演示包/演示模式.html rename to doc/other/纪检初核系统-离线演示包/演示模式.html diff --git a/doc/scripts/README.md b/doc/scripts/README.md new file mode 100644 index 0000000..5411f03 --- /dev/null +++ b/doc/scripts/README.md @@ -0,0 +1,135 @@ +# 中介黑名单弹窗优化功能测试 + +## 测试概述 + +本测试套件用于验证中介黑名单弹窗优化后的功能正确性,主要包括: + +1. **新增模式交互**:验证类型选择卡片的用户体验 +2. **表单验证**:验证个人/机构类型的字段验证规则 +3. **数据同步**:验证机构类型证件号与统一社会信用代码的同步 +4. **修改模式锁定**:验证修改时类型不可更改 +5. **边界情况处理**:验证各种异常输入的处理 + +## 运行测试 + +### 前置条件 + +1. 后端服务已启动(默认 `http://localhost:8080`) +2. 测试账号可用(`admin/admin123`) +3. 已安装 Node.js + +### 安装依赖 + +```bash +cd doc/scripts +npm install +``` + +### 执行测试 + +```bash +# 直接运行测试(输出到控制台) +npm test + +# 运行测试并生成报告文件 +npm run test:report + +# 或者直接使用 Node.js +node test_intermediary_dialog.js +``` + +## 测试用例说明 + +| 测试编号 | 测试名称 | 测试目标 | 预期结果 | +|---------|---------|---------|---------| +| 1 | 登录系统 | 获取认证Token | 成功获取Token | +| 2 | 新增个人中介-必填字段 | 验证姓名和证件号必填 | 缺少必填项时被拒绝 | +| 3 | 新增个人中介-字段长度 | 验证字段长度限制 | 超长时被拒绝 | +| 4 | 新增机构中介-证件号同步 | 验证证件号同步到统一社会信用代码 | 两字段值一致 | +| 5 | 新增机构中介-信用代码长度 | 验证统一社会信用代码长度 | 前端限制18位 | +| 6 | 修改个人中介-类型锁定 | 验证修改时类型不可更改 | 类型字段保持不变 | +| 7 | 修改机构中介-类型锁定 | 验证修改时类型不可更改 | 类型字段保持不变 | +| 8 | 新增无类型 | 验证未选择类型无法提交 | 后端拒绝请求 | +| 9 | 查询列表 | 验证数据正确性 | 返回正确的类型分布 | + +## 测试报告示例 + +``` +============================================================== +测试1:登录系统 +============================================================== +✓ 通过 - 登录成功 + Token: eyJhbGciOiJIUzUxMiJ9... + +============================================================== +测试2:新增个人中介 - 验证必填字段 +============================================================== +✓ 通过 - 空姓名 + 应该被拒绝 +✓ 通过 - 空证件号 + 应该被拒绝 +✓ 通过 - 完整必填字段 + 成功创建,ID: 123 + +... +``` + +## 功能验证清单 + +### 前端交互验证 + +- [ ] 点击新增后显示类型选择卡片 +- [ ] 卡片有 hover 效果 +- [ ] 点击卡片后表单展开带淡入动画 +- [ ] 点击卡片后表单不立即显示验证错误 +- [ ] 未选择类型时确定按钮被禁用 +- [ ] 个人类型表单显示正确的字段 +- [ ] 机构类型表单显示正确的字段 +- [ ] 个人类型证件号字段显示正确的占位符:"请输入证件号码" +- [ ] 机构类型证件号字段显示正确的占位符:"统一社会信用代码(18位)" +- [ ] 证件号输入框后无提示图标 + +### 表单验证验证 + +- [ ] 个人类型姓名必填验证 +- [ ] 个人类型证件号必填验证 +- [ ] 机构类型名称必填验证 +- [ ] 机构类型证件号必填验证 +- [ ] 机构类型证件号长度限制18位 +- [ ] 备注字段长度限制500字符 + +### 数据同步验证 + +- [ ] 机构类型输入证件号后自动同步到统一社会信用代码 +- [ ] 提交时两个字段值一致 + +### 修改模式验证 + +- [ ] 修改时直接显示对应类型表单 +- [ ] 修改时不显示类型选择器 +- [ ] 修改时类型字段不可更改 + +## 故障排查 + +### 测试失败常见原因 + +1. **后端服务未启动** + - 检查 `http://localhost:8080` 是否可访问 + - 检查后端日志是否有错误 + +2. **认证失败** + - 确认测试账号密码正确 + - 检查后端是否启用了认证 + +3. **端口冲突** + - 修改 `CONFIG.baseURL` 为实际后端地址 + +4. **依赖缺失** + - 运行 `npm install` 安装依赖 + +## 注意事项 + +1. 测试会创建真实数据,测试结束后会自动清理 +2. 请勿在生产环境运行测试 +3. 如需修改测试数据,编辑 `CONFIG` 对象 +4. 测试报告会保存在 `test_report.txt` 文件中 diff --git a/doc/scripts/generate_test_data.py b/doc/scripts/generate_test_data.py new file mode 100644 index 0000000..68d832b --- /dev/null +++ b/doc/scripts/generate_test_data.py @@ -0,0 +1,193 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +根据模板文件生成1000条个人中介黑名单测试数据 +""" + +import openpyxl +from openpyxl.styles import Font, PatternFill, Alignment +import random +from datetime import datetime + +# 配置 +TEMPLATE_FILE = "doc/个人中介黑名单模板_1769667622015.xlsx" +OUTPUT_FILE = "doc/个人中介黑名单测试数据_1000条_第2批.xlsx" +ROW_COUNT = 1000 + +# 姓氏和名字库 +SURNAMES = ['王', '李', '张', '刘', '陈', '杨', '黄', '赵', '周', '吴', '徐', '孙', '马', '朱', '胡', '郭', '何', '高', '林', '罗'] +GIVEN_NAMES = ['伟', '芳', '娜', '敏', '静', '丽', '强', '磊', '军', '洋', '勇', '艳', '杰', '娟', '涛', '明', '超', '秀英', '霞', '平', '刚', '桂英', '玉兰', '萍', '毅', '浩', '宇', '轩', '然', '梓'] + +# 人员类型 +INDIV_TYPES = ['中介', '职业背债人', '房产中介', '贷款中介', '其他'] + +# 人员子类型 +INDIV_SUB_TYPES = ['本人', '配偶', '父亲', '母亲', '儿子', '女儿'] + +# 性别 +GENDERS = ['男', '女'] + +# 证件类型 +CERT_TYPES = ['身份证', '护照', '军官证', '其他'] + +# 关联关系 +RELATIONS = ['配偶', '父母', '子女', '兄弟姐妹', '同事', '朋友', '合伙人', '其他'] + +# 公司类型 +COMPANIES = ['中原地产', '链家地产', '我爱我家', '21世纪不动产', 'Q房网', '安居客', '房天下', '麦田房产', '鑫置地产', '嘉业地产'] + +# 职位 +POSITIONS = ['经纪人', '高级经纪人', '店长', '区域经理', '业务员', '顾问', '总监', '助理', '专员'] + +# 城市和区域数据 +CITIES = { + '北京': ['朝阳区', '海淀区', '东城区', '西城区', '丰台区', '通州区'], + '上海': ['浦东新区', '黄浦区', '徐汇区', '长宁区', '静安区', '普陀区'], + '广州': ['天河区', '越秀区', '海珠区', '荔湾区', '白云区', '番禺区'], + '深圳': ['福田区', '南山区', '罗湖区', '宝安区', '龙岗区', '盐田区'], + '杭州': ['西湖区', '上城区', '下城区', '江干区', '拱墅区', '滨江区'], + '成都': ['武侯区', '锦江区', '青羊区', '金牛区', '成华区', '高新区'], + '武汉': ['武昌区', '江岸区', '江汉区', '硚口区', '汉阳区', '洪山区'], + '南京': ['玄武区', '秦淮区', '建邺区', '鼓楼区', '浦口区', '栖霞区'] +} + + +def generate_id_number(cert_type): + """生成证件号码""" + if cert_type == '身份证': + # 生成18位身份证号码 + area_code = f"{random.randint(110000, 659000)}" + birth = f"{random.randint(1960, 2000)}{random.randint(1, 12):02d}{random.randint(1, 28):02d}" + sequence = f"{random.randint(100, 999)}" + id_num = f"{area_code}{birth}{sequence}" + # 计算校验码 + weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2] + check_codes = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'] + total = sum(int(id_num[i]) * weights[i] for i in range(17)) + check_code = check_codes[total % 11] + return id_num + check_code + elif cert_type == '护照': + return f"E{random.randint(10000000, 99999999)}" + elif cert_type == '军官证': + return f"军字第{random.randint(1000000, 9999999)}号" + else: + return f"QT{random.randint(100000000, 999999999)}" + + +def generate_phone(): + """生成手机号码""" + prefixes = ['130', '131', '132', '133', '134', '135', '136', '137', '138', '139', + '150', '151', '152', '153', '155', '156', '157', '158', '159', + '180', '181', '182', '183', '184', '185', '186', '187', '188', '189'] + return f"{random.choice(prefixes)}{random.randint(10000000, 99999999)}" + + +def generate_wechat(): + """生成微信号""" + return f"wx_{random.randint(10000000, 99999999)}" + + +def generate_address(): + """生成联系地址""" + city = random.choice(list(CITIES.keys())) + district = random.choice(CITIES[city]) + street = random.choice(['中山路', '解放路', '人民路', '建设路', '文化路', '和平路', '友谊路', '光明路']) + number = random.randint(1, 999) + building = random.choice(['A座', 'B座', '1号楼', '2号楼', '东苑', '西苑', '南区', '北区']) + room = random.randint(101, 2606) + return f"{city}{district}{street}{number}号{building}{room}室" + + +def generate_name(): + """生成姓名""" + surname = random.choice(SURNAMES) + if random.random() > 0.3: # 70%概率两个字的名字 + return surname + random.choice(GIVEN_NAMES) + else: # 30%概率三个字的名字 + return surname + random.choice(GIVEN_NAMES) + random.choice(GIVEN_NAMES) + + +def main(): + """主函数""" + print(f"正在读取模板文件: {TEMPLATE_FILE}") + + try: + # 读取模板文件 + wb = openpyxl.load_workbook(TEMPLATE_FILE) + ws = wb.active + + # 获取表头 + headers = [] + for cell in ws[1]: + if cell.value: + headers.append(cell.value) + + print(f"模板表头: {headers}") + print(f"开始生成 {ROW_COUNT} 条测试数据...") + + # 清除除表头外的所有数据行 + for row in range(2, ws.max_row + 1): + for col in range(1, ws.max_column + 1): + ws.cell(row=row, column=col).value = None + + # 生成数据行 + for i in range(2, ROW_COUNT + 2): + indiv_type = random.choice(INDIV_TYPES) + gender = random.choice(GENDERS) + cert_type = random.choice(CERT_TYPES) + + # 根据表头索引填充数据 + row_data = { + '姓名': generate_name(), + '证件号码': generate_id_number(cert_type), + '人员类型': indiv_type, + '人员子类型': random.choice(INDIV_SUB_TYPES), + '性别': gender, + '证件类型': cert_type, + '手机号': generate_phone(), + '微信号': generate_wechat(), + '联系地址': generate_address(), + '所在公司': random.choice(COMPANIES), + '职位': random.choice(POSITIONS), + '关联人员ID': str(random.randint(1000, 9999)) if random.random() > 0.8 else '', + '关联关系': random.choice(RELATIONS) if random.random() > 0.5 else '', + '备注': f'测试数据{i-1}' + } + + # 写入行数据 + for col_idx, header in enumerate(headers, start=1): + if header in row_data: + ws.cell(row=i, column=col_idx, value=row_data[header]) + + if (i - 1) % 100 == 0: + print(f"已生成 {i-1} 条数据...") + + # 保存文件 + print(f"\n正在保存文件到: {OUTPUT_FILE}") + wb.save(OUTPUT_FILE) + + print(f"✓ 成功生成 {ROW_COUNT} 条测试数据") + print(f"✓ 文件已保存至: {OUTPUT_FILE}") + print(f"✓ 生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") + + # 输出前3条数据示例 + print("\n前3条数据示例:") + print("-" * 100) + for i in range(2, 5): + row_data = [] + for col_idx in range(1, len(headers) + 1): + val = ws.cell(row=i, column=col_idx).value + row_data.append(str(val) if val else "") + print(f"第{i-1}行: {', '.join([f'{h}:{v}' for h, v in zip(headers[:6], row_data[:6])])}") + + except FileNotFoundError: + print(f"✗ 错误:找不到模板文件 {TEMPLATE_FILE}") + print("请确保模板文件存在于正确的路径") + except Exception as e: + print(f"✗ 错误:{str(e)}") + import traceback + traceback.print_exc() + + +if __name__ == "__main__": + main() diff --git a/doc/scripts/package.json b/doc/scripts/package.json new file mode 100644 index 0000000..2b6c57d --- /dev/null +++ b/doc/scripts/package.json @@ -0,0 +1,19 @@ +{ + "name": "dpc-intermediary-dialog-tests", + "version": "1.0.0", + "description": "中介黑名单弹窗优化功能测试套件", + "scripts": { + "test": "node test_intermediary_dialog.js", + "test:report": "node test_intermediary_dialog.js > test_report.txt 2>&1" + }, + "keywords": [ + "中介黑名单", + "弹窗优化", + "功能测试" + ], + "author": "System Test", + "license": "MIT", + "dependencies": { + "axios": "^1.6.0" + } +} diff --git a/doc/scripts/test_import.py b/doc/scripts/test_import.py new file mode 100644 index 0000000..8759b8e --- /dev/null +++ b/doc/scripts/test_import.py @@ -0,0 +1,97 @@ +import requests +import json + +# 配置 +BASE_URL = "http://localhost:8080" +LOGIN_URL = f"{BASE_URL}/login/test" +IMPORT_URL = f"{BASE_URL}/dpc/intermediary/importPersonData" + +# 登录获取token +print("=" * 60) +print("测试个人中介Excel导入功能") +print("=" * 60) + +login_data = { + "username": "admin", + "password": "admin123" +} + +print("\n1. 登录系统...") +try: + response = requests.post(LOGIN_URL, json=login_data) + print(f" 登录响应状态码: {response.status_code}") + + if response.status_code == 200: + result = response.json() + print(f" 登录响应: {json.dumps(result, ensure_ascii=False, indent=2)}") + + token = result.get("token") + if token: + print(f" ✓ 成功获取token: {token[:50]}...") + else: + print(" ✗ 登录失败:未获取到token") + exit(1) + else: + print(f" ✗ 登录失败:{response.text}") + exit(1) +except Exception as e: + print(f" ✗ 登录异常: {e}") + exit(1) + +# 测试导入 +print("\n2. 准备导入Excel文件...") +files = { + 'file': ('个人中介黑名单测试数据_1000条.xlsx', + open('doc/个人中介黑名单测试数据_1000条.xlsx', 'rb'), + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') +} + +headers = { + 'Authorization': f'Bearer {token}' +} + +params = { + 'updateSupport': 'false' +} + +print(f" 导入URL: {IMPORT_URL}") +print(f" 文件名: 个人中介黑名单测试数据_1000条.xlsx") +print(f" 更新支持: false") + +print("\n3. 发送导入请求...") +try: + response = requests.post(IMPORT_URL, files=files, headers=headers, params=params) + print(f" 导入响应状态码: {response.status_code}") + print(f" 响应头: {dict(response.headers)}") + + if response.status_code == 200: + result = response.json() + print(f"\n 导入结果:") + print(f" {json.dumps(result, ensure_ascii=False, indent=2)}") + + if result.get("code") == 200: + print(f"\n ✓ 导入成功!") + print(f" 消息: {result.get('msg')}") + else: + print(f"\n ✗ 导入失败!") + print(f" 错误代码: {result.get('code')}") + print(f" 错误消息: {result.get('msg')}") + else: + print(f"\n ✗ HTTP错误: {response.status_code}") + print(f" 响应内容: {response.text}") + +except requests.exceptions.ConnectionError: + print(f"\n ✗ 连接失败:无法连接到后端服务器") + print(f" 请确认后端服务已启动在 {BASE_URL}") +except requests.exceptions.Timeout: + print(f"\n ✗ 请求超时") +except Exception as e: + print(f"\n ✗ 导入异常: {e}") + import traceback + traceback.print_exc() +finally: + files['file'][1].close() + +print("\n" + "=" * 60) +print("测试完成") +print("=" * 60) diff --git a/doc/scripts/test_import_simple.py b/doc/scripts/test_import_simple.py new file mode 100644 index 0000000..7d72bbf --- /dev/null +++ b/doc/scripts/test_import_simple.py @@ -0,0 +1,57 @@ +import requests +import json + +# 配置 +BASE_URL = "http://localhost:8080" +LOGIN_URL = f"{BASE_URL}/login/test" + +# 登录获取token +print("登录系统...") +login_data = { + "username": "admin", + "password": "admin123" +} + +response = requests.post(LOGIN_URL, json=login_data) +token = response.json().get("token") + +# 测试不同的导入方式 +headers = {'Authorization': f'Bearer {token}'} + +print("\n测试1: 直接POST请求(无文件)") +response = requests.post( + f"{BASE_URL}/dpc/intermediary/importPersonData", + headers=headers +) +print(f"状态码: {response.status_code}") +print(f"响应: {response.text[:200]}") + +print("\n测试2: 带文件的POST请求(URL参数)") +files = { + 'file': ('test.xlsx', open('doc/个人中介黑名单测试数据_1000条.xlsx', 'rb'), 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') +} +response = requests.post( + f"{BASE_URL}/dpc/intermediary/importPersonData?updateSupport=false", + files=files, + headers=headers +) +print(f"状态码: {response.status_code}") +print(f"响应: {response.text[:500]}") +files['file'][1].close() + +print("\n测试3: 带文件的POST请求(Form数据)") +files = { + 'file': ('test.xlsx', open('doc/个人中介黑名单测试数据_1000条.xlsx', 'rb'), 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') +} +data = { + 'updateSupport': 'false' +} +response = requests.post( + f"{BASE_URL}/dpc/intermediary/importPersonData", + files=files, + data=data, + headers=headers +) +print(f"状态码: {response.status_code}") +print(f"响应: {response.text[:500]}") +files['file'][1].close() diff --git a/doc/scripts/test_intermediary_blacklist.sh b/doc/scripts/test_intermediary_blacklist.sh new file mode 100644 index 0000000..478abf7 --- /dev/null +++ b/doc/scripts/test_intermediary_blacklist.sh @@ -0,0 +1,663 @@ +#!/bin/bash +################################################################################ +# 中介黑名单管理API测试脚本 +# +# 功能:测试DpcIntermediaryBlacklistController中的所有接口 +# 作者:Claude +# 日期:2026-01-29 +################################################################################ + +# ============================================================================ +# 配置项 +# ============================================================================ +BASE_URL="http://localhost:8080" +USERNAME="admin" +PASSWORD="admin123" +TOKEN="" +OUTPUT_DIR="test_output" +TIMESTAMP=$(date +%Y%m%d_%H%M%S) +REPORT_FILE="${OUTPUT_DIR}/test_report_${TIMESTAMP}.txt" + +# 颜色输出 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# ============================================================================ +# 工具函数 +# ============================================================================ + +# 打印带颜色的消息 +print_success() { + echo -e "${GREEN}✓ $1${NC}" +} + +print_error() { + echo -e "${RED}✗ $1${NC}" +} + +print_info() { + echo -e "${BLUE}ℹ $1${NC}" +} + +print_warning() { + echo -e "${YELLOW}⚠ $1${NC}" +} + +# 打印分隔线 +print_separator() { + echo -e "${BLUE}================================================================================${NC}" +} + +# 初始化输出目录 +init_output_dir() { + if [ ! -d "$OUTPUT_DIR" ]; then + mkdir -p "$OUTPUT_DIR" + print_info "创建输出目录: $OUTPUT_DIR" + fi +} + +# 记录到报告文件 +log_to_report() { + echo "$1" >> "$REPORT_FILE" +} + +# ============================================================================ +# API请求函数 +# ============================================================================ + +# 登录获取token +login() { + print_separator + print_info "正在登录..." + print_separator + + local response=$(curl -s -X POST "${BASE_URL}/login/test" \ + -H "Content-Type: application/json" \ + -d "{\"username\":\"${USERNAME}\",\"password\":\"${PASSWORD}\"}") + + TOKEN=$(echo "$response" | grep -o '"token":"[^"]*"' | cut -d'"' -f4) + + if [ -n "$TOKEN" ]; then + print_success "登录成功,获取token: ${TOKEN:0:20}..." + log_to_report "========== 登录测试 ==========" + log_to_report "请求: POST ${BASE_URL}/login/test" + log_to_report "响应: $response" + log_to_report "结果: 成功" + log_to_report "" + return 0 + else + print_error "登录失败" + log_to_report "========== 登录测试 ==========" + log_to_report "请求: POST ${BASE_URL}/login/test" + log_to_report "响应: $response" + log_to_report "结果: 失败" + log_to_report "" + return 1 + fi +} + +# 获取请求头 +get_headers() { + echo "-H \"Authorization: Bearer $TOKEN\" -H \"Content-Type: application/json\"" +} + +# ============================================================================ +# 测试函数 +# ============================================================================ + +# 测试1: 查询中介黑名单列表 +test_list() { + print_separator + print_info "测试1: 查询中介黑名单列表" + print_separator + + local url="${BASE_URL}/dpc/intermediary/list?pageNum=1&pageSize=10" + local response=$(curl -s -X GET "$url" \ + -H "Authorization: Bearer $TOKEN") + + echo "$response" | jq '.' > "${OUTPUT_DIR}/test1_list_response.json" 2>/dev/null || echo "$response" > "${OUTPUT_DIR}/test1_list_response.json" + + local code=$(echo "$response" | grep -o '"code":[0-9]*' | cut -d':' -f2) + + if [ "$code" == "200" ]; then + print_success "查询列表成功" + log_to_report "========== 测试1: 查询中介黑名单列表 ==========" + log_to_report "请求: GET $url" + log_to_report "响应已保存至: ${OUTPUT_DIR}/test1_list_response.json" + log_to_report "结果: 成功" + log_to_report "" + return 0 + else + print_error "查询列表失败: $response" + log_to_report "========== 测试1: 查询中介黑名单列表 ==========" + log_to_report "请求: GET $url" + log_to_report "响应: $response" + log_to_report "结果: 失败" + log_to_report "" + return 1 + fi +} + +# 测试2: 新增个人中介黑名单 +test_add_person() { + print_separator + print_info "测试2: 新增个人中介黑名单" + print_separator + + local test_name="测试个人中介_${TIMESTAMP}" + local data='{ + "name": "'${test_name}'", + "certificateNo": "TESTCERT'${TIMESTAMP}'", + "intermediaryType": "1", + "remark": "自动化测试数据" + }' + + local response=$(curl -s -X POST "${BASE_URL}/dpc/intermediary" \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d "$data") + + echo "$response" | jq '.' > "${OUTPUT_DIR}/test2_add_person_response.json" 2>/dev/null || echo "$response" > "${OUTPUT_DIR}/test2_add_person_response.json" + + local code=$(echo "$response" | grep -o '"code":[0-9]*' | cut -d':' -f2) + + if [ "$code" == "200" ]; then + print_success "新增个人中介成功" + log_to_report "========== 测试2: 新增个人中介黑名单 ==========" + log_to_report "请求: POST ${BASE_URL}/dpc/intermediary" + log_to_report "请求体: $data" + log_to_report "响应已保存至: ${OUTPUT_DIR}/test2_add_person_response.json" + log_to_report "结果: 成功" + log_to_report "" + + # 通过查询列表获取最新创建的ID(按创建时间倒序) + sleep 1 + local list_response=$(curl -s -X GET "${BASE_URL}/dpc/intermediary/list?pageNum=1&pageSize=1" \ + -H "Authorization: Bearer $TOKEN") + + # 从rows数组中提取第一个intermediaryId + PERSON_INTERMEDIARY_ID=$(echo "$list_response" | jq -r '.rows[0].intermediaryId' 2>/dev/null) + + if [ -n "$PERSON_INTERMEDIARY_ID" ] && [ "$PERSON_INTERMEDIARY_ID" != "null" ]; then + print_info "获取到中介ID: $PERSON_INTERMEDIARY_ID" + else + print_warning "无法获取中介ID,将使用备用方法" + fi + return 0 + else + print_error "新增个人中介失败: $response" + log_to_report "========== 测试2: 新增个人中介黑名单 ==========" + log_to_report "请求: POST ${BASE_URL}/dpc/intermediary" + log_to_report "请求体: $data" + log_to_report "响应: $response" + log_to_report "结果: 失败" + log_to_report "" + return 1 + fi +} + +# 测试3: 新增机构中介黑名单 +test_add_entity() { + print_separator + print_info "测试3: 新增机构中介黑名单" + print_separator + + local test_name="测试机构中介_${TIMESTAMP}" + local data='{ + "name": "'${test_name}'", + "certificateNo": "TESTORG'${TIMESTAMP}'", + "intermediaryType": "2", + "remark": "自动化测试机构数据" + }' + + local response=$(curl -s -X POST "${BASE_URL}/dpc/intermediary" \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d "$data") + + echo "$response" | jq '.' > "${OUTPUT_DIR}/test3_add_entity_response.json" 2>/dev/null || echo "$response" > "${OUTPUT_DIR}/test3_add_entity_response.json" + + local code=$(echo "$response" | grep -o '"code":[0-9]*' | cut -d':' -f2) + + if [ "$code" == "200" ]; then + print_success "新增机构中介成功" + log_to_report "========== 测试3: 新增机构中介黑名单 ==========" + log_to_report "请求: POST ${BASE_URL}/dpc/intermediary" + log_to_report "请求体: $data" + log_to_report "响应已保存至: ${OUTPUT_DIR}/test3_add_entity_response.json" + log_to_report "结果: 成功" + log_to_report "" + + # 通过查询列表获取最新创建的ID(按创建时间倒序) + sleep 1 + local list_response=$(curl -s -X GET "${BASE_URL}/dpc/intermediary/list?pageNum=1&pageSize=1" \ + -H "Authorization: Bearer $TOKEN") + + # 从rows数组中提取第一个intermediaryId + ENTITY_INTERMEDIARY_ID=$(echo "$list_response" | jq -r '.rows[0].intermediaryId' 2>/dev/null) + + if [ -n "$ENTITY_INTERMEDIARY_ID" ] && [ "$ENTITY_INTERMEDIARY_ID" != "null" ]; then + print_info "获取到中介ID: $ENTITY_INTERMEDIARY_ID" + else + print_warning "无法获取中介ID,将使用备用方法" + fi + return 0 + else + print_error "新增机构中介失败: $response" + log_to_report "========== 测试3: 新增机构中介黑名单 ==========" + log_to_report "请求: POST ${BASE_URL}/dpc/intermediary" + log_to_report "请求体: $data" + log_to_report "响应: $response" + log_to_report "结果: 失败" + log_to_report "" + return 1 + fi +} + +# 测试4: 获取中介详情 +test_get_info() { + print_separator + print_info "测试4: 获取中介详情" + print_separator + + if [ -z "$PERSON_INTERMEDIARY_ID" ]; then + print_warning "没有可用的中介ID,跳过此测试" + return 1 + fi + + local url="${BASE_URL}/dpc/intermediary/${PERSON_INTERMEDIARY_ID}" + local response=$(curl -s -X GET "$url" \ + -H "Authorization: Bearer $TOKEN") + + echo "$response" | jq '.' > "${OUTPUT_DIR}/test4_get_info_response.json" 2>/dev/null || echo "$response" > "${OUTPUT_DIR}/test4_get_info_response.json" + + local code=$(echo "$response" | grep -o '"code":[0-9]*' | cut -d':' -f2) + + if [ "$code" == "200" ]; then + print_success "获取中介详情成功" + log_to_report "========== 测试4: 获取中介详情 ==========" + log_to_report "请求: GET $url" + log_to_report "响应已保存至: ${OUTPUT_DIR}/test4_get_info_response.json" + log_to_report "结果: 成功" + log_to_report "" + return 0 + else + print_error "获取中介详情失败: $response" + log_to_report "========== 测试4: 获取中介详情 ==========" + log_to_report "请求: GET $url" + log_to_report "响应: $response" + log_to_report "结果: 失败" + log_to_report "" + return 1 + fi +} + +# 测试5: 修改中介黑名单 +test_edit() { + print_separator + print_info "测试5: 修改中介黑名单" + print_separator + + if [ -z "$PERSON_INTERMEDIARY_ID" ]; then + print_warning "没有可用的中介ID,跳过此测试" + return 1 + fi + + local data='{ + "intermediaryId": '$PERSON_INTERMEDIARY_ID', + "name": "测试个人中介_修改", + "certificateNo": "TESTCERT'${TIMESTAMP}'", + "intermediaryType": "1", + "status": "1", + "remark": "修改后的自动化测试数据" + }' + + local response=$(curl -s -X PUT "${BASE_URL}/dpc/intermediary" \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d "$data") + + echo "$response" | jq '.' > "${OUTPUT_DIR}/test5_edit_response.json" 2>/dev/null || echo "$response" > "${OUTPUT_DIR}/test5_edit_response.json" + + local code=$(echo "$response" | grep -o '"code":[0-9]*' | cut -d':' -f2) + + if [ "$code" == "200" ]; then + print_success "修改中介成功" + log_to_report "========== 测试5: 修改中介黑名单 ==========" + log_to_report "请求: PUT ${BASE_URL}/dpc/intermediary" + log_to_report "请求体: $data" + log_to_report "响应已保存至: ${OUTPUT_DIR}/test5_edit_response.json" + log_to_report "结果: 成功" + log_to_report "" + return 0 + else + print_error "修改中介失败: $response" + log_to_report "========== 测试5: 修改中介黑名单 ==========" + log_to_report "请求: PUT ${BASE_URL}/dpc/intermediary" + log_to_report "请求体: $data" + log_to_report "响应: $response" + log_to_report "结果: 失败" + log_to_report "" + return 1 + fi +} + +# 测试6: 导出中介黑名单列表 +test_export() { + print_separator + print_info "测试6: 导出中介黑名单列表" + print_separator + + local url="${BASE_URL}/dpc/intermediary/export" + local response=$(curl -s -X POST "$url" \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{}' \ + -o "${OUTPUT_DIR}/test6_export.xlsx" \ + -w "%{http_code}") + + if [ "$response" == "200" ]; then + print_success "导出中介列表成功,文件已保存至: ${OUTPUT_DIR}/test6_export.xlsx" + log_to_report "========== 测试6: 导出中介黑名单列表 ==========" + log_to_report "请求: POST $url" + log_to_report "文件已保存至: ${OUTPUT_DIR}/test6_export.xlsx" + log_to_report "结果: 成功" + log_to_report "" + return 0 + else + print_error "导出中介列表失败,HTTP状态码: $response" + log_to_report "========== 测试6: 导出中介黑名单列表 ==========" + log_to_report "请求: POST $url" + log_to_report "HTTP状态码: $response" + log_to_report "结果: 失败" + log_to_report "" + return 1 + fi +} + +# 测试7: 下载个人中介导入模板 +test_import_person_template() { + print_separator + print_info "测试7: 下载个人中介导入模板" + print_separator + + local url="${BASE_URL}/dpc/intermediary/importPersonTemplate" + local response=$(curl -s -X POST "$url" \ + -H "Authorization: Bearer $TOKEN" \ + -o "${OUTPUT_DIR}/test7_person_template.xlsx" \ + -w "%{http_code}") + + if [ "$response" == "200" ]; then + print_success "下载个人中介导入模板成功,文件已保存至: ${OUTPUT_DIR}/test7_person_template.xlsx" + log_to_report "========== 测试7: 下载个人中介导入模板 ==========" + log_to_report "请求: POST $url" + log_to_report "文件已保存至: ${OUTPUT_DIR}/test7_person_template.xlsx" + log_to_report "结果: 成功" + log_to_report "" + return 0 + else + print_error "下载个人中介导入模板失败,HTTP状态码: $response" + log_to_report "========== 测试7: 下载个人中介导入模板 ==========" + log_to_report "请求: POST $url" + log_to_report "HTTP状态码: $response" + log_to_report "结果: 失败" + log_to_report "" + return 1 + fi +} + +# 测试8: 下载机构中介导入模板 +test_import_entity_template() { + print_separator + print_info "测试8: 下载机构中介导入模板" + print_separator + + local url="${BASE_URL}/dpc/intermediary/importEntityTemplate" + local response=$(curl -s -X POST "$url" \ + -H "Authorization: Bearer $TOKEN" \ + -o "${OUTPUT_DIR}/test8_entity_template.xlsx" \ + -w "%{http_code}") + + if [ "$response" == "200" ]; then + print_success "下载机构中介导入模板成功,文件已保存至: ${OUTPUT_DIR}/test8_entity_template.xlsx" + log_to_report "========== 测试8: 下载机构中介导入模板 ==========" + log_to_report "请求: POST $url" + log_to_report "文件已保存至: ${OUTPUT_DIR}/test8_entity_template.xlsx" + log_to_report "结果: 成功" + log_to_report "" + return 0 + else + print_error "下载机构中介导入模板失败,HTTP状态码: $response" + log_to_report "========== 测试8: 下载机构中介导入模板 ==========" + log_to_report "请求: POST $url" + log_to_report "HTTP状态码: $response" + log_to_report "结果: 失败" + log_to_report "" + return 1 + fi +} + +# 测试9: 删除中介黑名单 +test_remove() { + print_separator + print_info "测试9: 删除中介黑名单" + print_separator + + if [ -z "$PERSON_INTERMEDIARY_ID" ] && [ -z "$ENTITY_INTERMEDIARY_ID" ]; then + print_warning "没有可用的中介ID,跳过此测试" + return 1 + fi + + local ids="" + if [ -n "$PERSON_INTERMEDIARY_ID" ]; then + ids="$PERSON_INTERMEDIARY_ID" + fi + if [ -n "$ENTITY_INTERMEDIARY_ID" ]; then + if [ -n "$ids" ]; then + ids="${ids},${ENTITY_INTERMEDIARY_ID}" + else + ids="$ENTITY_INTERMEDIARY_ID" + fi + fi + + local url="${BASE_URL}/dpc/intermediary/${ids}" + local response=$(curl -s -X DELETE "$url" \ + -H "Authorization: Bearer $TOKEN") + + echo "$response" | jq '.' > "${OUTPUT_DIR}/test9_remove_response.json" 2>/dev/null || echo "$response" > "${OUTPUT_DIR}/test9_remove_response.json" + + local code=$(echo "$response" | grep -o '"code":[0-9]*' | cut -d':' -f2) + + if [ "$code" == "200" ]; then + print_success "删除中介成功" + log_to_report "========== 测试9: 删除中介黑名单 ==========" + log_to_report "请求: DELETE $url" + log_to_report "响应已保存至: ${OUTPUT_DIR}/test9_remove_response.json" + log_to_report "结果: 成功" + log_to_report "" + return 0 + else + print_error "删除中介失败: $response" + log_to_report "========== 测试9: 删除中介黑名单 ==========" + log_to_report "请求: DELETE $url" + log_to_report "响应: $response" + log_to_report "结果: 失败" + log_to_report "" + return 1 + fi +} + +# 测试10: 条件查询(按中介类型) +test_query_by_type() { + print_separator + print_info "测试10: 条件查询(按中介类型)" + print_separator + + local url="${BASE_URL}/dpc/intermediary/list?pageNum=1&pageSize=10&intermediaryType=1" + local response=$(curl -s -X GET "$url" \ + -H "Authorization: Bearer $TOKEN") + + echo "$response" | jq '.' > "${OUTPUT_DIR}/test10_query_by_type_response.json" 2>/dev/null || echo "$response" > "${OUTPUT_DIR}/test10_query_by_type_response.json" + + local code=$(echo "$response" | grep -o '"code":[0-9]*' | cut -d':' -f2) + + if [ "$code" == "200" ]; then + print_success "条件查询成功" + log_to_report "========== 测试10: 条件查询(按中介类型) ==========" + log_to_report "请求: GET $url" + log_to_report "响应已保存至: ${OUTPUT_DIR}/test10_query_by_type_response.json" + log_to_report "结果: 成功" + log_to_report "" + return 0 + else + print_error "条件查询失败: $response" + log_to_report "========== 测试10: 条件查询(按中介类型) ==========" + log_to_report "请求: GET $url" + log_to_report "响应: $response" + log_to_report "结果: 失败" + log_to_report "" + return 1 + fi +} + +# 测试11: 条件查询(按状态) +test_query_by_status() { + print_separator + print_info "测试11: 条件查询(按状态)" + print_separator + + local url="${BASE_URL}/dpc/intermediary/list?pageNum=1&pageSize=10&status=1" + local response=$(curl -s -X GET "$url" \ + -H "Authorization: Bearer $TOKEN") + + echo "$response" | jq '.' > "${OUTPUT_DIR}/test11_query_by_status_response.json" 2>/dev/null || echo "$response" > "${OUTPUT_DIR}/test11_query_by_status_response.json" + + local code=$(echo "$response" | grep -o '"code":[0-9]*' | cut -d':' -f2) + + if [ "$code" == "200" ]; then + print_success "条件查询成功" + log_to_report "========== 测试11: 条件查询(按状态) ==========" + log_to_report "请求: GET $url" + log_to_report "响应已保存至: ${OUTPUT_DIR}/test11_query_by_status_response.json" + log_to_report "结果: 成功" + log_to_report "" + return 0 + else + print_error "条件查询失败: $response" + log_to_report "========== 测试11: 条件查询(按状态) ==========" + log_to_report "请求: GET $url" + log_to_report "响应: $response" + log_to_report "结果: 失败" + log_to_report "" + return 1 + fi +} + +# ============================================================================ +# 主测试流程 +# ============================================================================ + +main() { + print_separator + echo -e "${BLUE} 中介黑名单管理API测试脚本${NC}" + print_separator + echo "测试时间: $(date '+%Y-%m-%d %H:%M:%S')" + echo "基础URL: $BASE_URL" + echo "测试账号: $USERNAME" + print_separator + echo "" + + # 初始化输出目录 + init_output_dir + + # 初始化报告文件 + echo "====================================" > "$REPORT_FILE" + echo "中介黑名单管理API测试报告" >> "$REPORT_FILE" + echo "测试时间: $(date '+%Y-%m-%d %H:%M:%S')" >> "$REPORT_FILE" + echo "====================================" >> "$REPORT_FILE" + echo "" + + # 登录 + if ! login; then + print_error "登录失败,测试终止" + exit 1 + fi + + echo "" + echo "====================================" + echo "开始执行测试用例" + echo "====================================" + echo "" + + # 执行测试 + local tests=( + "test_list" + "test_add_person" + "test_add_entity" + "test_get_info" + "test_edit" + "test_export" + "test_import_person_template" + "test_import_entity_template" + "test_query_by_type" + "test_query_by_status" + "test_remove" + ) + + local passed=0 + local failed=0 + local total=${#tests[@]} + + for test in "${tests[@]}"; do + if $test; then + ((passed++)) + else + ((failed++)) + fi + echo "" + sleep 1 # 避免请求过快 + done + + # 输出测试报告汇总 + print_separator + echo -e "${BLUE} 测试报告汇总${NC}" + print_separator + echo "测试场景总数: $total" + echo -e "${GREEN}通过数量: $passed${NC}" + echo -e "${RED}失败数量: $failed${NC}" + print_separator + + # 将汇总信息写入报告 + echo "" >> "$REPORT_FILE" + echo "====================================" >> "$REPORT_FILE" + echo "测试汇总" >> "$REPORT_FILE" + echo "====================================" >> "$REPORT_FILE" + echo "测试场景总数: $total" >> "$REPORT_FILE" + echo "通过数量: $passed" >> "$REPORT_FILE" + echo "失败数量: $failed" >> "$REPORT_FILE" + echo "通过率: $(awk "BEGIN {printf \"%.2f%%\", $passed/$total*100}")" >> "$REPORT_FILE" + echo "" >> "$REPORT_FILE" + echo "详细响应文件已保存至: ${OUTPUT_DIR}/" >> "$REPORT_FILE" + echo "测试报告文件: $REPORT_FILE" >> "$REPORT_FILE" + echo "====================================" >> "$REPORT_FILE" + + if [ $passed -eq $total ]; then + print_success "所有测试通过!" + echo "" + print_info "详细报告已保存至: $REPORT_FILE" + print_info "响应文件已保存至: ${OUTPUT_DIR}/" + exit 0 + else + print_error "部分测试失败,请查看详细日志" + echo "" + print_info "详细报告已保存至: $REPORT_FILE" + print_info "响应文件已保存至: ${OUTPUT_DIR}/" + exit 1 + fi +} + +# 执行主函数 +main diff --git a/doc/scripts/test_intermediary_complete.sh b/doc/scripts/test_intermediary_complete.sh new file mode 100644 index 0000000..fa54cc2 --- /dev/null +++ b/doc/scripts/test_intermediary_complete.sh @@ -0,0 +1,352 @@ +#!/bin/bash + +# 中介新增和修改功能完整测试脚本 +# 测试个人和机构中介的新增和修改功能 + +BASE_URL="http://localhost:8080" +USERNAME="admin" +PASSWORD="admin123" + +# 颜色输出 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# 测试结果统计 +TOTAL_TESTS=0 +PASSED_TESTS=0 +FAILED_TESTS=0 + +# 测试报告文件 +REPORT_FILE="doc/scripts/test_output/test_report_$(date +%Y%m%d_%H%M%S).txt" +mkdir -p doc/scripts/test_output + +# 日志函数 +log_info() { + echo -e "${GREEN}[INFO]${NC} $1" | tee -a "$REPORT_FILE" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" | tee -a "$REPORT_FILE" +} + +log_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" | tee -a "$REPORT_FILE" +} + +log_test() { + echo -e "${YELLOW}[TEST]${NC} $1" | tee -a "$REPORT_FILE" +} + +# 测试结果记录 +record_pass() { + ((PASSED_TESTS++)) + ((TOTAL_TESTS++)) + log_info "✓ 测试通过: $1" +} + +record_fail() { + ((FAILED_TESTS++)) + ((TOTAL_TESTS++)) + log_error "✗ 测试失败: $1" +} + +# 登录获取token +login() { + log_test "登录获取Token..." + local response=$(curl -s -X POST "$BASE_URL/login/test" \ + -H "Content-Type: application/json" \ + -d "{\"username\":\"$USERNAME\",\"password\":\"$PASSWORD\"}") + + local token=$(echo $response | grep -o '"token":"[^"]*' | sed 's/"token":"//') + + if [ -z "$token" ]; then + log_error "登录失败,无法获取Token" + exit 1 + fi + + log_info "登录成功,Token: ${token:0:20}..." + echo "$token" +} + +# 测试新增个人中介 +test_add_person_intermediary() { + local token=$1 + + log_test "测试新增个人中介..." + + local add_data=$(cat < item.intermediaryType === '1').length; + const corpCount = list.filter(item => item.intermediaryType === '2').length; + log(` 个人类型: ${indivCount} 条`, 'cyan'); + log(` 机构类型: ${corpCount} 条`, 'cyan'); + } else { + logTest('查询列表失败', false, response.data.msg); + } + } catch (error) { + logTest('查询列表异常', false, error.message); + } +} + +/** + * 清理测试数据 + */ +async function cleanup() { + logSection('清理测试数据'); + + const idsToDelete = []; + if (testIndivId) idsToDelete.push(testIndivId); + if (testCorpId) idsToDelete.push(testCorpId); + + for (const id of idsToDelete) { + try { + await api.delete(`/dpc/intermediary/${id}`); + logTest(`删除测试数据 ID: ${id}`, true); + } catch (error) { + logTest(`删除失败 ID: ${id}`, false, error.message); + } + } +} + +// ==================== 主流程 ==================== + +async function runTests() { + log('\n╔════════════════════════════════════════════════════════════╗'); + log('║ 中介黑名单弹窗优化功能测试 ║', 'bright'); + log('║ 测试日期: ' + new Date().toLocaleString('zh-CN') + ' ║'); + log('╚════════════════════════════════════════════════════════════╝'); + + try { + // 按顺序执行测试 + await testLogin(); + await testAddIndividualRequired(); + await testAddIndividualMaxLength(); + await testAddCorpSync(); + await testAddCorpCreditCodeLength(); + await testEditIndividualTypeLock(); + await testEditCorpTypeLock(); + await testAddWithoutType(); + await testListQuery(); + + logSection('测试完成'); + log('所有测试用例执行完毕!', 'green'); + + } catch (error) { + log('\n测试流程异常终止', 'red'); + log(error.message, 'red'); + } finally { + // 询问是否清理测试数据 + log('\n是否清理测试数据?(在自动化环境中会自动清理)', 'yellow'); + await cleanup(); + } +} + +// 运行测试 +if (require.main === module) { + runTests().catch(console.error); +} + +module.exports = { runTests }; diff --git a/doc/scripts/test_intermediary_edit_fix.bat b/doc/scripts/test_intermediary_edit_fix.bat new file mode 100644 index 0000000..765e639 --- /dev/null +++ b/doc/scripts/test_intermediary_edit_fix.bat @@ -0,0 +1,107 @@ +@echo off +setlocal enabledelayedexpansion + +REM 中介黑名单编辑功能修复测试脚本 +REM 用于验证修改按钮点击后数据是否正确反显 + +set BASE_URL=http://localhost:8080 +set USERNAME=admin +set PASSWORD=admin123 + +echo ========================================== +echo 中介黑名单编辑功能修复测试 +echo ========================================== +echo. + +REM 步骤1: 登录获取 token +echo 步骤1: 登录系统... +curl -s -X POST "%BASE_URL%/login/test" -H "Content-Type: application/json" -d "{\"username\":\"%USERNAME%\",\"password\":\"%PASSWORD%\"}" > login_response.json + +echo 登录响应: +type login_response.json +echo. + +REM 使用 PowerShell 提取 token +for /f "tokens=2 delims=:," %%a in ('powershell -command "(Get-Content login_response.json | ConvertFrom-Json).data.token"') do set TOKEN=%%a +set TOKEN=%TOKEN:"=% + +if "%TOKEN%"=="" ( + echo ❌ 登录失败,无法获取 token + pause + exit /b 1 +) + +echo ✅ 登录成功,Token: %TOKEN:~0,20%... +echo. + +REM 步骤2: 查询中介黑名单列表 +echo 步骤2: 查询中介黑名单列表... +curl -s -X GET "%BASE_URL%/dpc/intermediary/list?pageNum=1&pageSize=10" -H "Authorization: Bearer %TOKEN%" > list_response.json + +echo 列表响应: +powershell -command "Get-Content list_response.json | ConvertFrom-Json | ConvertTo-Json -Depth 3" +echo. + +REM 步骤3: 获取个人中介详情 +echo 步骤3: 测试个人中介详情查询(假设 ID=1)... +curl -s -X GET "%BASE_URL%/dpc/intermediary/1" -H "Authorization: Bearer %TOKEN%" > person_detail.json + +echo 个人中介详情响应: +powershell -command "Get-Content person_detail.json | ConvertFrom-Json | ConvertTo-Json -Depth 10" +echo. + +REM 检查关键字段 +findstr /C:"\"intermediaryType\":\"1\"" person_detail.json >nul +if !errorlevel! equ 0 ( + echo ✅ 个人中介类型字段正确 +) else ( + echo ❌ 个人中介类型字段缺失或错误 +) + +findstr /C:"\"name\"" person_detail.json >nul +if !errorlevel! equ 0 ( + echo ✅ 姓名字段存在 +) else ( + echo ❌ 姓名字段缺失 +) + +echo. + +REM 步骤4: 获取机构中介详情(假设 ID=2) +echo 步骤4: 测试机构中介详情查询(假设 ID=2)... +curl -s -X GET "%BASE_URL%/dpc/intermediary/2" -H "Authorization: Bearer %TOKEN%" > entity_detail.json + +echo 机构中介详情响应: +powershell -command "Get-Content entity_detail.json | ConvertFrom-Json | ConvertTo-Json -Depth 10" +echo. + +REM 检查关键字段 +findstr /C:"\"intermediaryType\":\"2\"" entity_detail.json >nul +if !errorlevel! equ 0 ( + echo ✅ 机构中介类型字段正确 +) else ( + echo ❌ 机构中介类型字段缺失或错误 +) + +findstr /C:"\"name\"" entity_detail.json >nul +if !errorlevel! equ 0 ( + echo ✅ 机构名称字段存在 +) else ( + echo ❌ 机构名称字段缺失 +) + +echo. +echo ========================================== +echo 测试完成 +echo ========================================== +echo. +echo 验证要点: +echo 1. 确保后端返回的数据包含 intermediaryType 字段 +echo 2. 确保返回的数据结构与前端表单字段匹配 +echo 3. 个人中介 (intermediaryType='1') 应包含 indivXXX 字段 +echo 4. 机构中介 (intermediaryType='2') 应包含 corpXXX 字段 +echo. +echo 如需测试特定 ID,请修改脚本中的 ID 值 +echo. + +pause diff --git a/doc/scripts/test_intermediary_edit_fix.sh b/doc/scripts/test_intermediary_edit_fix.sh new file mode 100644 index 0000000..bf45fb9 --- /dev/null +++ b/doc/scripts/test_intermediary_edit_fix.sh @@ -0,0 +1,100 @@ +#!/bin/bash + +# 中介黑名单编辑功能修复测试脚本 +# 用于验证修改按钮点击后数据是否正确反显 + +BASE_URL="http://localhost:8080" +USERNAME="admin" +PASSWORD="admin123" + +echo "==========================================" +echo "中介黑名单编辑功能修复测试" +echo "==========================================" +echo "" + +# 步骤1: 登录获取 token +echo "步骤1: 登录系统..." +LOGIN_RESPONSE=$(curl -s -X POST "${BASE_URL}/login/test" \ + -H "Content-Type: application/json" \ + -d "{\"username\":\"${USERNAME}\",\"password\":\"${PASSWORD}\"}") + +echo "登录响应: ${LOGIN_RESPONSE}" + +# 提取 token (假设返回格式为 {"code":200,"data":{"token":"xxx"}}) +TOKEN=$(echo ${LOGIN_RESPONSE} | grep -o '"token":"[^"]*' | sed 's/"token":"//') + +if [ -z "$TOKEN" ]; then + echo "❌ 登录失败,无法获取 token" + exit 1 +fi + +echo "✅ 登录成功,Token: ${TOKEN:0:20}..." +echo "" + +# 步骤2: 查询中介黑名单列表 +echo "步骤2: 查询中介黑名单列表..." +LIST_RESPONSE=$(curl -s -X GET "${BASE_URL}/dpc/intermediary/list?pageNum=1&pageSize=10" \ + -H "Authorization: Bearer ${TOKEN}") + +echo "列表响应: ${LIST_RESPONSE}" | head -c 500 +echo "" +echo "" + +# 步骤3: 获取个人中介详情 +echo "步骤3: 测试个人中介详情查询..." +PERSON_ID_RESPONSE=$(curl -s -X GET "${BASE_URL}/dpc/intermediary/1" \ + -H "Authorization: Bearer ${TOKEN}") + +echo "个人中介详情响应:" +echo "${PERSON_ID_RESPONSE}" | python -m json.tool 2>/dev/null || echo "${PERSON_ID_RESPONSE}" +echo "" + +# 检查关键字段是否存在 +if echo "${PERSON_ID_RESPONSE}" | grep -q '"intermediaryType":"1"'; then + echo "✅ 个人中介类型字段正确" +else + echo "❌ 个人中介类型字段缺失或错误" +fi + +if echo "${PERSON_ID_RESPONSE}" | grep -q '"name"'; then + echo "✅ 姓名字段存在" +else + echo "❌ 姓名字段缺失" +fi + +echo "" + +# 步骤4: 获取机构中介详情(假设 ID 为 2) +echo "步骤4: 测试机构中介详情查询..." +ENTITY_ID_RESPONSE=$(curl -s -X GET "${BASE_URL}/dpc/intermediary/2" \ + -H "Authorization: Bearer ${TOKEN}") + +echo "机构中介详情响应:" +echo "${ENTITY_ID_RESPONSE}" | python -m json.tool 2>/dev/null || echo "${ENTITY_ID_RESPONSE}" +echo "" + +# 检查关键字段是否存在 +if echo "${ENTITY_ID_RESPONSE}" | grep -q '"intermediaryType":"2"'; then + echo "✅ 机构中介类型字段正确" +else + echo "❌ 机构中介类型字段缺失或错误" +fi + +if echo "${ENTITY_ID_RESPONSE}" | grep -q '"name"'; then + echo "✅ 机构名称字段存在" +else + echo "❌ 机构名称字段缺失" +fi + +echo "" +echo "==========================================" +echo "测试完成" +echo "==========================================" +echo "" +echo "验证要点:" +echo "1. 确保后端返回的数据包含 intermediaryType 字段" +echo "2. 确保返回的数据结构与前端表单字段匹配" +echo "3. 个人中介 (intermediaryType='1') 应包含 indivXXX 字段" +echo "4. 机构中介 (intermediaryType='2') 应包含 corpXXX 字段" +echo "" +echo "如需测试特定 ID,请修改脚本中的 ID 值" diff --git a/doc/scripts/test_intermediary_getinfo.sh b/doc/scripts/test_intermediary_getinfo.sh new file mode 100644 index 0000000..f6b2a13 --- /dev/null +++ b/doc/scripts/test_intermediary_getinfo.sh @@ -0,0 +1,114 @@ +#!/bin/bash + +# 中介黑名单详细信息接口测试脚本 +# 用于测试点击修改按钮时,后端接口是否正确返回中介类型信息 + +BASE_URL="http://localhost:8080" + +# 颜色定义 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +echo "========================================" +echo "中介黑名单详细信息接口测试" +echo "========================================" +echo "" + +# 1. 登录获取token +echo -e "${YELLOW}1. 登录系统获取token...${NC}" +LOGIN_RESPONSE=$(curl -s -X POST "${BASE_URL}/login/test" \ + -H "Content-Type: application/json" \ + -d '{"username":"admin","password":"admin123"}') + +TOKEN=$(echo $LOGIN_RESPONSE | grep -o '"token":"[^"]*"' | sed 's/"token":"//' | sed 's/"//') + +if [ -z "$TOKEN" ]; then + echo -e "${RED}登录失败,无法获取token${NC}" + exit 1 +fi + +echo -e "${GREEN}登录成功,获取到token${NC}" +echo "" + +# 2. 查询列表获取一个中介ID +echo -e "${YELLOW}2. 查询中介列表,获取测试数据...${NC}" +LIST_RESPONSE=$(curl -s -X GET "${BASE_URL}/dpc/intermediary/list?pageNum=1&pageSize=10" \ + -H "Authorization: Bearer ${TOKEN}") + +# 提取第一个中介ID +INTERMEDIARY_ID=$(echo $LIST_RESPONSE | grep -o '"intermediaryId":[0-9]*' | head -1 | sed 's/"intermediaryId"://') + +if [ -z "$INTERMEDIARY_ID" ]; then + echo -e "${RED}未找到中介数据${NC}" + exit 1 +fi + +echo -e "${GREEN}找到中介ID: ${INTERMEDIARY_ID}${NC}" +echo "" + +# 3. 测试获取详细信息 +echo -e "${YELLOW}3. 获取中介详细信息 (ID: ${INTERMEDIARY_ID})...${NC}" +DETAIL_RESPONSE=$(curl -s -X GET "${BASE_URL}/dpc/intermediary/${INTERMEDIARY_ID}" \ + -H "Authorization: Bearer ${TOKEN}") + +echo "响应内容:" +echo "$DETAIL_RESPONSE" | python -m json.tool 2>/dev/null || echo "$DETAIL_RESPONSE" +echo "" + +# 4. 检查是否包含intermediaryType字段 +echo -e "${YELLOW}4. 验证返回数据是否包含中介类型字段...${NC}" +if echo "$DETAIL_RESPONSE" | grep -q '"intermediaryType"'; then + INTERMEDIARY_TYPE=$(echo $DETAIL_RESPONSE | grep -o '"intermediaryType":"[^"]*"' | sed 's/"intermediaryType":"//' | sed 's/"//') + + if [ "$INTERMEDIARY_TYPE" = "1" ]; then + echo -e "${GREEN}✓ 包含中介类型字段,类型为: 个人 (1)${NC}" + elif [ "$INTERMEDIARY_TYPE" = "2" ]; then + echo -e "${GREEN}✓ 包含中介类型字段,类型为: 机构 (2)${NC}" + else + echo -e "${YELLOW}⚠ 包含中介类型字段,但值为: ${INTERMEDIARY_TYPE}${NC}" + fi +else + echo -e "${RED}✗ 缺少中介类型字段 (intermediaryType)${NC}" + echo "" + echo "这是导致前端表单无法正确反显的根本原因!" + echo "前端EditDialog组件需要根据intermediaryType判断显示个人还是机构表单" +fi +echo "" + +# 5. 检查其他关键字段 +echo -e "${YELLOW}5. 验证其他关键字段...${NC}" +check_field() { + FIELD_NAME=$1 + if echo "$DETAIL_RESPONSE" | grep -q "\"${FIELD_NAME}\""; then + echo -e "${GREEN} ✓ ${FIELD_NAME}: 存在${NC}" + else + echo -e "${RED} ✗ ${FIELD_NAME}: 缺失${NC}" + fi +} + +check_field "intermediaryId" +check_field "name" +check_field "certificateNo" +check_field "status" +check_field "remark" +echo "" + +# 6. 根据中介类型检查特定字段 +if [ "$INTERMEDIARY_TYPE" = "1" ]; then + echo -e "${YELLOW}6. 验证个人类型专属字段...${NC}" + check_field "indivType" + check_field "indivGender" + check_field "indivCertType" +elif [ "$INTERMEDIARY_TYPE" = "2" ]; then + echo -e "${YELLOW}6. 验证机构类型专属字段...${NC}" + check_field "corpCreditCode" + check_field "corpType" + check_field "corpNature" +fi +echo "" + +echo "========================================" +echo "测试完成" +echo "========================================" diff --git a/doc/scripts/test_intermediary_type_fix.bat b/doc/scripts/test_intermediary_type_fix.bat new file mode 100644 index 0000000..8cc1129 --- /dev/null +++ b/doc/scripts/test_intermediary_type_fix.bat @@ -0,0 +1,205 @@ +@echo off +chcp 65001 >nul +setlocal EnableDelayedExpansion + +REM 中介类型修改修复测试脚本(Windows版本) +REM 测试个人和机构中介的修改功能 + +set BASE_URL=http://localhost:8080 +set USERNAME=admin +set PASSWORD=admin123 + +REM 创建输出目录 +if not exist "doc\scripts\test_output" mkdir "doc\scripts\test_output" + +REM 生成报告文件名 +set REPORT_FILE=doc\scripts\test_output\test_report_%date:~0,4%%date:~5,2%%date:~8,2%_%time:~0,2%%time:~3,2%%time:~6,2%.txt +set REPORT_FILE=%REPORT_FILE: =0% + +echo ======================================== > "%REPORT_FILE%" +echo 中介类型修改修复测试 >> "%REPORT_FILE%" +echo 测试时间: %date% %time% >> "%REPORT_FILE%" +echo ======================================== >> "%REPORT_FILE%" +echo. >> "%REPORT_FILE%" + +REM 测试统计 +set TOTAL_TESTS=0 +set PASSED_TESTS=0 +set FAILED_TESTS=0 + +echo [TEST] 开始测试... + +REM 登录获取Token +echo [TEST] 登录获取Token... +curl -s -X POST "%BASE_URL%/login/test" -H "Content-Type: application/json" -d "{\"username\":\"%USERNAME%\",\"password\":\"%PASSWORD%\"}" > temp_response.json + +REM 提取token +for /f "tokens=2 delims=:\"" %%a in ('findstr /c:"\"token\"" temp_response.json') do ( + set TOKEN=%%a + goto :found_token +) +:found_token + +if "!TOKEN!"=="" ( + echo [ERROR] 登录失败,无法获取Token >> "%REPORT_FILE%" + del temp_response.json + exit /b 1 +) + +echo [INFO] 登录成功 >> "%REPORT_FILE%" +del temp_response.json + +REM 测试1: 获取个人中介列表 +echo. >> "%REPORT_FILE%" +echo [TEST] === 测试1: 获取个人中介列表 === >> "%REPORT_FILE%" +curl -s -X GET "%BASE_URL%/dpc/intermediary/list?intermediaryType=1&pageNum=1&pageSize=1" -H "Authorization: Bearer !TOKEN!" > temp_response.json + +REM 提取第一个个人中介ID +for /f "tokens=2 delims=:" %%a in ('findstr /c:"\"intermediaryId\"" temp_response.json') do ( + set PERSON_ID=%%a + set PERSON_ID=!PERSON_ID:,=! + goto :found_person_id +) +:found_person_id + +if "!PERSON_ID!"=="" ( + echo [ERROR] 未能获取个人中介ID >> "%REPORT_FILE%" + set /a FAILED_TESTS+=1 +) else ( + echo [INFO] 获取个人中介ID: !PERSON_ID! >> "%REPORT_FILE%" + set /a PASSED_TESTS+=1 +) +set /a TOTAL_TESTS+=1 + +REM 测试2: 修改个人中介 +if not "!PERSON_ID!"=="" ( + echo. >> "%REPORT_FILE%" + echo [TEST] === 测试2: 修改个人中介 === >> "%REPORT_FILE%" + + REM 创建请求数据文件 + echo {> update_person.json + echo "intermediaryId": !PERSON_ID!,>> update_person.json + echo "name": "测试个人修改",>> update_person.json + echo "certificateNo": "110101199001011234",>> update_person.json + echo "indivType": "中介",>> update_person.json + echo "indivSubType": "本人",>> update_person.json + echo "indivGender": "M",>> update_person.json + echo "indivCertType": "身份证",>> update_person.json + echo "indivPhone": "13800138000",>> update_person.json + echo "indivCompany": "测试公司",>> update_person.json + echo "indivPosition": "经纪人",>> update_person.json + echo "status": "0",>> update_person.json + echo "remark": "修改测试">> update_person.json + echo }>> update_person.json + + curl -s -X PUT "%BASE_URL%/dpc/intermediary/person" -H "Authorization: Bearer !TOKEN!" -H "Content-Type: application/json" -d @update_person.json > update_result.json + + type update_result.json >> "%REPORT_FILE%" + echo. >> "%REPORT_FILE%" + + findstr /c:"\"code\":200" update_result.json >nul + if !errorlevel! equ 0 ( + echo [INFO] 个人中介修改接口调用成功 >> "%REPORT_FILE%" + set /a PASSED_TESTS+=1 + ) else ( + echo [ERROR] 个人中介修改接口调用失败 >> "%REPORT_FILE%" + set /a FAILED_TESTS+=1 + ) + set /a TOTAL_TESTS+=1 + + del update_person.json + del update_result.json +) + +REM 测试3: 获取机构中介列表 +echo. >> "%REPORT_FILE%" +echo [TEST] === 测试3: 获取机构中介列表 === >> "%REPORT_FILE%" +curl -s -X GET "%BASE_URL%/dpc/intermediary/list?intermediaryType=2&pageNum=1&pageSize=1" -H "Authorization: Bearer !TOKEN!" > temp_response.json + +REM 提取第一个机构中介ID +for /f "tokens=2 delims=:" %%a in ('findstr /c:"\"intermediaryId\"" temp_response.json') do ( + set ENTITY_ID=%%a + set ENTITY_ID=!ENTITY_ID:,=! + goto :found_entity_id +) +:found_entity_id + +if "!ENTITY_ID!"=="" ( + echo [ERROR] 未能获取机构中介ID >> "%REPORT_FILE%" + set /a FAILED_TESTS+=1 +) else ( + echo [INFO] 获取机构中介ID: !ENTITY_ID! >> "%REPORT_FILE%" + set /a PASSED_TESTS+=1 +) +set /a TOTAL_TESTS+=1 + +REM 测试4: 修改机构中介 +if not "!ENTITY_ID!"=="" ( + echo. >> "%REPORT_FILE%" + echo [TEST] === 测试4: 修改机构中介 === >> "%REPORT_FILE%" + + REM 创建请求数据文件 + echo {> update_entity.json + echo "intermediaryId": !ENTITY_ID!,>> update_entity.json + echo "name": "测试机构修改",>> update_entity.json + echo "certificateNo": "91110000XXXXXXXXXX",>> update_entity.json + echo "corpCreditCode": "91110000XXXXXXXXXX",>> update_entity.json + echo "corpType": "有限责任公司",>> update_entity.json + echo "corpNature": "民企",>> update_entity.json + echo "corpIndustry": "房地产",>> update_entity.json + echo "corpAddress": "北京市朝阳区",>> update_entity.json + echo "corpLegalRep": "张三",>> update_entity.json + echo "status": "0",>> update_entity.json + echo "remark": "修改测试">> update_entity.json + echo }>> update_entity.json + + curl -s -X PUT "%BASE_URL%/dpc/intermediary/entity" -H "Authorization: Bearer !TOKEN!" -H "Content-Type: application/json" -d @update_entity.json > update_result.json + + type update_result.json >> "%REPORT_FILE%" + echo. >> "%REPORT_FILE%" + + findstr /c:"\"code\":200" update_result.json >nul + if !errorlevel! equ 0 ( + echo [INFO] 机构中介修改接口调用成功 >> "%REPORT_FILE%" + set /a PASSED_TESTS+=1 + ) else ( + echo [ERROR] 机构中介修改接口调用失败 >> "%REPORT_FILE%" + set /a FAILED_TESTS+=1 + ) + set /a TOTAL_TESTS+=1 + + del update_entity.json + del update_result.json +) + +REM 清理临时文件 +if exist temp_response.json del temp_response.json + +REM 输出测试总结 +echo. >> "%REPORT_FILE%" +echo ======================================== >> "%REPORT_FILE%" +echo 测试总结 >> "%REPORT_FILE%" +echo ======================================== >> "%REPORT_FILE%" +echo 总测试数: %TOTAL_TESTS% >> "%REPORT_FILE%" +echo 通过: %PASSED_TESTS% >> "%REPORT_FILE%" +echo 失败: %FAILED_TESTS% >> "%REPORT_FILE%" +echo ======================================== >> "%REPORT_FILE%" + +echo. +echo ======================================== +echo 测试总结 +echo ======================================== +echo 总测试数: %TOTAL_TESTS% +echo 通过: %PASSED_TESTS% +echo 失败: %FAILED_TESTS% +echo ======================================== +echo. +echo 详细报告已保存到: %REPORT_FILE% + +if %FAILED_TESTS% equ 0 ( + echo [INFO] 所有测试通过! + exit /b 0 +) else ( + echo [ERROR] 部分测试失败,请查看详细日志 + exit /b 1 +) diff --git a/doc/scripts/test_intermediary_type_fix.sh b/doc/scripts/test_intermediary_type_fix.sh new file mode 100644 index 0000000..9fe5662 --- /dev/null +++ b/doc/scripts/test_intermediary_type_fix.sh @@ -0,0 +1,271 @@ +#!/bin/bash + +# 中介类型修改修复测试脚本 +# 测试个人和机构中介的修改功能 + +BASE_URL="http://localhost:8080" +USERNAME="admin" +PASSWORD="admin123" + +# 颜色输出 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# 测试结果统计 +TOTAL_TESTS=0 +PASSED_TESTS=0 +FAILED_TESTS=0 + +# 测试报告文件 +REPORT_FILE="doc/scripts/test_output/test_report_$(date +%Y%m%d_%H%M%S).txt" +mkdir -p doc/scripts/test_output + +# 日志函数 +log_info() { + echo -e "${GREEN}[INFO]${NC} $1" | tee -a "$REPORT_FILE" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" | tee -a "$REPORT_FILE" +} + +log_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" | tee -a "$REPORT_FILE" +} + +log_test() { + echo -e "${YELLOW}[TEST]${NC} $1" | tee -a "$REPORT_FILE" +} + +# 测试结果记录 +record_pass() { + ((PASSED_TESTS++)) + ((TOTAL_TESTS++)) + log_info "✓ 测试通过: $1" +} + +record_fail() { + ((FAILED_TESTS++)) + ((TOTAL_TESTS++)) + log_error "✗ 测试失败: $1" +} + +# 登录获取token +login() { + log_test "登录获取Token..." + local response=$(curl -s -X POST "$BASE_URL/login/test" \ + -H "Content-Type: application/json" \ + -d "{\"username\":\"$USERNAME\",\"password\":\"$PASSWORD\"}") + + local token=$(echo $response | grep -o '"token":"[^"]*' | sed 's/"token":"//') + + if [ -z "$token" ]; then + log_error "登录失败,无法获取Token" + exit 1 + fi + + log_info "登录成功,Token: ${token:0:20}..." + echo "$token" +} + +# 获取中介列表 +get_intermediary_list() { + local token=$1 + local type=$2 + + log_test "获取中介列表(类型: $type)..." + local response=$(curl -s -X GET "$BASE_URL/dpc/intermediary/list?intermediaryType=$type&pageNum=1&pageSize=1" \ + -H "Authorization: Bearer $token") + + echo "$response" +} + +# 测试修改个人中介 +test_update_person_intermediary() { + local token=$1 + local intermediary_id=$2 + + log_test "测试修改个人中介 (ID: $intermediary_id)..." + + local update_data=$(cat < + + +``` + +#### 2. 导入对话框改造 + +支持选择导入类型,并根据类型下载对应模板: + +```vue + + + + + + 个人中介 + 机构中介 + + + + + +
将文件拖到此处,或点击上传
+
+ 是否更新已经存在的数据 + 下载模板 +
+
+ 仅允许导入"xls"或"xlsx"格式文件。 +
+
+ +
+``` + +### 详情对话框设计 + +#### 对话框结构 + +```vue + + + + + {{ detailData.intermediaryId }} + {{ detailData.intermediaryTypeName }} + {{ detailData.name }} + {{ detailData.certificateNo }} + + 正常 + 停用 + + {{ detailData.dataSourceName }} + + + + + + + + + {{ detailData.remark || '-' }} + {{ detailData.createTime }} + {{ detailData.createBy }} + + + +``` + +#### 数据属性 + +```javascript +data() { + return { + // ... 现有数据 ... + + // 详情对话框 + detailOpen: false, + detailData: {}, + + // 导入参数 + upload: { + open: false, + title: "", + isUploading: false, + updateSupport: 0, + importType: "person", // person 或 entity + headers: { Authorization: "Bearer " + getToken() }, + url: "" // 动态设置 + } + } +} +``` + +#### 方法实现 + +```javascript +methods: { + /** 查看详情操作 */ + handleDetail(row) { + const intermediaryId = row.intermediaryId; + getIntermediary(intermediaryId).then(response => { + this.detailData = response.data; + this.detailOpen = true; + }); + }, + + /** 导入按钮操作 */ + handleImport() { + this.upload.title = "中介黑名单数据导入"; + this.upload.importType = "person"; // 默认个人 + this.upload.updateSupport = 0; + this.upload.open = true; + }, + + /** 下载导入模板 */ + downloadImportTemplate() { + if (this.upload.importType === 'person') { + this.download('dpc/intermediary/importPersonTemplate', {}, `个人中介黑名单模板_${new Date().getTime()}.xlsx`); + } else { + this.download('dpc/intermediary/importEntityTemplate', {}, `机构中介黑名单模板_${new Date().getTime()}.xlsx`); + } + }, + + // 文件上传中处理 + handleFileUploadProgress(event, file, fileList) { + this.upload.isUploading = true; + }, + + // 文件上传成功处理 + handleFileSuccess(response, file, fileList) { + this.upload.isUploading = false; + this.upload.open = false; + this.getList(); + this.$alert("
" + response.msg + "
", "导入结果"); + }, + + // 提交上传文件 + submitFileForm() { + // 根据导入类型设置上传地址 + if (this.upload.importType === 'person') { + this.upload.url = process.env.VUE_APP_BASE_API + "/dpc/intermediary/importPersonData?updateSupport=" + this.upload.updateSupport; + } else { + this.upload.url = process.env.VUE_APP_BASE_API + "/dpc/intermediary/importEntityData?updateSupport=" + this.upload.updateSupport; + } + this.$refs.upload.submit(); + } +} +``` + +### 新增/编辑对话框增强 + +#### 使用 Tabs 分组展示字段 + +```vue + + + + + + + + + + + + + + + + 个人 + 机构 + + + + + + + + + + + + + + 正常 + 停用 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 股东信息 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +#### 数据属性和方法 + +```javascript +data() { + return { + // ... 现有数据 ... + activeTab: 'basic' + } +}, + +methods: { + // 表单重置 + reset() { + this.form = { + intermediaryId: 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 + }; + this.activeTab = 'basic'; + this.resetForm("form"); + }, + + // 中介类型切换处理 + handleTypeChange(value) { + // 切换到对应的标签页 + if (value === '1') { + this.activeTab = 'person'; + } else if (value === '2') { + this.activeTab = 'entity'; + } + } +} +``` + +## 数据流设计 + +### 详情数据流 + +``` +用户点击"详情"按钮 + ↓ +调用 getIntermediary(id) + ↓ +后端根据 intermediaryType 返回不同的 VO + ↓ +前端接收响应并存储到 detailData + ↓ +详情对话框根据 detailData.intermediaryType 渲染不同字段 +``` + +### 导入数据流 + +``` +用户点击"导入"按钮 + ↓ +打开导入对话框,默认选择"个人"类型 + ↓ +用户选择导入类型(个人/机构) + ↓ +用户点击"下载模板" + ↓ +根据类型调用对应的模板下载接口 + ↓ +用户填写 Excel 并上传 + ↓ +根据类型设置上传地址 + ↓ +调用对应的导入接口 + ↓ +后端处理并返回结果 +``` + +### 表单提交数据流 + +``` +用户点击"新增"或"修改" + ↓ +打开表单对话框 + ↓ +用户选择中介类型(自动切换到对应标签页) + ↓ +用户填写基本信息和详细字段 + ↓ +用户点击"确定" + ↓ +前端合并所有字段(核心字段 + 类型专属字段) + ↓ +调用 addIntermediary 或 updateIntermediary + ↓ +后端根据 intermediaryType 保存对应字段 +``` + +## 字段映射表 + +### 个人字段映射 + +| 前端表单字段 | 后端字段 | 显示名称 | +|------------|---------|---------| +| indivType | indiv_type | 人员类型 | +| indivSubType | indiv_sub_type | 人员子类型 | +| indivGender | indiv_gender | 性别 | +| indivCertType | indiv_cert_type | 证件类型 | +| indivPhone | indiv_phone | 手机号码 | +| indivWechat | indiv_wechat | 微信号 | +| indivAddress | indiv_address | 联系地址 | +| indivCompany | indiv_company | 所在公司 | +| indivPosition | indiv_position | 职位 | +| indivRelatedId | indiv_related_id | 关联人员ID | +| indivRelation | indiv_relation | 关联关系 | + +### 机构字段映射 + +| 前端表单字段 | 后端字段 | 显示名称 | +|------------|---------|---------| +| corpCreditCode | corp_credit_code | 统一社会信用代码 | +| corpType | corp_type | 主体类型 | +| corpNature | corp_nature | 企业性质 | +| corpIndustryCategory | corp_industry_category | 行业分类 | +| corpIndustry | corp_industry | 所属行业 | +| corpEstablishDate | corp_establish_date | 成立日期 | +| corpAddress | corp_address | 注册地址 | +| corpLegalRep | corp_legal_rep | 法定代表人 | +| corpLegalCertType | corp_legal_cert_type | 法定代表人证件类型 | +| corpLegalCertNo | corp_legal_cert_no | 法定代表人证件号码 | +| corpShareholder1 | corp_shareholder_1 | 股东1 | +| corpShareholder2 | corp_shareholder_2 | 股东2 | +| corpShareholder3 | corp_shareholder_3 | 股东3 | +| corpShareholder4 | corp_shareholder_4 | 股东4 | +| corpShareholder5 | corp_shareholder_5 | 股东5 | + +## 用户体验设计 + +### 交互细节 + +1. **类型切换自动跳转** + - 用户选择"个人"类型,自动跳转到"个人信息"标签页 + - 用户选择"机构"类型,自动跳转到"机构信息"标签页 + +2. **导入类型提示** + - 导入对话框顶部显示当前选择的导入类型 + - 下载模板链接根据类型变化 + +3. **详情字段空值处理** + - 字段值为空时显示 "-" + - 避免显示空白或 undefined + +4. **表单验证** + - 基本信息标签页的字段保持原有验证规则 + - 详细信息字段暂时设为可选,减少录入压力 + +### 样式优化 + +- 使用 `el-tabs` 组织大量字段,提高可读性 +- 使用 `el-row` 和 `el-col` 实现响应式布局 +- 详情对话框使用 `el-descriptions` 组件,展示更美观 +- 对话框宽度适当增加,容纳更多字段 + +## 技术约束 + +1. **前端框架**:Vue 2.6.12 +2. **UI 组件库**:Element UI 2.15.14 +3. **HTTP 客户端**:Axios 0.28.1 +4. **向后兼容**:保持现有功能不变,只做增强 + +## 测试要点 + +### 功能测试 +- [ ] 详情对话框正确显示个人类型字段 +- [ ] 详情对话框正确显示机构类型字段 +- [ ] 新增/编辑对话框正确切换标签页 +- [ ] 个人中介模板下载正常 +- [ ] 机构中介模板下载正常 +- [ ] 个人中介数据导入正常 +- [ ] 机构中介数据导入正常 + +### 兼容性测试 +- [ ] 旧数据详情显示正常(字段为空时显示"-") +- [ ] 现有列表查询功能正常 +- [ ] 现有新增/编辑功能正常 +- [ ] 现有删除功能正常 +- [ ] 现有导出功能正常 diff --git a/openspec/changes/sync-intermediary-frontend-with-detailed-fields/proposal.md b/openspec/changes/sync-intermediary-frontend-with-detailed-fields/proposal.md new file mode 100644 index 0000000..fe43cd2 --- /dev/null +++ b/openspec/changes/sync-intermediary-frontend-with-detailed-fields/proposal.md @@ -0,0 +1,159 @@ +# Proposal: 同步前端以支持中介黑名单详细字段和类型化模板导入 + +## Change ID +`sync-intermediary-frontend-with-detailed-fields` + +## Summary +同步前端代码,使其与后端 API 文档中定义的中介黑名单增强功能保持一致,支持个人和机构类型的详细字段展示,以及类型化的模板下载和导入功能。 + +## Motivation + +### 问题背景 +后端已完成中介黑名单的增强(变更 `enhance-intermediary-with-detailed-fields`),新增了: +1. 个人类型的详细字段(人员类型、性别、证件类型、手机号码、微信号等) +2. 机构类型的详细字段(统一社会信用代码、主体类型、企业性质、法定代表人、股东等) +3. 分离的个人和机构导入模板下载接口 +4. 分离的个人和机构导入接口 + +### 现状 +当前前端代码 [ruoyi-ui/src/views/dpcIntermediary/index.vue](../../../../ruoyi-ui/src/views/dpcIntermediary/index.vue) 和 [ruoyi-ui/src/api/dpcIntermediary.js](../../../../ruoyi-ui/src/api/dpcIntermediary.js) 仅支持基础字段: +- 只显示核心字段(姓名/机构名称、证件号、中介类型、状态、备注) +- 只有一个通用的导入模板下载接口 +- 只有一个通用的导入接口 +- 详情对话框不支持根据类型显示不同字段 + +### 业务需求 +1. 列表页面保持简洁,显示核心字段 +2. 详情对话框需要根据中介类型显示不同的详细字段 +3. 导入功能需要支持分别下载和导入个人/机构模板 +4. 新增/编辑对话框需要支持详细字段的录入 + +## Scope + +### 包含的功能 + +#### 2.1 API 接口层修改 +- 添加个人中介模板下载接口调用 +- 添加机构中介模板下载接口调用 +- 添加个人中介数据导入接口调用 +- 添加机构中介数据导入接口调用 +- 保留原有通用接口以保持向后兼容 + +#### 2.2 列表页面修改 +- 保持列表显示简洁(核心字段) +- 添加"查看详情"按钮 +- 导入功能改为支持类型选择(个人/机构) + +#### 2.3 详情对话框新增 +- 根据中介类型动态显示不同的字段 +- 个人类型显示:人员类型、人员子类型、性别、证件类型、手机号码、微信号等 +- 机构类型显示:统一社会信用代码、主体类型、企业性质、法定代表人、股东等 +- 支持只读模式,不提供编辑功能 + +#### 2.4 新增/编辑对话框增强 +- 根据中介类型显示对应的字段组 +- 个人类型显示个人相关字段 +- 机构类型显示机构相关字段 +- 使用表单验证确保数据完整性 + +### 明确排除 +- 后端代码修改(已在 `enhance-intermediary-with-detailed-fields` 中完成) +- 数据库结构修改(已在 `enhance-intermediary-with-detailed-fields` 中完成) +- 路由和菜单配置修改(保持现有配置) + +## Proposed Design +详见 [design.md](./design.md) + +## Alternatives Considered + +### 选项1:在列表中展开显示所有字段 +**优点**: +- 用户无需点击详情即可看到完整信息 + +**缺点**: +- 列表过于拥挤,不利于快速浏览 +- 个人和机构字段混杂,难以阅读 + +**决定**:不采用。保持列表简洁,详情通过对话框展示。 + +### 选项2:使用两个独立的页面(个人列表和机构列表) +**优点**: +- 页面结构清晰,各自独立 + +**缺点**: +- 需要添加新的路由和菜单配置 +- 代码重复度高 +- 不符合单一数据源的管理模式 + +**决定**:不采用。使用同一个列表页面,通过中介类型区分。 + +### 选项3:在现有对话框中内嵌详情视图 +**优点**: +- 减少对话框数量 + +**缺点**: +- 编辑和查看模式混合,逻辑复杂 +- 表单验证逻辑难以处理 + +**决定**:不采用。分离详情对话框和编辑对话框,职责更清晰。 + +## Impact + +### 前端影响 + +#### API 层 +- 新增 4 个接口调用函数(模板下载 × 2,数据导入 × 2) +- 修改导入对话框以支持类型选择 + +#### 视图层 +- 新增详情对话框组件 +- 修改列表操作列(添加"查看详情"按钮) +- 修改新增/编辑对话框(添加详细字段) +- 修改导入对话框(支持类型选择和对应的模板下载) + +#### 数据流 +- 详情接口返回的数据结构根据类型不同 +- 表单提交需要包含对应类型的字段 + +### 用户体验影响 +- **正面**:可以看到更完整的中介信息 +- **正面**:导入模板更符合实际需求,减少录入错误 +- **中性**:导入时需要先选择类型,增加一步操作 + +## Dependencies +- 依赖后端变更 `enhance-intermediary-with-detailed-fields` 必须先完成 +- 依赖后端 API 接口按 [doc/中介黑名单管理API文档.md](../../../../doc/中介黑名单管理API文档.md) 定义实现 + +## Related Changes +- `enhance-intermediary-with-detailed-fields` - 后端增强功能 + +## Open Questions + +1. **详情对话框是否支持编辑?** + - 建议:不支持编辑,只做展示。编辑使用现有的编辑对话框。 + +2. **新增/编辑对话框如何处理大量字段?** + - 建议:使用 el-tabs 或 el-row/el-col 分组展示,提高可读性。 + +3. **导入时是否需要类型验证?** + - 建议:在后端验证,前端只负责选择正确的模板和接口。 + +4. **旧数据的详情如何处理?** + - 建议:旧数据没有详细字段,详情对话框显示空值或占位符(如"未填写")。 + +## Success Criteria +- [ ] API 接口层添加新的接口调用函数 +- [ ] 列表页面添加"查看详情"按钮 +- [ ] 详情对话框根据类型正确显示不同字段 +- [ ] 新增/编辑对话框支持详细字段录入 +- [ ] 导入功能支持个人/机构类型选择 +- [ ] 可以下载个人中介专用模板 +- [ ] 可以下载机构中介专用模板 +- [ ] 可以使用个人模板导入数据 +- [ ] 可以使用机构模板导入数据 +- [ ] 现有功能保持正常运行 + +## References +- [doc/中介黑名单管理API文档.md](../../../../doc/中介黑名单管理API文档.md) +- [openspec/changes/enhance-intermediary-with-detailed-fields/proposal.md](../enhance-intermediary-with-detailed-fields/proposal.md) +- [openspec/changes/enhance-intermediary-with-detailed-fields/design.md](../enhance-intermediary-with-detailed-fields/design.md) diff --git a/openspec/changes/sync-intermediary-frontend-with-detailed-fields/specs/frontend-api-layer/spec.md b/openspec/changes/sync-intermediary-frontend-with-detailed-fields/specs/frontend-api-layer/spec.md new file mode 100644 index 0000000..1d39e34 --- /dev/null +++ b/openspec/changes/sync-intermediary-frontend-with-detailed-fields/specs/frontend-api-layer/spec.md @@ -0,0 +1,67 @@ +# Spec: 前端 API 层扩展 + +## ADDED Requirements + +### Requirement: 添加个人中介模板下载接口调用 + +前端 SHALL 提供调用个人中介模板下载接口的函数。 + +#### Scenario: 用户下载个人中介导入模板 + +**Given** 用户在中介黑名单列表页面 +**And** 用户点击"导入"按钮 +**And** 用户选择"个人中介"类型 +**When** 用户点击"下载模板"链接 +**Then** 系统调用 `/dpc/intermediary/importPersonTemplate` 接口 +**And** 系统下载个人中介黑名单模板 Excel 文件 +**And** 文件名格式为 `个人中介黑名单模板_{timestamp}.xlsx` + +--- + +### Requirement: 添加机构中介模板下载接口调用 + +前端 SHALL 提供调用机构中介模板下载接口的函数。 + +#### Scenario: 用户下载机构中介导入模板 + +**Given** 用户在中介黑名单列表页面 +**And** 用户点击"导入"按钮 +**And** 用户选择"机构中介"类型 +**When** 用户点击"下载模板"链接 +**Then** 系统调用 `/dpc/intermediary/importEntityTemplate` 接口 +**And** 系统下载机构中介黑名单模板 Excel 文件 +**And** 文件名格式为 `机构中介黑名单模板_{timestamp}.xlsx` + +--- + +### Requirement: 添加个人中介数据导入接口调用 + +前端 SHALL 提供调用个人中介数据导入接口的函数。 + +#### Scenario: 用户导入个人中介数据 + +**Given** 用户在中介黑名单列表页面 +**And** 用户点击"导入"按钮 +**And** 用户选择"个人中介"类型 +**And** 用户已下载并填写了个人中介模板 +**When** 用户上传 Excel 文件 +**Then** 系统调用 `/dpc/intermediary/importPersonData` 接口 +**And** 系统传递 `updateSupport` 参数 +**And** 系统显示导入结果 + +--- + +### Requirement: 添加机构中介数据导入接口调用 + +前端 SHALL 提供调用机构中介数据导入接口的函数。 + +#### Scenario: 用户导入机构中介数据 + +**Given** 用户在中介黑名单列表页面 +**And** 用户点击"导入"按钮 +**And** 用户选择"机构中介"类型 +**And** 用户已下载并填写了机构中介模板 +**When** 用户上传 Excel 文件 +**Then** 系统调用 `/dpc/intermediary/importEntityData` 接口 +**And** 系统传递 `updateSupport` 参数 +**And** 系统显示导入结果 diff --git a/openspec/changes/sync-intermediary-frontend-with-detailed-fields/specs/frontend-detail-view/spec.md b/openspec/changes/sync-intermediary-frontend-with-detailed-fields/specs/frontend-detail-view/spec.md new file mode 100644 index 0000000..dfe62b8 --- /dev/null +++ b/openspec/changes/sync-intermediary-frontend-with-detailed-fields/specs/frontend-detail-view/spec.md @@ -0,0 +1,58 @@ +# Spec: 前端详情视图 + +## ADDED Requirements + +### Requirement: 添加中介详情查看功能 + +前端 SHALL 提供查看中介详细信息的对话框,根据中介类型显示不同的字段。 + +#### Scenario: 查看个人类型中介详情 + +**Given** 用户在中介黑名单列表页面 +**And** 列表中存在一条个人类型的中介记录 +**When** 用户点击该记录的"详情"按钮 +**Then** 系统打开详情对话框 +**And** 标题为"中介黑名单详情" +**And** 显示核心字段(中介ID、中介类型、姓名、证件号、状态、数据来源) +**And** 显示个人专属字段(人员类型、人员子类型、性别、证件类型、手机号码、微信号、联系地址、所在公司、职位、关联人员ID、关联关系) +**And** 不显示机构专属字段 +**And** 空值字段显示"-" +**And** 对话框只有"关闭"按钮 + +#### Scenario: 查看机构类型中介详情 + +**Given** 用户在中介黑名单列表页面 +**And** 列表中存在一条机构类型的中介记录 +**When** 用户点击该记录的"详情"按钮 +**Then** 系统打开详情对话框 +**And** 标题为"中介黑名单详情" +**And** 显示核心字段(中介ID、中介类型、机构名称、统一社会信用代码、状态、数据来源) +**And** 显示机构专属字段(主体类型、企业性质、行业分类、所属行业、成立日期、注册地址、法定代表人、法定代表人证件类型、法定代表人证件号码、股东1-5) +**And** 不显示个人专属字段 +**And** 空值字段显示"-" +**And** 对话框只有"关闭"按钮 + +#### Scenario: 查看旧数据详情(无详细字段) + +**Given** 用户在中介黑名单列表页面 +**And** 列表中存在一条旧数据记录(详细字段为空) +**When** 用户点击该记录的"详情"按钮 +**Then** 系统打开详情对话框 +**And** 核心字段正常显示 +**And** 详细字段显示"-" +**And** 对话框正常关闭 + +--- + +### Requirement: 列表操作列添加详情按钮 + +列表 SHALL 在操作列中添加"详情"按钮。 + +#### Scenario: 操作列显示详情按钮 + +**Given** 用户在中介黑名单列表页面 +**When** 列表加载完成 +**Then** 操作列显示"详情"按钮 +**And** "详情"按钮不需要权限控制 +**And** "详情"按钮图标为 "el-icon-view" +**And** 操作列宽度调整为 240px(原 180px) diff --git a/openspec/changes/sync-intermediary-frontend-with-detailed-fields/specs/frontend-form-enhancement/spec.md b/openspec/changes/sync-intermediary-frontend-with-detailed-fields/specs/frontend-form-enhancement/spec.md new file mode 100644 index 0000000..84b5cc2 --- /dev/null +++ b/openspec/changes/sync-intermediary-frontend-with-detailed-fields/specs/frontend-form-enhancement/spec.md @@ -0,0 +1,139 @@ +# Spec: 前端表单增强 + +## ADDED Requirements + +### Requirement: 新增/编辑对话框支持详细字段录入 + +新增和编辑对话框 SHALL 扩展以支持个人和机构类型的详细字段录入。 + +#### Scenario: 新增个人类型中介 + +**Given** 用户点击"新增"按钮 +**And** 对话框打开,默认选择"个人"类型 +**When** 用户查看对话框 +**Then** 显示"基本信息"、"个人信息"两个标签页 +**And** 自动切换到"个人信息"标签页 +**When** 用户填写个人信息字段 +**And** 用户点击"确定"按钮 +**Then** 系统提交核心字段和个人字段到后端 +**And** 显示"新增成功"提示 +**And** 列表刷新 + +#### Scenario: 新增机构类型中介 + +**Given** 用户点击"新增"按钮 +**And** 用户将中介类型切换为"机构" +**When** 用户查看对话框 +**Then** 显示"基本信息"、"机构信息"两个标签页 +**And** 自动切换到"机构信息"标签页 +**When** 用户填写机构信息字段 +**And** 用户点击"确定"按钮 +**Then** 系统提交核心字段和机构字段到后端 +**And** 显示"新增成功"提示 +**And** 列表刷新 + +#### Scenario: 编辑个人类型中介 + +**Given** 用户点击一条个人类型记录的"修改"按钮 +**When** 对话框打开 +**Then** 系统加载该记录的详细信息 +**And** "个人信息"标签页显示已保存的个人字段值 +**When** 用户修改个人信息字段 +**And** 用户点击"确定"按钮 +**Then** 系统提交修改后的数据到后端 +**And** 显示"修改成功"提示 +**And** 列表刷新 + +#### Scenario: 编辑机构类型中介 + +**Given** 用户点击一条机构类型记录的"修改"按钮 +**When** 对话框打开 +**Then** 系统加载该记录的详细信息 +**And** "机构信息"标签页显示已保存的机构字段值 +**When** 用户修改机构信息字段 +**And** 用户点击"确定"按钮 +**Then** 系统提交修改后的数据到后端 +**And** 显示"修改成功"提示 +**And** 列表刷新 + +#### Scenario: 切换中介类型时自动跳转标签页 + +**Given** 用户在新增或编辑对话框中 +**And** 当前选择的是"个人"类型 +**When** 用户将中介类型切换为"机构" +**Then** 对话框自动切换到"机构信息"标签页 +**And** 个人字段保持不变(隐藏但保留值) + +--- + +### Requirement: 导入对话框支持类型选择 + +导入对话框 SHALL 支持选择导入类型(个人/机构),并根据类型下载对应模板。 + +#### Scenario: 选择个人类型导入 + +**Given** 用户点击"导入"按钮 +**When** 对话框打开 +**Then** 默认选择"个人中介"类型 +**And** 显示"是否更新已经存在的数据"复选框 +**And** 显示"下载模板"链接 +**When** 用户保持"个人中介"类型 +**And** 用户点击"下载模板"链接 +**Then** 系统下载个人中介模板 + +#### Scenario: 选择机构类型导入 + +**Given** 用户点击"导入"按钮 +**When** 对话框打开 +**And** 用户选择"机构中介"类型 +**And** 用户点击"下载模板"链接 +**Then** 系统下载机构中介模板 + +#### Scenario: 上传个人中介文件 + +**Given** 用户在导入对话框中 +**And** 用户选择"个人中介"类型 +**And** 用户勾选"是否更新已经存在的数据" +**When** 用户上传 Excel 文件 +**And** 用户点击"确定"按钮 +**Then** 系统调用 `/dpc/intermediary/importPersonData` 接口 +**And** 系统传递 `updateSupport=true` 参数 +**And** 显示导入结果 + +#### Scenario: 上传机构中介文件 + +**Given** 用户在导入对话框中 +**And** 用户选择"机构中介"类型 +**And** 用户不勾选"是否更新已经存在的数据" +**When** 用户上传 Excel 文件 +**And** 用户点击"确定"按钮 +**Then** 系统调用 `/dpc/intermediary/importEntityData` 接口 +**And** 系统传递 `updateSupport=false` 参数 +**And** 显示导入结果 + +--- + +### Requirement: 表单字段布局优化 + +表单 SHALL 使用标签页和响应式布局优化大量字段的展示。 + +#### Scenario: 个人信息标签页布局 + +**Given** 用户在新增或编辑对话框中 +**And** 中介类型为"个人" +**When** 用户查看"个人信息"标签页 +**Then** 字段使用两列布局(el-col :span="12") +**And** 长文本字段(如联系地址)使用整行布局 +**And** 字段标签宽度为 120px +**And** 输入框有合适的 maxlength 限制 + +#### Scenario: 机构信息标签页布局 + +**Given** 用户在新增或编辑对话框中 +**And** 中介类型为"机构" +**When** 用户查看"机构信息"标签页 +**Then** 字段使用两列布局 +**And** 长文本字段(如注册地址)使用整行布局 +**And** 股东信息区域使用分隔线(el-divider)分隔 +**And** 字段标签宽度为 140px( accommodate 更长的标签名称) +**And** 输入框有合适的 maxlength 限制 diff --git a/openspec/changes/sync-intermediary-frontend-with-detailed-fields/tasks.md b/openspec/changes/sync-intermediary-frontend-with-detailed-fields/tasks.md new file mode 100644 index 0000000..4635449 --- /dev/null +++ b/openspec/changes/sync-intermediary-frontend-with-detailed-fields/tasks.md @@ -0,0 +1,139 @@ +# Tasks: 同步前端以支持中介黑名单详细字段和类型化模板导入 + +## 任务列表 + +### 阶段 1:API 接口层扩展 + +- [x] 1.1 在 `ruoyi-ui/src/api/dpcIntermediary.js` 中添加 `importPersonTemplate` 函数 + - 调用 `POST /dpc/intermediary/importPersonTemplate` + - 返回个人中介模板文件 + +- [x] 1.2 在 `ruoyi-ui/src/api/dpcIntermediary.js` 中添加 `importEntityTemplate` 函数 + - 调用 `POST /dpc/intermediary/importEntityTemplate` + - 返回机构中介模板文件 + +- [x] 1.3 在 `ruoyi-ui/src/api/dpcIntermediary.js` 中添加 `importPersonData` 函数 + - 调用 `POST /dpc/intermediary/importPersonData` + - 支持传递 `updateSupport` 参数 + +- [x] 1.4 在 `ruoyi-ui/src/api/dpcIntermediary.js` 中添加 `importEntityData` 函数 + - 调用 `POST /dpc/intermediary/importEntityData` + - 支持传递 `updateSupport` 参数 + +### 阶段 2:详情对话框实现 + +- [x] 2.1 在 `ruoyi-ui/src/views/dpcIntermediary/index.vue` 的 data 中添加详情相关属性 + - 添加 `detailOpen: false` + - 添加 `detailData: {}` + +- [x] 2.2 在 `ruoyi-ui/src/views/dpcIntermediary/index.vue` 的 template 中添加详情对话框 + - 使用 `el-descriptions` 组件展示字段 + - 根据中介类型条件渲染个人/机构专属字段 + +- [x] 2.3 实现 `handleDetail` 方法 + - 调用 `getIntermediary` 接口获取详情 + - 将数据存储到 `detailData` + - 打开详情对话框 + +- [x] 2.4 在列表操作列添加"详情"按钮 + - 使用 `el-icon-view` 图标 + - 绑定 `handleDetail` 方法 + - 调整操作列宽度为 240px + +### 阶段 3:新增/编辑对话框增强 + +- [x] 3.1 在 `ruoyi-ui/src/views/dpcIntermediary/index.vue` 的 data 中添加 `activeTab` 属性 + - 默认值为 `'basic'` + +- [x] 3.2 在表单中添加 `el-tabs` 组件 + - 添加"基本信息"标签页(name="basic") + - 添加"个人信息"标签页(name="person") + - 添加"机构信息"标签页(name="entity") + +- [x] 3.3 实现"个人信息"标签页内容 + - 添加人员类型、人员子类型、性别、证件类型字段 + - 添加手机号码、微信号、联系地址字段 + - 添加所在公司、职位、关联人员ID、关联关系字段 + - 使用两列响应式布局 + +- [x] 3.4 实现"机构信息"标签页内容 + - 添加统一社会信用代码、主体类型、企业性质字段 + - 添加行业分类、所属行业、成立日期、注册地址字段 + - 添加法定代表人及其证件信息字段 + - 添加股东1-5字段,使用分隔线分组 + +- [x] 3.5 更新 `reset` 方法 + - 添加所有个人字段的初始化 + - 添加所有机构字段的初始化 + - 重置 `activeTab` 为 `'basic'` + +- [x] 3.6 实现 `handleTypeChange` 方法 + - 监听中介类型变化 + - 自动切换到对应的标签页 + +- [x] 3.7 调整对话框宽度 + - 将宽度从 600px 调整为 900px + - 适应更多字段的展示 + +### 阶段 4:导入对话框改造 + +- [x] 4.1 在导入对话框中添加类型选择单选框组 + - 选项:个人中介(person)、机构中介(entity) + - 默认选择"个人中介" + +- [x] 4.2 在 `upload` 数据中添加 `importType` 属性 + - 默认值为 `'person'` + +- [x] 4.3 修改 `downloadImportTemplate` 方法 + - 根据 `upload.importType` 调用对应的模板下载接口 + - 个人类型调用 `importPersonTemplate` + - 机构类型调用 `importEntityTemplate` + +- [x] 4.4 修改 `submitFileForm` 方法 + - 根据 `upload.importType` 动态设置 `upload.url` + - 个人类型使用 `/dpc/intermediary/importPersonData` + - 机构类型使用 `/dpc/intermediary/importEntityData` + - 添加 `updateSupport` 参数到 URL + +- [x] 4.5 调整导入对话框宽度 + - 从 400px 调整为 450px + - 适应新增的类型选择区域 + +### 阶段 5:测试验证 + +- [x] 5.1 测试详情对话框功能 + - 测试个人类型详情显示 + - 测试机构类型详情显示 + - 测试旧数据详情显示(字段为空) + +- [x] 5.2 测试新增/编辑功能 + - 测试新增个人类型中介 + - 测试新增机构类型中介 + - 测试编辑个人类型中介 + - 测试编辑机构类型中介 + - 测试类型切换时标签页自动跳转 + +- [x] 5.3 测试导入功能 + - 测试个人类型模板下载 + - 测试机构类型模板下载 + - 测试个人类型数据导入 + - 测试机构类型数据导入 + - 测试更新支持选项 + +- [x] 5.4 测试兼容性 + - 测试现有列表查询功能 + - 测试现有删除功能 + - 测试现有导出功能 + +## 依赖关系 + +- 阶段 1 必须首先完成,为后续阶段提供 API 接口 +- 阶段 2、3、4 可以并行开发 +- 阶段 5 必须在所有开发阶段完成后进行 + +## 验收标准 + +每个任务完成后应满足: +- 代码符合 Vue 2.x 和 Element UI 规范 +- 功能与设计文档描述一致 +- 不影响现有功能的正常运行 diff --git a/ruoyi-dpc/src/main/java/com/ruoyi/dpc/controller/DpcEnumController.java b/ruoyi-dpc/src/main/java/com/ruoyi/dpc/controller/DpcEnumController.java new file mode 100644 index 0000000..e49f070 --- /dev/null +++ b/ruoyi-dpc/src/main/java/com/ruoyi/dpc/controller/DpcEnumController.java @@ -0,0 +1,154 @@ +package com.ruoyi.dpc.controller; + +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.dpc.domain.vo.EnumOptionVO; +import com.ruoyi.dpc.enums.*; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.ArrayList; +import java.util.List; + +/** + * DPC枚举接口Controller + * + * @author ruoyi + */ +@Tag(name = "DPC枚举接口", description = "中介黑名单相关枚举选项接口") +@RestController +@RequestMapping("/dpc/enum") +public class DpcEnumController { + + /** + * 获取人员类型选项 + */ + @Operation(summary = "获取人员类型选项") + @GetMapping("/indivType") + public AjaxResult getIndivTypeOptions() { + List options = new ArrayList<>(); + for (IndivType type : IndivType.values()) { + options.add(new EnumOptionVO(type.getCode(), type.getDesc())); + } + return AjaxResult.success(options); + } + + /** + * 获取人员子类型选项 + */ + @Operation(summary = "获取人员子类型选项") + @GetMapping("/indivSubType") + public AjaxResult getIndivSubTypeOptions() { + List options = new ArrayList<>(); + for (IndivSubType type : IndivSubType.values()) { + options.add(new EnumOptionVO(type.getCode(), type.getDesc())); + } + return AjaxResult.success(options); + } + + /** + * 获取性别选项 + */ + @Operation(summary = "获取性别选项") + @GetMapping("/gender") + public AjaxResult getGenderOptions() { + List options = new ArrayList<>(); + for (Gender gender : Gender.values()) { + options.add(new EnumOptionVO(gender.getCode(), gender.getDesc())); + } + return AjaxResult.success(options); + } + + /** + * 获取证件类型选项 + */ + @Operation(summary = "获取证件类型选项") + @GetMapping("/certType") + public AjaxResult getCertTypeOptions() { + List options = new ArrayList<>(); + for (CertType type : CertType.values()) { + options.add(new EnumOptionVO(type.getCode(), type.getDesc())); + } + return AjaxResult.success(options); + } + + /** + * 获取关联关系选项 + */ + @Operation(summary = "获取关联关系选项") + @GetMapping("/relationType") + public AjaxResult getRelationTypeOptions() { + List options = new ArrayList<>(); + for (RelationType type : RelationType.values()) { + options.add(new EnumOptionVO(type.getCode(), type.getDesc())); + } + return AjaxResult.success(options); + } + + /** + * 获取主体类型选项 + */ + @Operation(summary = "获取主体类型选项") + @GetMapping("/corpType") + public AjaxResult getCorpTypeOptions() { + List options = new ArrayList<>(); + for (CorpType type : CorpType.values()) { + options.add(new EnumOptionVO(type.getCode(), type.getDesc())); + } + return AjaxResult.success(options); + } + + /** + * 获取企业性质选项 + */ + @Operation(summary = "获取企业性质选项") + @GetMapping("/corpNature") + public AjaxResult getCorpNatureOptions() { + List options = new ArrayList<>(); + for (CorpNature nature : CorpNature.values()) { + options.add(new EnumOptionVO(nature.getCode(), nature.getDesc())); + } + return AjaxResult.success(options); + } + + /** + * 获取中介类型选项 + */ + @Operation(summary = "获取中介类型选项") + @GetMapping("/intermediaryType") + public AjaxResult getIntermediaryTypeOptions() { + List options = new ArrayList<>(); + for (IntermediaryType type : IntermediaryType.values()) { + options.add(new EnumOptionVO(type.getCode(), type.getDesc())); + } + return AjaxResult.success(options); + } + + /** + * 获取中介状态选项 + */ + @Operation(summary = "获取中介状态选项") + @GetMapping("/intermediaryStatus") + public AjaxResult getIntermediaryStatusOptions() { + List options = new ArrayList<>(); + for (IntermediaryStatus status : IntermediaryStatus.values()) { + options.add(new EnumOptionVO(status.getCode(), status.getDesc())); + } + return AjaxResult.success(options); + } + + /** + * 获取数据来源选项 + */ + @Operation(summary = "获取数据来源选项") + @GetMapping("/dataSource") + public AjaxResult getDataSourceOptions() { + List options = new ArrayList<>(); + for (DataSource source : DataSource.values()) { + options.add(new EnumOptionVO(source.getCode(), source.getDesc())); + } + return AjaxResult.success(options); + } +} diff --git a/ruoyi-dpc/src/main/java/com/ruoyi/dpc/controller/DpcIntermediaryBlacklistController.java b/ruoyi-dpc/src/main/java/com/ruoyi/dpc/controller/DpcIntermediaryBlacklistController.java index e43fc8a..4fc495e 100644 --- a/ruoyi-dpc/src/main/java/com/ruoyi/dpc/controller/DpcIntermediaryBlacklistController.java +++ b/ruoyi-dpc/src/main/java/com/ruoyi/dpc/controller/DpcIntermediaryBlacklistController.java @@ -9,9 +9,7 @@ import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.core.page.TableSupport; import com.ruoyi.common.enums.BusinessType; import com.ruoyi.dpc.domain.DpcIntermediaryBlacklist; -import com.ruoyi.dpc.domain.dto.DpcIntermediaryBlacklistAddDTO; -import com.ruoyi.dpc.domain.dto.DpcIntermediaryBlacklistEditDTO; -import com.ruoyi.dpc.domain.dto.DpcIntermediaryBlacklistQueryDTO; +import com.ruoyi.dpc.domain.dto.*; import com.ruoyi.dpc.domain.excel.DpcIntermediaryBlacklistExcel; import com.ruoyi.dpc.domain.excel.DpcIntermediaryEntityExcel; import com.ruoyi.dpc.domain.excel.DpcIntermediaryPersonExcel; @@ -80,27 +78,73 @@ public class DpcIntermediaryBlacklistController extends BaseController { } /** - * 新增中介黑名单 + * 新增中介黑名单(已废弃,请使用类型专用接口) */ - @Operation(summary = "新增中介黑名单") + @Operation(summary = "新增中介黑名单(已废弃,请使用类型专用接口)") @PreAuthorize("@ss.hasPermi('dpc:intermediary:add')") @Log(title = "中介黑名单", businessType = BusinessType.INSERT) @PostMapping + @Deprecated public AjaxResult add(@Validated @RequestBody DpcIntermediaryBlacklistAddDTO addDTO) { return toAjax(intermediaryService.insertIntermediary(addDTO)); } + /** + * 新增个人中介黑名单 + */ + @Operation(summary = "新增个人中介黑名单") + @PreAuthorize("@ss.hasPermi('dpc:intermediary:add')") + @Log(title = "个人中介黑名单", businessType = BusinessType.INSERT) + @PostMapping("/person") + public AjaxResult addPerson(@Validated @RequestBody DpcIntermediaryPersonAddDTO addDTO) { + return toAjax(intermediaryService.insertPersonIntermediary(addDTO)); + } + + /** + * 新增机构中介黑名单 + */ + @Operation(summary = "新增机构中介黑名单") + @PreAuthorize("@ss.hasPermi('dpc:intermediary:add')") + @Log(title = "机构中介黑名单", businessType = BusinessType.INSERT) + @PostMapping("/entity") + public AjaxResult addEntity(@Validated @RequestBody DpcIntermediaryEntityAddDTO addDTO) { + return toAjax(intermediaryService.insertEntityIntermediary(addDTO)); + } + /** * 修改中介黑名单 */ - @Operation(summary = "修改中介黑名单") + @Operation(summary = "修改中介黑名单(已废弃,请使用类型专用接口)") @PreAuthorize("@ss.hasPermi('dpc:intermediary:edit')") @Log(title = "中介黑名单", businessType = BusinessType.UPDATE) @PutMapping + @Deprecated public AjaxResult edit(@Validated @RequestBody DpcIntermediaryBlacklistEditDTO editDTO) { return toAjax(intermediaryService.updateIntermediary(editDTO)); } + /** + * 修改个人中介黑名单 + */ + @Operation(summary = "修改个人中介黑名单") + @PreAuthorize("@ss.hasPermi('dpc:intermediary:edit')") + @Log(title = "个人中介黑名单", businessType = BusinessType.UPDATE) + @PutMapping("/person") + public AjaxResult editPerson(@Validated @RequestBody DpcIntermediaryPersonEditDTO editDTO) { + return toAjax(intermediaryService.updatePersonIntermediary(editDTO)); + } + + /** + * 修改机构中介黑名单 + */ + @Operation(summary = "修改机构中介黑名单") + @PreAuthorize("@ss.hasPermi('dpc:intermediary:edit')") + @Log(title = "机构中介黑名单", businessType = BusinessType.UPDATE) + @PutMapping("/entity") + public AjaxResult editEntity(@Validated @RequestBody DpcIntermediaryEntityEditDTO editDTO) { + return toAjax(intermediaryService.updateEntityIntermediary(editDTO)); + } + /** * 删除中介黑名单 */ @@ -137,7 +181,7 @@ public class DpcIntermediaryBlacklistController extends BaseController { @PreAuthorize("@ss.hasPermi('dpc:intermediary:import')") @Log(title = "中介黑名单", businessType = BusinessType.IMPORT) @PostMapping("/importPersonData") - public AjaxResult importPersonData(MultipartFile file, boolean updateSupport) throws Exception { + public AjaxResult importPersonData(@RequestParam("file") MultipartFile file, @RequestParam(value = "updateSupport", defaultValue = "false") boolean updateSupport) throws Exception { List list = EasyExcelUtil.importExcel(file.getInputStream(), DpcIntermediaryPersonExcel.class); String message = intermediaryService.importPersonIntermediary(list, updateSupport); return success(message); @@ -150,7 +194,7 @@ public class DpcIntermediaryBlacklistController extends BaseController { @PreAuthorize("@ss.hasPermi('dpc:intermediary:import')") @Log(title = "中介黑名单", businessType = BusinessType.IMPORT) @PostMapping("/importEntityData") - public AjaxResult importEntityData(MultipartFile file, boolean updateSupport) throws Exception { + public AjaxResult importEntityData(@RequestParam("file") MultipartFile file, @RequestParam(value = "updateSupport", defaultValue = "false") boolean updateSupport) throws Exception { List list = EasyExcelUtil.importExcel(file.getInputStream(), DpcIntermediaryEntityExcel.class); String message = intermediaryService.importEntityIntermediary(list, updateSupport); return success(message); diff --git a/ruoyi-dpc/src/main/java/com/ruoyi/dpc/domain/DpcIntermediaryBlacklist.java b/ruoyi-dpc/src/main/java/com/ruoyi/dpc/domain/DpcIntermediaryBlacklist.java index cf22e55..1dc8fca 100644 --- a/ruoyi-dpc/src/main/java/com/ruoyi/dpc/domain/DpcIntermediaryBlacklist.java +++ b/ruoyi-dpc/src/main/java/com/ruoyi/dpc/domain/DpcIntermediaryBlacklist.java @@ -111,18 +111,23 @@ public class DpcIntermediaryBlacklist implements Serializable { 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; // ============================================================ diff --git a/ruoyi-dpc/src/main/java/com/ruoyi/dpc/domain/dto/DpcIntermediaryBlacklistAddDTO.java b/ruoyi-dpc/src/main/java/com/ruoyi/dpc/domain/dto/DpcIntermediaryBlacklistAddDTO.java index 7d35c17..8126684 100644 --- a/ruoyi-dpc/src/main/java/com/ruoyi/dpc/domain/dto/DpcIntermediaryBlacklistAddDTO.java +++ b/ruoyi-dpc/src/main/java/com/ruoyi/dpc/domain/dto/DpcIntermediaryBlacklistAddDTO.java @@ -30,10 +30,6 @@ public class DpcIntermediaryBlacklistAddDTO implements Serializable { @NotBlank(message = "中介类型不能为空") private String intermediaryType; - /** 状态 */ - @NotBlank(message = "状态不能为空") - private String status; - /** 备注 */ @Size(max = 500, message = "备注长度不能超过500个字符") private String remark; @@ -62,14 +58,6 @@ public class DpcIntermediaryBlacklistAddDTO implements Serializable { this.intermediaryType = intermediaryType; } - public String getStatus() { - return status; - } - - public void setStatus(String status) { - this.status = status; - } - public String getRemark() { return remark; } diff --git a/ruoyi-dpc/src/main/java/com/ruoyi/dpc/domain/dto/DpcIntermediaryBlacklistEditDTO.java b/ruoyi-dpc/src/main/java/com/ruoyi/dpc/domain/dto/DpcIntermediaryBlacklistEditDTO.java index 2728a4c..ff34bea 100644 --- a/ruoyi-dpc/src/main/java/com/ruoyi/dpc/domain/dto/DpcIntermediaryBlacklistEditDTO.java +++ b/ruoyi-dpc/src/main/java/com/ruoyi/dpc/domain/dto/DpcIntermediaryBlacklistEditDTO.java @@ -6,6 +6,7 @@ import jakarta.validation.constraints.Size; import java.io.Serial; import java.io.Serializable; +import java.util.Date; /** * 中介人员黑名单编辑 DTO @@ -43,6 +44,90 @@ public class DpcIntermediaryBlacklistEditDTO implements Serializable { @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; } @@ -90,4 +175,212 @@ public class DpcIntermediaryBlacklistEditDTO implements Serializable { 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; + } } diff --git a/ruoyi-dpc/src/main/java/com/ruoyi/dpc/domain/dto/DpcIntermediaryEntityAddDTO.java b/ruoyi-dpc/src/main/java/com/ruoyi/dpc/domain/dto/DpcIntermediaryEntityAddDTO.java index 8318070..5d08122 100644 --- a/ruoyi-dpc/src/main/java/com/ruoyi/dpc/domain/dto/DpcIntermediaryEntityAddDTO.java +++ b/ruoyi-dpc/src/main/java/com/ruoyi/dpc/domain/dto/DpcIntermediaryEntityAddDTO.java @@ -2,17 +2,19 @@ package com.ruoyi.dpc.domain.dto; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.Size; +import lombok.Data; import java.io.Serial; import java.io.Serializable; import java.util.Date; /** - * 机构中介黑名单新增 DTO + * 机构中介新增 DTO * * @author ruoyi * @date 2026-01-29 */ +@Data public class DpcIntermediaryEntityAddDTO implements Serializable { @Serial @@ -23,18 +25,8 @@ public class DpcIntermediaryEntityAddDTO implements Serializable { @Size(min = 1, max = 100, message = "机构名称长度不能超过100个字符") private String name; - /** 状态 */ - @NotBlank(message = "状态不能为空") - private String status; - - /** 备注 */ - @Size(max = 500, message = "备注长度不能超过500个字符") - private String remark; - - // ============================================================ - // 机构专属字段 - // ============================================================ /** 统一社会信用代码 */ + @NotBlank(message = "统一社会信用代码不能为空") @Size(max = 18, message = "统一社会信用代码长度不能超过18个字符") private String corpCreditCode; @@ -93,147 +85,11 @@ public class DpcIntermediaryEntityAddDTO implements Serializable { @Size(max = 30, message = "股东5长度不能超过30个字符") private String corpShareholder5; - public String getName() { - return name; - } + /** 状态 */ + @NotBlank(message = "状态不能为空") + private String status; - public void setName(String name) { - this.name = name; - } - - 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 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; - } + /** 备注 */ + @Size(max = 500, message = "备注长度不能超过500个字符") + private String remark; } diff --git a/ruoyi-dpc/src/main/java/com/ruoyi/dpc/domain/dto/DpcIntermediaryEntityEditDTO.java b/ruoyi-dpc/src/main/java/com/ruoyi/dpc/domain/dto/DpcIntermediaryEntityEditDTO.java new file mode 100644 index 0000000..fc9397f --- /dev/null +++ b/ruoyi-dpc/src/main/java/com/ruoyi/dpc/domain/dto/DpcIntermediaryEntityEditDTO.java @@ -0,0 +1,89 @@ +package com.ruoyi.dpc.domain.dto; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 机构中介编辑 DTO + * + * @author ruoyi + * @date 2026-01-29 + */ +@Data +public class DpcIntermediaryEntityEditDTO 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; + + /** 统一社会信用代码 */ + 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; + + /** 状态 */ + @NotBlank(message = "状态不能为空") + private String status; + + /** 备注 */ + @Size(max = 500, message = "备注长度不能超过500个字符") + private String remark; +} diff --git a/ruoyi-dpc/src/main/java/com/ruoyi/dpc/domain/dto/DpcIntermediaryPersonAddDTO.java b/ruoyi-dpc/src/main/java/com/ruoyi/dpc/domain/dto/DpcIntermediaryPersonAddDTO.java index 993de3d..b68a349 100644 --- a/ruoyi-dpc/src/main/java/com/ruoyi/dpc/domain/dto/DpcIntermediaryPersonAddDTO.java +++ b/ruoyi-dpc/src/main/java/com/ruoyi/dpc/domain/dto/DpcIntermediaryPersonAddDTO.java @@ -2,16 +2,18 @@ package com.ruoyi.dpc.domain.dto; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.Size; +import lombok.Data; import java.io.Serial; import java.io.Serializable; /** - * 个人中介黑名单新增 DTO + * 个人中介新增 DTO * * @author ruoyi * @date 2026-01-29 */ +@Data public class DpcIntermediaryPersonAddDTO implements Serializable { @Serial @@ -22,31 +24,20 @@ public class DpcIntermediaryPersonAddDTO implements Serializable { @Size(min = 1, max = 100, message = "姓名长度不能超过100个字符") private String name; - /** 证件号码 */ - @NotBlank(message = "证件号码不能为空") - @Size(max = 50, message = "证件号码长度不能超过50个字符") + /** 证件号 */ + @NotBlank(message = "证件号不能为空") + @Size(max = 50, message = "证件号长度不能超过50个字符") private String certificateNo; - /** 状态 */ - @NotBlank(message = "状态不能为空") - private String status; - - /** 备注 */ - @Size(max = 500, message = "备注长度不能超过500个字符") - private String remark; - - // ============================================================ - // 个人专属字段 - // ============================================================ - /** 人员类型 */ + /** 人员类型(中介、职业背债人、房产中介等) */ @Size(max = 30, message = "人员类型长度不能超过30个字符") private String indivType; - /** 人员子类型 */ + /** 人员子类型(本人、配偶等) */ @Size(max = 50, message = "人员子类型长度不能超过50个字符") private String indivSubType; - /** 性别 */ + /** 性别(M男 F女 O其他) */ @Size(max = 1, message = "性别长度不能超过1个字符") private String indivGender; @@ -54,7 +45,7 @@ public class DpcIntermediaryPersonAddDTO implements Serializable { @Size(max = 30, message = "证件类型长度不能超过30个字符") private String indivCertType; - /** 手机号码 */ + /** 手机号码(加密存储) */ @Size(max = 20, message = "手机号码长度不能超过20个字符") private String indivPhone; @@ -82,123 +73,11 @@ public class DpcIntermediaryPersonAddDTO implements Serializable { @Size(max = 50, message = "关联关系长度不能超过50个字符") private String indivRelation; - public String getName() { - return name; - } + /** 状态 */ + @NotBlank(message = "状态不能为空") + private String status; - public void setName(String name) { - this.name = name; - } - - public String getCertificateNo() { - return certificateNo; - } - - public void setCertificateNo(String certificateNo) { - this.certificateNo = certificateNo; - } - - 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; - } + /** 备注 */ + @Size(max = 500, message = "备注长度不能超过500个字符") + private String remark; } diff --git a/ruoyi-dpc/src/main/java/com/ruoyi/dpc/domain/dto/DpcIntermediaryPersonEditDTO.java b/ruoyi-dpc/src/main/java/com/ruoyi/dpc/domain/dto/DpcIntermediaryPersonEditDTO.java new file mode 100644 index 0000000..f3510ed --- /dev/null +++ b/ruoyi-dpc/src/main/java/com/ruoyi/dpc/domain/dto/DpcIntermediaryPersonEditDTO.java @@ -0,0 +1,76 @@ +package com.ruoyi.dpc.domain.dto; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 个人中介编辑 DTO + * + * @author ruoyi + * @date 2026-01-29 + */ +@Data +public class DpcIntermediaryPersonEditDTO 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; + + /** 人员类型(中介、职业背债人、房产中介等) */ + 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; + + /** 状态 */ + @NotBlank(message = "状态不能为空") + private String status; + + /** 备注 */ + @Size(max = 500, message = "备注长度不能超过500个字符") + private String remark; +} diff --git a/ruoyi-dpc/src/main/java/com/ruoyi/dpc/domain/vo/EnumOptionVO.java b/ruoyi-dpc/src/main/java/com/ruoyi/dpc/domain/vo/EnumOptionVO.java new file mode 100644 index 0000000..06f6269 --- /dev/null +++ b/ruoyi-dpc/src/main/java/com/ruoyi/dpc/domain/vo/EnumOptionVO.java @@ -0,0 +1,28 @@ +package com.ruoyi.dpc.domain.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 枚举选项VO + * + * @author ruoyi + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class EnumOptionVO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** 选项值 */ + private String value; + + /** 选项标签 */ + private String label; +} diff --git a/ruoyi-dpc/src/main/java/com/ruoyi/dpc/enums/CertType.java b/ruoyi-dpc/src/main/java/com/ruoyi/dpc/enums/CertType.java new file mode 100644 index 0000000..1a79a5d --- /dev/null +++ b/ruoyi-dpc/src/main/java/com/ruoyi/dpc/enums/CertType.java @@ -0,0 +1,41 @@ +package com.ruoyi.dpc.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 证件类型枚举 + * + * @author ruoyi + */ +@Getter +@AllArgsConstructor +public enum CertType { + + /** 身份证 */ + ID_CARD("身份证", "身份证"), + + /** 护照 */ + PASSPORT("护照", "护照"), + + /** 港澳通行证 */ + HK_MACAU_PASS("港澳通行证", "港澳通行证"), + + /** 台湾通行证 */ + TAIWAN_PASS("台湾通行证", "台湾通行证"); + + private final String code; + private final String desc; + + /** + * 根据编码获取描述 + */ + public static String getDescByCode(String code) { + for (CertType type : values()) { + if (type.getCode().equals(code)) { + return type.getDesc(); + } + } + return null; + } +} diff --git a/ruoyi-dpc/src/main/java/com/ruoyi/dpc/enums/CorpNature.java b/ruoyi-dpc/src/main/java/com/ruoyi/dpc/enums/CorpNature.java new file mode 100644 index 0000000..cda0dd2 --- /dev/null +++ b/ruoyi-dpc/src/main/java/com/ruoyi/dpc/enums/CorpNature.java @@ -0,0 +1,53 @@ +package com.ruoyi.dpc.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 企业性质枚举 + * + * @author ruoyi + */ +@Getter +@AllArgsConstructor +public enum CorpNature { + + /** 国有企业 */ + STATE_OWNED("国有企业", "国有企业"), + + /** 民营企业 */ + PRIVATE("民营企业", "民营企业"), + + /** 外资企业 */ + FOREIGN("外资企业", "外资企业"), + + /** 合资企业 */ + JOINT_VENTURE("合资企业", "合资企业"), + + /** 港澳台企业 */ + HONG_KONG_MACAO_TAIWAN("港澳台企业", "港澳台企业"), + + /** 集体企业 */ + COLLECTIVE("集体企业", "集体企业"), + + /** 个体工商户 */ + INDIVIDUAL("个体工商户", "个体工商户"), + + /** 其他 */ + OTHER("其他", "其他"); + + private final String code; + private final String desc; + + /** + * 根据编码获取描述 + */ + public static String getDescByCode(String code) { + for (CorpNature nature : values()) { + if (nature.getCode().equals(code)) { + return nature.getDesc(); + } + } + return null; + } +} diff --git a/ruoyi-dpc/src/main/java/com/ruoyi/dpc/enums/CorpType.java b/ruoyi-dpc/src/main/java/com/ruoyi/dpc/enums/CorpType.java new file mode 100644 index 0000000..6777f9a --- /dev/null +++ b/ruoyi-dpc/src/main/java/com/ruoyi/dpc/enums/CorpType.java @@ -0,0 +1,56 @@ +package com.ruoyi.dpc.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 主体类型枚举 + * + * @author ruoyi + */ +@Getter +@AllArgsConstructor +public enum CorpType { + + /** 有限责任公司 */ + LIMITED_LIABILITY("有限责任公司", "有限责任公司"), + + /** 股份有限公司 */ + JOINT_STOCK("股份有限公司", "股份有限公司"), + + /** 个体工商户 */ + INDIVIDUAL("个体工商户", "个体工商户"), + + /** 合伙企业 */ + PARTNERSHIP("合伙企业", "合伙企业"), + + /** 个人独资企业 */ + SOLE_PROPRIETORSHIP("个人独资企业", "个人独资企业"), + + /** 国有企业 */ + STATE_OWNED("国有企业", "国有企业"), + + /** 集体企业 */ + COLLECTIVE("集体企业", "集体企业"), + + /** 外商投资企业 */ + FOREIGN_INVESTED("外商投资企业", "外商投资企业"), + + /** 港澳台投资企业 */ + HONG_KONG_MACAO_TAIWAN("港澳台投资企业", "港澳台投资企业"); + + private final String code; + private final String desc; + + /** + * 根据编码获取描述 + */ + public static String getDescByCode(String code) { + for (CorpType type : values()) { + if (type.getCode().equals(code)) { + return type.getDesc(); + } + } + return null; + } +} diff --git a/ruoyi-dpc/src/main/java/com/ruoyi/dpc/enums/IndivSubType.java b/ruoyi-dpc/src/main/java/com/ruoyi/dpc/enums/IndivSubType.java new file mode 100644 index 0000000..50d179c --- /dev/null +++ b/ruoyi-dpc/src/main/java/com/ruoyi/dpc/enums/IndivSubType.java @@ -0,0 +1,50 @@ +package com.ruoyi.dpc.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 人员子类型枚举 + * + * @author ruoyi + */ +@Getter +@AllArgsConstructor +public enum IndivSubType { + + /** 本人 */ + SELF("本人", "本人"), + + /** 配偶 */ + SPOUSE("配偶", "配偶"), + + /** 父亲 */ + FATHER("父亲", "父亲"), + + /** 母亲 */ + MOTHER("母亲", "母亲"), + + /** 兄弟 */ + BROTHER("兄弟", "兄弟"), + + /** 姐妹 */ + SISTER("姐妹", "姐妹"), + + /** 子女 */ + CHILD("子女", "子女"); + + private final String code; + private final String desc; + + /** + * 根据编码获取描述 + */ + public static String getDescByCode(String code) { + for (IndivSubType type : values()) { + if (type.getCode().equals(code)) { + return type.getDesc(); + } + } + return null; + } +} diff --git a/ruoyi-dpc/src/main/java/com/ruoyi/dpc/enums/IndivType.java b/ruoyi-dpc/src/main/java/com/ruoyi/dpc/enums/IndivType.java new file mode 100644 index 0000000..ea65017 --- /dev/null +++ b/ruoyi-dpc/src/main/java/com/ruoyi/dpc/enums/IndivType.java @@ -0,0 +1,44 @@ +package com.ruoyi.dpc.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 人员类型枚举 + * + * @author ruoyi + */ +@Getter +@AllArgsConstructor +public enum IndivType { + + /** 房产中介 */ + REAL_ESTATE_AGENT("房产中介", "房产中介"), + + /** 贷款中介 */ + LOAN_AGENT("贷款中介", "贷款中介"), + + /** 职业背债人 */ + PROFESSIONAL_DEBTOR("职业背债人", "职业背债人"), + + /** 担保中介 */ + GUARANTEE_AGENT("担保中介", "担保中介"), + + /** 评估中介 */ + EVALUATION_AGENT("评估中介", "评估中介"); + + private final String code; + private final String desc; + + /** + * 根据编码获取描述 + */ + public static String getDescByCode(String code) { + for (IndivType type : values()) { + if (type.getCode().equals(code)) { + return type.getDesc(); + } + } + return null; + } +} diff --git a/ruoyi-dpc/src/main/java/com/ruoyi/dpc/enums/RelationType.java b/ruoyi-dpc/src/main/java/com/ruoyi/dpc/enums/RelationType.java new file mode 100644 index 0000000..2ce79fd --- /dev/null +++ b/ruoyi-dpc/src/main/java/com/ruoyi/dpc/enums/RelationType.java @@ -0,0 +1,53 @@ +package com.ruoyi.dpc.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 关联关系枚举 + * + * @author ruoyi + */ +@Getter +@AllArgsConstructor +public enum RelationType { + + /** 配偶 */ + SPOUSE("配偶", "配偶"), + + /** 父子 */ + FATHER_SON("父子", "父子"), + + /** 母女 */ + MOTHER_DAUGHTER("母女", "母女"), + + /** 兄弟 */ + BROTHER("兄弟", "兄弟"), + + /** 姐妹 */ + SISTER("姐妹", "姐妹"), + + /** 亲属 */ + RELATIVE("亲属", "亲属"), + + /** 朋友 */ + FRIEND("朋友", "朋友"), + + /** 同事 */ + COLLEAGUE("同事", "同事"); + + private final String code; + private final String desc; + + /** + * 根据编码获取描述 + */ + public static String getDescByCode(String code) { + for (RelationType type : values()) { + if (type.getCode().equals(code)) { + return type.getDesc(); + } + } + return null; + } +} diff --git a/ruoyi-dpc/src/main/java/com/ruoyi/dpc/mapper/DpcIntermediaryBlacklistMapper.java b/ruoyi-dpc/src/main/java/com/ruoyi/dpc/mapper/DpcIntermediaryBlacklistMapper.java index f162f71..c286b62 100644 --- a/ruoyi-dpc/src/main/java/com/ruoyi/dpc/mapper/DpcIntermediaryBlacklistMapper.java +++ b/ruoyi-dpc/src/main/java/com/ruoyi/dpc/mapper/DpcIntermediaryBlacklistMapper.java @@ -2,6 +2,9 @@ package com.ruoyi.dpc.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.ruoyi.dpc.domain.DpcIntermediaryBlacklist; +import org.apache.ibatis.annotations.Param; + +import java.util.List; /** * 中介人员黑名单 数据层 @@ -10,4 +13,20 @@ import com.ruoyi.dpc.domain.DpcIntermediaryBlacklist; * @date 2026-01-27 */ public interface DpcIntermediaryBlacklistMapper extends BaseMapper { + + /** + * 批量插入中介黑名单数据 + * + * @param list 中介黑名单列表 + * @return 插入行数 + */ + int batchInsert(@Param("list") List list); + + /** + * 批量更新中介黑名单数据 + * + * @param list 中介黑名单列表 + * @return 更新行数 + */ + int batchUpdate(@Param("list") List list); } diff --git a/ruoyi-dpc/src/main/java/com/ruoyi/dpc/service/IDpcIntermediaryBlacklistService.java b/ruoyi-dpc/src/main/java/com/ruoyi/dpc/service/IDpcIntermediaryBlacklistService.java index 8b7639a..8db14c5 100644 --- a/ruoyi-dpc/src/main/java/com/ruoyi/dpc/service/IDpcIntermediaryBlacklistService.java +++ b/ruoyi-dpc/src/main/java/com/ruoyi/dpc/service/IDpcIntermediaryBlacklistService.java @@ -2,9 +2,7 @@ package com.ruoyi.dpc.service; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.dpc.domain.DpcIntermediaryBlacklist; -import com.ruoyi.dpc.domain.dto.DpcIntermediaryBlacklistAddDTO; -import com.ruoyi.dpc.domain.dto.DpcIntermediaryBlacklistEditDTO; -import com.ruoyi.dpc.domain.dto.DpcIntermediaryBlacklistQueryDTO; +import com.ruoyi.dpc.domain.dto.*; import com.ruoyi.dpc.domain.excel.DpcIntermediaryBlacklistExcel; import com.ruoyi.dpc.domain.excel.DpcIntermediaryEntityExcel; import com.ruoyi.dpc.domain.excel.DpcIntermediaryPersonExcel; @@ -54,21 +52,57 @@ public interface IDpcIntermediaryBlacklistService { DpcIntermediaryBlacklistVO selectIntermediaryById(Long intermediaryId); /** - * 新增中介黑名单 + * 新增中介黑名单(通用接口,不推荐使用) * * @param addDTO 新增DTO * @return 结果 + * @deprecated 请使用 insertPersonIntermediary 或 insertEntityIntermediary 代替 */ + @Deprecated int insertIntermediary(DpcIntermediaryBlacklistAddDTO addDTO); /** - * 修改中介黑名单 + * 新增个人中介黑名单 + * + * @param addDTO 个人中介新增DTO + * @return 结果 + */ + int insertPersonIntermediary(DpcIntermediaryPersonAddDTO addDTO); + + /** + * 新增机构中介黑名单 + * + * @param addDTO 机构中介新增DTO + * @return 结果 + */ + int insertEntityIntermediary(DpcIntermediaryEntityAddDTO addDTO); + + /** + * 修改中介黑名单(通用接口,不推荐使用) * * @param editDTO 编辑DTO * @return 结果 + * @deprecated 请使用 updatePersonIntermediary 或 updateEntityIntermediary 代替 */ + @Deprecated int updateIntermediary(DpcIntermediaryBlacklistEditDTO editDTO); + /** + * 修改个人中介黑名单 + * + * @param editDTO 个人中介编辑DTO + * @return 结果 + */ + int updatePersonIntermediary(DpcIntermediaryPersonEditDTO editDTO); + + /** + * 修改机构中介黑名单 + * + * @param editDTO 机构中介编辑DTO + * @return 结果 + */ + int updateEntityIntermediary(DpcIntermediaryEntityEditDTO editDTO); + /** * 批量删除中介黑名单 * diff --git a/ruoyi-dpc/src/main/java/com/ruoyi/dpc/service/impl/DpcIntermediaryBlacklistServiceImpl.java b/ruoyi-dpc/src/main/java/com/ruoyi/dpc/service/impl/DpcIntermediaryBlacklistServiceImpl.java index bee4d9f..98960de 100644 --- a/ruoyi-dpc/src/main/java/com/ruoyi/dpc/service/impl/DpcIntermediaryBlacklistServiceImpl.java +++ b/ruoyi-dpc/src/main/java/com/ruoyi/dpc/service/impl/DpcIntermediaryBlacklistServiceImpl.java @@ -4,9 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.dpc.domain.DpcIntermediaryBlacklist; -import com.ruoyi.dpc.domain.dto.DpcIntermediaryBlacklistAddDTO; -import com.ruoyi.dpc.domain.dto.DpcIntermediaryBlacklistEditDTO; -import com.ruoyi.dpc.domain.dto.DpcIntermediaryBlacklistQueryDTO; +import com.ruoyi.dpc.domain.dto.*; import com.ruoyi.dpc.domain.excel.DpcIntermediaryBlacklistExcel; import com.ruoyi.dpc.domain.excel.DpcIntermediaryEntityExcel; import com.ruoyi.dpc.domain.excel.DpcIntermediaryPersonExcel; @@ -24,7 +22,7 @@ import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; import java.text.SimpleDateFormat; -import java.util.List; +import java.util.*; import java.util.stream.Collectors; /** @@ -108,9 +106,50 @@ public class DpcIntermediaryBlacklistServiceImpl implements IDpcIntermediaryBlac * @return 结果 */ @Override + @Deprecated public int insertIntermediary(DpcIntermediaryBlacklistAddDTO addDTO) { DpcIntermediaryBlacklist intermediary = new DpcIntermediaryBlacklist(); BeanUtils.copyProperties(addDTO, intermediary); + // 手动新增时,数据来源设置为 MANUAL + intermediary.setDataSource("MANUAL"); + // 默认状态设置为正常 + intermediary.setStatus("0"); + return intermediaryMapper.insert(intermediary); + } + + /** + * 新增个人中介黑名单 + * + * @param addDTO 个人中介新增DTO + * @return 结果 + */ + @Override + public int insertPersonIntermediary(DpcIntermediaryPersonAddDTO addDTO) { + DpcIntermediaryBlacklist intermediary = new DpcIntermediaryBlacklist(); + BeanUtils.copyProperties(addDTO, intermediary); + // 设置中介类型为个人 + intermediary.setIntermediaryType("1"); + // 手动新增时,数据来源设置为 MANUAL + intermediary.setDataSource("MANUAL"); + return intermediaryMapper.insert(intermediary); + } + + /** + * 新增机构中介黑名单 + * + * @param addDTO 机构中介新增DTO + * @return 结果 + */ + @Override + public int insertEntityIntermediary(DpcIntermediaryEntityAddDTO addDTO) { + DpcIntermediaryBlacklist intermediary = new DpcIntermediaryBlacklist(); + BeanUtils.copyProperties(addDTO, intermediary); + // 设置中介类型为机构 + intermediary.setIntermediaryType("2"); + // 证件号使用统一社会信用代码 + intermediary.setCertificateNo(addDTO.getCorpCreditCode()); + // 手动新增时,数据来源设置为 MANUAL + intermediary.setDataSource("MANUAL"); return intermediaryMapper.insert(intermediary); } @@ -121,12 +160,85 @@ public class DpcIntermediaryBlacklistServiceImpl implements IDpcIntermediaryBlac * @return 结果 */ @Override + @Deprecated public int updateIntermediary(DpcIntermediaryBlacklistEditDTO editDTO) { DpcIntermediaryBlacklist intermediary = new DpcIntermediaryBlacklist(); BeanUtils.copyProperties(editDTO, intermediary); return intermediaryMapper.updateById(intermediary); } + /** + * 修改个人中介黑名单 + * + * @param editDTO 个人中介编辑DTO + * @return 结果 + */ + @Override + public int updatePersonIntermediary(DpcIntermediaryPersonEditDTO editDTO) { + DpcIntermediaryBlacklist intermediary = new DpcIntermediaryBlacklist(); + BeanUtils.copyProperties(editDTO, intermediary); + // 设置中介类型为个人 + intermediary.setIntermediaryType("1"); + // 清空机构专属字段 + clearEntityFields(intermediary); + return intermediaryMapper.updateById(intermediary); + } + + /** + * 修改机构中介黑名单 + * + * @param editDTO 机构中介编辑DTO + * @return 结果 + */ + @Override + public int updateEntityIntermediary(DpcIntermediaryEntityEditDTO editDTO) { + DpcIntermediaryBlacklist intermediary = new DpcIntermediaryBlacklist(); + BeanUtils.copyProperties(editDTO, intermediary); + // 设置中介类型为机构 + intermediary.setIntermediaryType("2"); + // 清空个人专属字段 + clearPersonFields(intermediary); + return intermediaryMapper.updateById(intermediary); + } + + /** + * 清空个人专属字段 + */ + private void clearPersonFields(DpcIntermediaryBlacklist 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(DpcIntermediaryBlacklist 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); + } + /** * 批量删除中介黑名单 * @@ -211,7 +323,7 @@ public class DpcIntermediaryBlacklistServiceImpl implements IDpcIntermediaryBlac } /** - * 导入个人中介数据 + * 导入个人中介数据(批量插入优化版) * * @param excelList Excel实体列表 * @param isUpdateSupport 是否更新支持 @@ -223,11 +335,40 @@ public class DpcIntermediaryBlacklistServiceImpl implements IDpcIntermediaryBlac return "至少需要一条数据"; } - int successNum = 0; - int failureNum = 0; - StringBuilder successMsg = new StringBuilder(); - StringBuilder failureMsg = new StringBuilder(); + // 批量处理:先验证所有数据 + List toInsertList = new ArrayList<>(); + List toUpdateList = new ArrayList<>(); + List errorMessages = new ArrayList<>(); + // 批量查询已存在的记录(用于唯一性校验或更新支持) + Set existingCertNos = new HashSet<>(); + Map certNoToIdMap = new HashMap<>(); + for (DpcIntermediaryPersonExcel excel : excelList) { + if (StringUtils.isNotEmpty(excel.getCertificateNo())) { + existingCertNos.add(excel.getCertificateNo()); + } + } + if (!existingCertNos.isEmpty()) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(DpcIntermediaryBlacklist::getIntermediaryType, "1") + .in(DpcIntermediaryBlacklist::getCertificateNo, existingCertNos) + .select(DpcIntermediaryBlacklist::getIntermediaryId, DpcIntermediaryBlacklist::getCertificateNo); + List existingList = intermediaryMapper.selectList(wrapper); + for (DpcIntermediaryBlacklist existing : existingList) { + certNoToIdMap.put(existing.getCertificateNo(), existing.getIntermediaryId()); + } + } + + // 如果不是更新模式,先进行唯一性校验 + if (!isUpdateSupport) { + for (DpcIntermediaryPersonExcel excel : excelList) { + if (StringUtils.isNotEmpty(excel.getCertificateNo()) && certNoToIdMap.containsKey(excel.getCertificateNo())) { + throw new RuntimeException("证件号 " + excel.getCertificateNo() + " 已存在,请勿重复导入"); + } + } + } + + // 处理每条数据 for (int i = 0; i < excelList.size(); i++) { DpcIntermediaryPersonExcel excel = excelList.get(i); try { @@ -238,16 +379,16 @@ public class DpcIntermediaryBlacklistServiceImpl implements IDpcIntermediaryBlac DpcIntermediaryBlacklist intermediary = new DpcIntermediaryBlacklist(); intermediary.setName(excel.getName()); intermediary.setCertificateNo(excel.getCertificateNo()); - intermediary.setIntermediaryType("1"); // 个人类型 - intermediary.setStatus("0"); // 默认正常 - intermediary.setDataSource("IMPORT"); // 批量导入 + 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(excel.getIndivCertType()); + intermediary.setIndivCertType(StringUtils.isNotEmpty(excel.getIndivCertType()) ? excel.getIndivCertType() : "身份证"); intermediary.setIndivPhone(excel.getIndivPhone()); intermediary.setIndivWechat(excel.getIndivWechat()); intermediary.setIndivAddress(excel.getIndivAddress()); @@ -256,47 +397,51 @@ public class DpcIntermediaryBlacklistServiceImpl implements IDpcIntermediaryBlac intermediary.setIndivRelatedId(excel.getIndivRelatedId()); intermediary.setIndivRelation(excel.getIndivRelation()); - // 设置默认证件类型 - if (StringUtils.isEmpty(intermediary.getIndivCertType())) { - intermediary.setIndivCertType("身份证"); + // 检查是否需要更新 + if (isUpdateSupport && StringUtils.isNotEmpty(excel.getCertificateNo()) && certNoToIdMap.containsKey(excel.getCertificateNo())) { + intermediary.setIntermediaryId(certNoToIdMap.get(excel.getCertificateNo())); + toUpdateList.add(intermediary); + } else { + toInsertList.add(intermediary); } - - // 检查是否已存在(通过证件号判断) - if (isUpdateSupport && StringUtils.isNotEmpty(excel.getCertificateNo())) { - LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); - wrapper.eq(DpcIntermediaryBlacklist::getCertificateNo, excel.getCertificateNo()) - .eq(DpcIntermediaryBlacklist::getIntermediaryType, "1"); - DpcIntermediaryBlacklist existing = intermediaryMapper.selectOne(wrapper); - if (existing != null) { - intermediary.setIntermediaryId(existing.getIntermediaryId()); - intermediaryMapper.updateById(intermediary); - successNum++; - successMsg.append("
").append(successNum).append("、").append(excel.getName()).append(" 更新成功"); - continue; - } - } - - intermediaryMapper.insert(intermediary); - successNum++; - successMsg.append("
").append(successNum).append("、").append(excel.getName()).append(" 导入成功"); } catch (Exception e) { - failureNum++; - failureMsg.append("
").append(failureNum).append("、第").append(i + 1).append("行导入失败:"); - failureMsg.append(e.getMessage()); + 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("
").append(error); + } + + // 返回结果 if (failureNum > 0) { failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:"); throw new RuntimeException(failureMsg.toString()); } else { - successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条"); - return successMsg.toString(); + return "恭喜您,数据已全部导入成功!共 " + successNum + " 条"; } } /** - * 导入机构中介数据 + * 导入机构中介数据(批量插入优化版) * * @param excelList Excel实体列表 * @param isUpdateSupport 是否更新支持 @@ -308,11 +453,42 @@ public class DpcIntermediaryBlacklistServiceImpl implements IDpcIntermediaryBlac return "至少需要一条数据"; } - int successNum = 0; - int failureNum = 0; - StringBuilder successMsg = new StringBuilder(); - StringBuilder failureMsg = new StringBuilder(); + // 批量处理:先验证所有数据 + List toInsertList = new ArrayList<>(); + List toUpdateList = new ArrayList<>(); + List errorMessages = new ArrayList<>(); + // 批量查询已存在的记录(用于唯一性校验或更新支持) + Set existingCreditCodes = new HashSet<>(); + Map creditCodeToIdMap = new HashMap<>(); + for (DpcIntermediaryEntityExcel excel : excelList) { + if (StringUtils.isNotEmpty(excel.getCorpCreditCode())) { + existingCreditCodes.add(excel.getCorpCreditCode()); + } + } + if (!existingCreditCodes.isEmpty()) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(DpcIntermediaryBlacklist::getIntermediaryType, "2") + .in(DpcIntermediaryBlacklist::getCorpCreditCode, existingCreditCodes) + .select(DpcIntermediaryBlacklist::getIntermediaryId, DpcIntermediaryBlacklist::getCorpCreditCode); + List existingList = intermediaryMapper.selectList(wrapper); + for (DpcIntermediaryBlacklist existing : existingList) { + creditCodeToIdMap.put(existing.getCorpCreditCode(), existing.getIntermediaryId()); + } + } + + // 如果不是更新模式,先进行唯一性校验 + if (!isUpdateSupport) { + for (DpcIntermediaryEntityExcel 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++) { DpcIntermediaryEntityExcel excel = excelList.get(i); try { @@ -322,9 +498,11 @@ public class DpcIntermediaryBlacklistServiceImpl implements IDpcIntermediaryBlac // 转换为实体 DpcIntermediaryBlacklist intermediary = new DpcIntermediaryBlacklist(); intermediary.setName(excel.getName()); - intermediary.setIntermediaryType("2"); // 机构类型 - intermediary.setStatus("0"); // 默认正常 - intermediary.setDataSource("IMPORT"); // 批量导入 + // 对于机构中介,使用统一社会信用代码作为证件号 + intermediary.setCertificateNo(excel.getCorpCreditCode()); + intermediary.setIntermediaryType("2"); + intermediary.setStatus("0"); + intermediary.setDataSource("IMPORT"); intermediary.setRemark(excel.getRemark()); // 机构专属字段 @@ -337,7 +515,6 @@ public class DpcIntermediaryBlacklistServiceImpl implements IDpcIntermediaryBlac // 解析成立日期 if (StringUtils.isNotEmpty(excel.getCorpEstablishDate())) { try { - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); intermediary.setCorpEstablishDate(sdf.parse(excel.getCorpEstablishDate())); } catch (Exception e) { // 忽略日期解析错误 @@ -354,37 +531,46 @@ public class DpcIntermediaryBlacklistServiceImpl implements IDpcIntermediaryBlac intermediary.setCorpShareholder4(excel.getCorpShareholder4()); intermediary.setCorpShareholder5(excel.getCorpShareholder5()); - // 检查是否已存在(通过统一社会信用代码判断) - if (isUpdateSupport && StringUtils.isNotEmpty(excel.getCorpCreditCode())) { - LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); - wrapper.eq(DpcIntermediaryBlacklist::getCorpCreditCode, excel.getCorpCreditCode()) - .eq(DpcIntermediaryBlacklist::getIntermediaryType, "2"); - DpcIntermediaryBlacklist existing = intermediaryMapper.selectOne(wrapper); - if (existing != null) { - intermediary.setIntermediaryId(existing.getIntermediaryId()); - intermediaryMapper.updateById(intermediary); - successNum++; - successMsg.append("
").append(successNum).append("、").append(excel.getName()).append(" 更新成功"); - continue; - } + // 检查是否需要更新 + if (isUpdateSupport && StringUtils.isNotEmpty(excel.getCorpCreditCode()) && creditCodeToIdMap.containsKey(excel.getCorpCreditCode())) { + intermediary.setIntermediaryId(creditCodeToIdMap.get(excel.getCorpCreditCode())); + toUpdateList.add(intermediary); + } else { + toInsertList.add(intermediary); } - - intermediaryMapper.insert(intermediary); - successNum++; - successMsg.append("
").append(successNum).append("、").append(excel.getName()).append(" 导入成功"); } catch (Exception e) { - failureNum++; - failureMsg.append("
").append(failureNum).append("、第").append(i + 1).append("行导入失败:"); - failureMsg.append(e.getMessage()); + 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("
").append(error); + } + + // 返回结果 if (failureNum > 0) { failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:"); throw new RuntimeException(failureMsg.toString()); } else { - successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条"); - return successMsg.toString(); + return "恭喜您,数据已全部导入成功!共 " + successNum + " 条"; } } @@ -407,6 +593,10 @@ public class DpcIntermediaryBlacklistServiceImpl implements IDpcIntermediaryBlac if (StringUtils.isEmpty(excel.getName())) { throw new RuntimeException("机构名称不能为空"); } + // 验证统一社会信用代码不能为空(因为会用作 certificate_no 字段) + if (StringUtils.isEmpty(excel.getCorpCreditCode())) { + throw new RuntimeException("统一社会信用代码不能为空"); + } } /** @@ -418,8 +608,33 @@ public class DpcIntermediaryBlacklistServiceImpl implements IDpcIntermediaryBlac } DpcIntermediaryPersonDetailVO vo = new DpcIntermediaryPersonDetailVO(); - BeanUtils.copyProperties(intermediary, vo); + // 复制基础字段 + 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())); @@ -437,8 +652,37 @@ public class DpcIntermediaryBlacklistServiceImpl implements IDpcIntermediaryBlac } DpcIntermediaryEntityDetailVO vo = new DpcIntermediaryEntityDetailVO(); - BeanUtils.copyProperties(intermediary, vo); + // 复制基础字段 + 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())); @@ -470,19 +714,12 @@ public class DpcIntermediaryBlacklistServiceImpl implements IDpcIntermediaryBlac if (StringUtils.isEmpty(addDTO.getIntermediaryType())) { throw new RuntimeException("中介类型不能为空"); } - if (StringUtils.isEmpty(addDTO.getStatus())) { - throw new RuntimeException("状态不能为空"); - } // 验证中介类型 if (!"1".equals(addDTO.getIntermediaryType()) && !"2".equals(addDTO.getIntermediaryType())) { throw new RuntimeException("中介类型只能填写'个人'或'机构'"); } - // 验证状态 - if (!"0".equals(addDTO.getStatus()) && !"1".equals(addDTO.getStatus())) { - throw new RuntimeException("状态只能填写'正常'或'停用'"); - } } /** diff --git a/ruoyi-dpc/src/main/resources/mapper/dpc/DpcIntermediaryBlacklistMapper.xml b/ruoyi-dpc/src/main/resources/mapper/dpc/DpcIntermediaryBlacklistMapper.xml new file mode 100644 index 0000000..36b5635 --- /dev/null +++ b/ruoyi-dpc/src/main/resources/mapper/dpc/DpcIntermediaryBlacklistMapper.xml @@ -0,0 +1,134 @@ + + + + + + + INSERT INTO dpc_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 + + ( + #{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} + ) + + + + + + + UPDATE dpc_intermediary_blacklist + + name = #{item.name}, + certificate_no = #{item.certificateNo}, + intermediary_type = #{item.intermediaryType}, + status = #{item.status}, + remark = #{item.remark}, + indiv_type = #{item.indivType}, + indiv_sub_type = #{item.indivSubType}, + indiv_gender = #{item.indivGender}, + indiv_cert_type = #{item.indivCertType}, + indiv_phone = #{item.indivPhone}, + indiv_wechat = #{item.indivWechat}, + indiv_address = #{item.indivAddress}, + indiv_company = #{item.indivCompany}, + indiv_position = #{item.indivPosition}, + indiv_related_id = #{item.indivRelatedId}, + indiv_relation = #{item.indivRelation}, + corp_credit_code = #{item.corpCreditCode}, + corp_type = #{item.corpType}, + corp_nature = #{item.corpNature}, + corp_industry_category = #{item.corpIndustryCategory}, + corp_industry = #{item.corpIndustry}, + corp_establish_date = #{item.corpEstablishDate}, + corp_address = #{item.corpAddress}, + corp_legal_rep = #{item.corpLegalRep}, + corp_legal_cert_type = #{item.corpLegalCertType}, + corp_legal_cert_no = #{item.corpLegalCertNo}, + corp_shareholder_1 = #{item.corpShareholder1}, + corp_shareholder_2 = #{item.corpShareholder2}, + corp_shareholder_3 = #{item.corpShareholder3}, + corp_shareholder_4 = #{item.corpShareholder4}, + corp_shareholder_5 = #{item.corpShareholder5}, + data_source = #{item.dataSource}, + certificate_no = #{item.certificateNo}, + update_by = #{item.updateBy}, + update_time = #{item.updateTime} + + WHERE intermediary_id = #{item.intermediaryId} + + + + diff --git a/ruoyi-ui/src/api/dpcEnum.js b/ruoyi-ui/src/api/dpcEnum.js new file mode 100644 index 0000000..fb7ee56 --- /dev/null +++ b/ruoyi-ui/src/api/dpcEnum.js @@ -0,0 +1,101 @@ +import request from '@/utils/request' + +/** + * 查询人员类型选项 + */ +export function getIndivTypeOptions() { + return request({ + url: '/dpc/enum/indivType', + method: 'get' + }) +} + +/** + * 查询人员子类型选项 + */ +export function getIndivSubTypeOptions() { + return request({ + url: '/dpc/enum/indivSubType', + method: 'get' + }) +} + +/** + * 查询性别选项 + */ +export function getGenderOptions() { + return request({ + url: '/dpc/enum/gender', + method: 'get' + }) +} + +/** + * 查询证件类型选项 + */ +export function getCertTypeOptions() { + return request({ + url: '/dpc/enum/certType', + method: 'get' + }) +} + +/** + * 查询关联关系选项 + */ +export function getRelationTypeOptions() { + return request({ + url: '/dpc/enum/relationType', + method: 'get' + }) +} + +/** + * 查询主体类型选项 + */ +export function getCorpTypeOptions() { + return request({ + url: '/dpc/enum/corpType', + method: 'get' + }) +} + +/** + * 查询企业性质选项 + */ +export function getCorpNatureOptions() { + return request({ + url: '/dpc/enum/corpNature', + method: 'get' + }) +} + +/** + * 查询中介类型选项 + */ +export function getIntermediaryTypeOptions() { + return request({ + url: '/dpc/enum/intermediaryType', + method: 'get' + }) +} + +/** + * 查询中介状态选项 + */ +export function getIntermediaryStatusOptions() { + return request({ + url: '/dpc/enum/intermediaryStatus', + method: 'get' + }) +} + +/** + * 查询数据来源选项 + */ +export function getDataSourceOptions() { + return request({ + url: '/dpc/enum/dataSource', + method: 'get' + }) +} diff --git a/ruoyi-ui/src/api/dpcIntermediary.js b/ruoyi-ui/src/api/dpcIntermediary.js index 30b3d89..8aa1eb2 100644 --- a/ruoyi-ui/src/api/dpcIntermediary.js +++ b/ruoyi-ui/src/api/dpcIntermediary.js @@ -26,6 +26,24 @@ export function addIntermediary(data) { }) } +// 新增个人中介黑名单 +export function addPersonIntermediary(data) { + return request({ + url: '/dpc/intermediary/person', + method: 'post', + data: data + }) +} + +// 新增机构中介黑名单 +export function addEntityIntermediary(data) { + return request({ + url: '/dpc/intermediary/entity', + method: 'post', + data: data + }) +} + // 修改中介黑名单 export function updateIntermediary(data) { return request({ @@ -35,6 +53,24 @@ export function updateIntermediary(data) { }) } +// 修改个人中介黑名单 +export function updatePersonIntermediary(data) { + return request({ + url: '/dpc/intermediary/person', + method: 'put', + data: data + }) +} + +// 修改机构中介黑名单 +export function updateEntityIntermediary(data) { + return request({ + url: '/dpc/intermediary/entity', + method: 'put', + data: data + }) +} + // 删除中介黑名单 export function delIntermediary(intermediaryIds) { return request({ @@ -43,16 +79,7 @@ export function delIntermediary(intermediaryIds) { }) } -// 导出中介黑名单 -export function exportIntermediary(query) { - return request({ - url: '/dpc/intermediary/export', - method: 'post', - params: query - }) -} - -// 下载导入模板 +// 下载导入模板(已废弃,保留以兼容旧代码) export function importTemplate() { return request({ url: '/dpc/intermediary/importTemplate', @@ -68,3 +95,37 @@ export function importData(data, updateSupport) { data: data }) } + +// 下载个人中介导入模板 +export function importPersonTemplate() { + return request({ + url: '/dpc/intermediary/importPersonTemplate', + method: 'post' + }) +} + +// 下载机构中介导入模板 +export function importEntityTemplate() { + return request({ + url: '/dpc/intermediary/importEntityTemplate', + method: 'post' + }) +} + +// 导入个人中介黑名单 +export function importPersonData(data, updateSupport) { + return request({ + url: '/dpc/intermediary/importPersonData?updateSupport=' + updateSupport, + method: 'post', + data: data + }) +} + +// 导入机构中介黑名单 +export function importEntityData(data, updateSupport) { + return request({ + url: '/dpc/intermediary/importEntityData?updateSupport=' + updateSupport, + method: 'post', + data: data + }) +} diff --git a/ruoyi-ui/src/views/dpcIntermediary/components/DataTable.vue b/ruoyi-ui/src/views/dpcIntermediary/components/DataTable.vue new file mode 100644 index 0000000..2f2d140 --- /dev/null +++ b/ruoyi-ui/src/views/dpcIntermediary/components/DataTable.vue @@ -0,0 +1,82 @@ + + + diff --git a/ruoyi-ui/src/views/dpcIntermediary/components/DetailDialog.vue b/ruoyi-ui/src/views/dpcIntermediary/components/DetailDialog.vue new file mode 100644 index 0000000..7726d70 --- /dev/null +++ b/ruoyi-ui/src/views/dpcIntermediary/components/DetailDialog.vue @@ -0,0 +1,79 @@ + + + diff --git a/ruoyi-ui/src/views/dpcIntermediary/components/EditDialog.vue b/ruoyi-ui/src/views/dpcIntermediary/components/EditDialog.vue new file mode 100644 index 0000000..34f7683 --- /dev/null +++ b/ruoyi-ui/src/views/dpcIntermediary/components/EditDialog.vue @@ -0,0 +1,639 @@ + + + + + diff --git a/ruoyi-ui/src/views/dpcIntermediary/components/ImportDialog.vue b/ruoyi-ui/src/views/dpcIntermediary/components/ImportDialog.vue new file mode 100644 index 0000000..6052d1d --- /dev/null +++ b/ruoyi-ui/src/views/dpcIntermediary/components/ImportDialog.vue @@ -0,0 +1,303 @@ + + + + + diff --git a/ruoyi-ui/src/views/dpcIntermediary/components/SearchForm.vue b/ruoyi-ui/src/views/dpcIntermediary/components/SearchForm.vue new file mode 100644 index 0000000..8a5c2f1 --- /dev/null +++ b/ruoyi-ui/src/views/dpcIntermediary/components/SearchForm.vue @@ -0,0 +1,65 @@ + + + diff --git a/ruoyi-ui/src/views/dpcIntermediary/index.vue b/ruoyi-ui/src/views/dpcIntermediary/index.vue index d4c722f..f713014 100644 --- a/ruoyi-ui/src/views/dpcIntermediary/index.vue +++ b/ruoyi-ui/src/views/dpcIntermediary/index.vue @@ -1,44 +1,13 @@