This commit is contained in:
2026-09-11 16:17:16 +08:00
parent 2d928d667b
commit 51ce609ab1
57 changed files with 942 additions and 139 deletions
+1
View File
@@ -112,6 +112,7 @@ CREATE TABLE IF NOT EXISTS iam_tenant_qualification (
qualification_type VARCHAR(32) NOT NULL COMMENT '客户资质类型',
certificate_no VARCHAR(128) NULL COMMENT '证书编号',
document_url VARCHAR(500) NULL COMMENT '资质文件存储地址',
original_file_name VARCHAR(255) NOT NULL COMMENT '上传时原始文件名',
valid_from DATE NULL COMMENT '有效期开始日期',
valid_to DATE NULL COMMENT '有效期结束日期',
status VARCHAR(20) NOT NULL DEFAULT 'PENDING' COMMENT '资质审核状态:PENDING待审核、APPROVED已通过、REJECTED已驳回',
+154 -10
View File
@@ -95,7 +95,7 @@ paths:
- {name: page, in: query, required: false, schema: {type: integer, minimum: 1, default: 1}}
- {name: size, in: query, required: false, schema: {type: integer, minimum: 1, maximum: 200, default: 20}}
- {name: keyword, in: query, required: false, schema: {type: string}, description: 客户名称关键字,不支持客户编号、信用代码或联系人搜索}
- {name: status, in: query, required: false, schema: {type: string, enum: [PROFILE_REQUIRED, PENDING, ACTIVE, REJECTED, DISABLED, ARCHIVED]}}
- {name: status, in: query, required: false, schema: {type: string, enum: [PROFILE_REQUIRED, PENDING, ACTIVE, REJECTED, DISABLED]}}
responses:
'200':
description: 企业客户分页查询成功
@@ -248,6 +248,22 @@ paths:
schema: {$ref: '#/components/schemas/TenantQualificationListApiResponse'}
'403': {$ref: '#/components/responses/Forbidden'}
'404': {$ref: '#/components/responses/NotFound'}
/api/platform/v1/iam/tenants/{tenantId}/qualifications/{qualificationId}:
parameters:
- {$ref: '#/components/parameters/TenantId'}
- {name: qualificationId, in: path, required: true, schema: {type: integer, format: int64}}
get:
tags: [Platform Tenant / 平台租户]
summary: 查询企业客户资质详情
description: 需要 `platform:customer:list` 权限,并同时校验客户与资质归属。
responses:
'200':
description: 企业客户资质详情查询成功
content:
application/json:
schema: {$ref: '#/components/schemas/TenantQualificationApiResponse'}
'403': {$ref: '#/components/responses/Forbidden'}
'404': {$ref: '#/components/responses/NotFound'}
/api/platform/v1/iam/tenants/{tenantId}/status:
parameters:
- {$ref: '#/components/parameters/TenantId'}
@@ -677,8 +693,39 @@ paths:
tags: [IAM Resources / IAM 资源]
summary: List tenant qualifications / 查询企业资质
responses:
'200': {$ref: '#/components/responses/Success'}
'200':
description: 当前客户资质列表
content:
application/json:
schema: {$ref: '#/components/schemas/TenantQualificationListApiResponse'}
'403': {$ref: '#/components/responses/Forbidden'}
/api/merchant/v1/iam/tenant/qualifications/{qualificationId}:
parameters:
- {name: qualificationId, in: path, required: true, schema: {type: integer, format: int64}}
get:
tags: [IAM Resources / IAM 资源]
summary: 查询当前客户资质详情
description: 需要 `merchant:profile:view` 权限;客户范围来自 JWT,跨客户资质按不存在处理。
responses:
'200':
description: 当前客户资质详情
content:
application/json:
schema: {$ref: '#/components/schemas/TenantQualificationApiResponse'}
'403': {$ref: '#/components/responses/Forbidden'}
'404': {$ref: '#/components/responses/NotFound'}
delete:
tags: [IAM Resources / IAM 资源]
summary: 删除送审前企业资质
description: 需要 `merchant:qualification:upload` 权限;仅客户状态为 `PROFILE_REQUIRED` 或 `REJECTED` 时允许,`PENDING`、`ACTIVE` 等提交审核后的状态由服务端拒绝。客户范围来自 JWT;重复删除或跨客户 ID 返回相同幂等结果,不泄露归属。
responses:
'200':
description: 删除成功或目标已不存在
content:
application/json:
schema: {$ref: '#/components/schemas/QualificationDeletionApiResponse'}
'403': {$ref: '#/components/responses/Forbidden'}
'409': {$ref: '#/components/responses/Conflict'}
/api/merchant/v1/iam/tenant/qualifications/submit-review:
post:
tags: [IAM Resources / IAM 资源]
@@ -810,6 +857,69 @@ paths:
'400': {$ref: '#/components/responses/BadRequest'}
'403': {$ref: '#/components/responses/Forbidden'}
'409': {$ref: '#/components/responses/Conflict'}
/internal/iam/merchant-registrations/{authUserId}:
get:
tags: [IAM Resources / IAM 资源]
summary: 查询已创建的企业注册状态
description: 仅供 Auth Service 对相同账号、手机号和密码的注册重试进行幂等确认,不创建或修改企业资料。
security: []
parameters:
- {$ref: '#/components/parameters/InternalServiceToken'}
- {name: authUserId, in: path, required: true, schema: {type: integer, format: int64}}
responses:
'200':
description: 注册状态查询成功
content:
application/json:
schema:
allOf:
- {$ref: '#/components/schemas/ApiResponse'}
- type: object
properties:
data:
type: object
required: [tenantId, membershipId, tenantStatus, dimensionInitializationStatus]
properties:
tenantId: {type: integer, format: int64}
membershipId: {type: integer, format: int64}
tenantStatus: {type: string, enum: [PROFILE_REQUIRED, PENDING, ACTIVE, REJECTED, DISABLED, ARCHIVED]}
dimensionInitializationStatus: {type: string, enum: [PENDING, READY, FAILED]}
'403': {$ref: '#/components/responses/Forbidden'}
'404': {$ref: '#/components/responses/NotFound'}
/internal/iam/qualifications:
post:
tags: [IAM Resources / IAM 资源]
summary: 登记客户单个选填资质
description: 仅供 File Service 调用;原始文件名必须由上传请求传入,不得从存储 URL 推断。
security: []
parameters:
- {$ref: '#/components/parameters/InternalServiceToken'}
requestBody:
required: true
content:
application/json:
schema: {$ref: '#/components/schemas/QualificationSubmissionRequest'}
responses:
'200': {$ref: '#/components/responses/Success'}
'403': {$ref: '#/components/responses/Forbidden'}
'409': {$ref: '#/components/responses/Conflict'}
/internal/iam/platform-qualifications:
post:
tags: [IAM Resources / IAM 资源]
summary: 平台代客户登记单个选填资质
description: 仅供 File Service 调用;原始文件名必须由上传请求传入,不得从存储 URL 推断。
security: []
parameters:
- {$ref: '#/components/parameters/InternalServiceToken'}
requestBody:
required: true
content:
application/json:
schema: {$ref: '#/components/schemas/QualificationSubmissionRequest'}
responses:
'200': {$ref: '#/components/responses/Success'}
'403': {$ref: '#/components/responses/Forbidden'}
'409': {$ref: '#/components/responses/Conflict'}
/internal/iam/required-qualification-packages:
post:
tags: [IAM Resources / IAM 资源]
@@ -1204,7 +1314,7 @@ components:
status: {type: string, enum: [PROFILE_REQUIRED, PENDING, ACTIVE, REJECTED, DISABLED, ARCHIVED]}
dimensionInitializationStatus: {type: string, enum: [PENDING, READY, FAILED], description: 客户默认尺寸初始化状态;未 READY 时依赖该配置的业务失败关闭}
legalName: {type: string}
legalRepresentative: {type: string, maxLength: 64}
legalRepresentative: {type: string, maxLength: 64, nullable: true}
unifiedSocialCreditCode: {type: string}
contactName: {type: string}
contactPhone: {type: string}
@@ -1258,6 +1368,23 @@ components:
data:
type: array
items: {$ref: '#/components/schemas/TenantQualification'}
TenantQualificationApiResponse:
allOf:
- {$ref: '#/components/schemas/ApiResponse'}
- type: object
properties:
data: {$ref: '#/components/schemas/TenantQualification'}
QualificationDeletionApiResponse:
allOf:
- {$ref: '#/components/schemas/ApiResponse'}
- type: object
properties:
data:
type: object
required: [qualificationId]
properties:
qualificationId: {type: string, pattern: '^\d+$'}
deletedDocumentUrl: {type: string, nullable: true, description: 首次删除时返回,供 File Service 回收文件;重复删除为空}
TenantAddress:
type: object
properties:
@@ -1273,26 +1400,43 @@ components:
isDefault: {type: boolean}
TenantQualification:
type: object
required: [id, tenantId, qualificationType, documentUrl, originalFileName, status, createdAt, updatedAt]
properties:
id: {type: string, pattern: '^\d+$'}
tenantId: {type: string, pattern: '^\d+$'}
qualificationType: {type: string, enum: [BUSINESS_LICENSE, LEGAL_PERSON_ID, FREIGHT_FORWARDER_CERTIFICATE, BANK_ACCOUNT_LICENSE]}
certificateNo: {type: string}
documentUrl: {type: string}
originalFileName: {type: string, description: 上传时原始文件名;前端不得从 URL 或内部 ID 推断}
validFrom: {type: string, format: date}
validTo: {type: string, format: date, nullable: true}
status: {type: string, enum: [PENDING, APPROVED, REJECTED, SUPERSEDED]}
reviewComment: {type: string}
createdAt: {type: string, format: date-time}
updatedAt: {type: string, format: date-time}
QualificationSubmissionRequest:
type: object
required: [tenantId, qualificationType, documentUrl, originalFileName, replace]
properties:
tenantId: {type: string, pattern: '^\d+$'}
qualificationType: {type: string, enum: [LEGAL_PERSON_ID, FREIGHT_FORWARDER_CERTIFICATE, BANK_ACCOUNT_LICENSE]}
certificateNo: {type: string, nullable: true}
documentUrl: {type: string, minLength: 1}
originalFileName: {type: string, minLength: 1, maxLength: 255}
validTo: {type: string, format: date, nullable: true}
replace: {type: boolean}
RequiredQualificationPackageRequest:
type: object
required: [tenantId, unifiedSocialCreditCode, businessLicenseDocumentUrl, replaceBusinessLicense]
required: [tenantId, unifiedSocialCreditCode, businessLicenseDocumentUrl, businessLicenseOriginalFileName, replaceBusinessLicense]
properties:
tenantId: {type: string, pattern: '^\d+$'}
unifiedSocialCreditCode: {type: string, pattern: '^[0-9A-Za-z]{18}$'}
businessLicenseDocumentUrl: {type: string, minLength: 1}
businessLicenseOriginalFileName: {type: string, minLength: 1, maxLength: 255}
businessLicenseValidTo: {type: string, format: date, nullable: true}
replaceBusinessLicense: {type: boolean}
legalPersonIdDocumentUrl: {type: string, minLength: 1, nullable: true, description: 法人身份证选填}
legalPersonIdOriginalFileName: {type: string, maxLength: 255, nullable: true, description: 上传法人身份证时必传}
legalPersonIdValidTo: {type: string, format: date, nullable: true}
replaceLegalPersonId: {type: boolean, nullable: true, default: false}
RequiredQualificationPackageResponse:
@@ -1312,11 +1456,11 @@ components:
data: {$ref: '#/components/schemas/RequiredQualificationPackageResponse'}
RegisterRequest:
type: object
required: [tenantName, legalName, legalRepresentative, contactName, contactPhone, servicePackage]
required: [tenantName, legalName, contactName, contactPhone, servicePackage]
properties:
tenantName: {type: string, example: 深圳虫虫出海科技有限公司}
legalName: {type: string, example: 深圳虫虫出海科技有限公司}
legalRepresentative: {type: string, maxLength: 64, example: 张三}
legalRepresentative: {type: string, maxLength: 64, nullable: true, example: 张三, description: 选填}
contactName: {type: string, example: 李四}
contactPhone: {type: string, pattern: '^1[3-9]\d{9}$', example: '13800138000', description: 创建时同时初始化公司联系电话与首个管理员登录手机号;创建后二者独立维护}
contactEmail: {type: string, format: email, example: contact@example.com}
@@ -1332,21 +1476,21 @@ components:
internalRemark: {type: string, maxLength: 1000}
UpdateProfileRequest:
type: object
required: [tenantName, legalName, legalRepresentative, contactName, contactPhone]
required: [tenantName, legalName, contactName, contactPhone]
properties:
tenantName: {type: string}
legalName: {type: string}
legalRepresentative: {type: string, maxLength: 64}
legalRepresentative: {type: string, maxLength: 64, nullable: true, description: 选填}
contactName: {type: string}
contactPhone: {type: string, pattern: '^[0-9-]{4,32}$', description: 公司联系电话,不作为登录标识且不要求跨企业唯一}
contactEmail: {type: string, format: email}
UpdateTenantRequest:
type: object
required: [tenantName, legalName, legalRepresentative, contactName, contactPhone]
required: [tenantName, legalName, contactName, contactPhone]
properties:
tenantName: {type: string}
legalName: {type: string}
legalRepresentative: {type: string, maxLength: 64}
legalRepresentative: {type: string, maxLength: 64, nullable: true, description: 选填}
contactName: {type: string}
contactPhone: {type: string, pattern: '^[0-9-]{4,32}$', description: 公司联系电话,与管理员及成员登录手机号独立且不要求跨企业唯一}
contactEmail: {type: string, format: email}