优化
This commit is contained in:
@@ -9,6 +9,8 @@ import java.util.Arrays;
|
||||
enum BusinessFileCategory {
|
||||
FLEET_DRIVER_LICENSE(false, FormatPolicy.PDF_IMAGE, Limits.STANDARD, BusinessIdPolicy.POSITIVE_LONG),
|
||||
FLEET_TRIP_OPERATION_EVIDENCE(false, FormatPolicy.PDF_IMAGE, Limits.STANDARD, BusinessIdPolicy.POSITIVE_LONG),
|
||||
OVERSEAS_DISPATCH_VEHICLE_EVIDENCE(false, FormatPolicy.PDF_IMAGE, Limits.STANDARD, BusinessIdPolicy.POSITIVE_LONG),
|
||||
OVERSEAS_DISPATCH_DRIVER_EVIDENCE(false, FormatPolicy.PDF_IMAGE, Limits.STANDARD, BusinessIdPolicy.POSITIVE_LONG),
|
||||
FLEET_VEHICLE_RECORD_PHOTO(false, FormatPolicy.IMAGE, Limits.STANDARD, BusinessIdPolicy.POSITIVE_LONG),
|
||||
DELIVERY_LOADING_PHOTO(true, FormatPolicy.ARBITRARY, Limits.CUSTOMS, BusinessIdPolicy.POSITIVE_LONG),
|
||||
DELIVERY_BOL(true, FormatPolicy.ARBITRARY, Limits.CUSTOMS, BusinessIdPolicy.POSITIVE_LONG),
|
||||
@@ -67,7 +69,12 @@ enum BusinessFileCategory {
|
||||
.orElseThrow(() -> new BizException(ResultCode.BAD_REQUEST, "不支持的附件业务类型"));
|
||||
}
|
||||
|
||||
/** 校验文件归属;跨客户排车证据固定为平台所有,不随货物客户变化。 */
|
||||
void validateOwner(long tenantId) {
|
||||
if ((this == OVERSEAS_DISPATCH_VEHICLE_EVIDENCE || this == OVERSEAS_DISPATCH_DRIVER_EVIDENCE)
|
||||
&& tenantId != 0) {
|
||||
throw new BizException(ResultCode.BAD_REQUEST, "排车车辆及司机证据必须归属平台");
|
||||
}
|
||||
if (this == FLEET_TRIP_OPERATION_EVIDENCE && tenantId != 0) {
|
||||
throw new BizException(ResultCode.BAD_REQUEST, "出车实测凭证必须归属平台");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: 平台排车车辆与司机证据内部文件契约
|
||||
version: 1.0.0
|
||||
description: >-
|
||||
复用 InternalBusinessFileController 的现有通用内部入口,不新增公开文件路由。
|
||||
两类证据均固定平台 tenantId=0,businessId 为排车内部正数 Long ID 的十进制表示,
|
||||
不使用车辆 ID、司机 ID、车牌或客户 ID。车辆与司机证据分别使用
|
||||
OVERSEAS_DISPATCH_VEHICLE_EVIDENCE、OVERSEAS_DISPATCH_DRIVER_EVIDENCE,不可互换。
|
||||
File 校验内部服务令牌、平台归属、正数业务 ID、文件非空、最大 10MiB(10485760 字节,包含边界)、
|
||||
PDF/JPG/PNG MIME 及对应内容签名。元数据和下载按 tenantId、businessType、businessId、fileId
|
||||
联合查询 ACTIVE 且未删除文件,错车或错类别均视为归属不匹配,下载前完成归属校验。
|
||||
上传生成不可变文件和真实元数据,不自动绑定证据或通过审核,不返回公开 URL 或存储路径。
|
||||
Lastleg 负责排车存在性、仓库与角色权限、当前及历史附件引用和审核状态;File 不查询 Lastleg 业务表。
|
||||
本文只描述排车网关实际消费的上传、元数据和内容三个操作,不改变通用文件接口的其他用途。
|
||||
统一异常处理使用 HTTP 200 JSON 业务错误,调用方必须检查 code;内容接口错误也返回 JSON,不能当作文件。
|
||||
security:
|
||||
- InternalServiceToken: []
|
||||
paths:
|
||||
/internal/file/v1/business-files/{tenantId}/{businessType}/{businessId}:
|
||||
parameters:
|
||||
- {$ref: '#/components/parameters/TenantId'}
|
||||
- {$ref: '#/components/parameters/BusinessType'}
|
||||
- {$ref: '#/components/parameters/BusinessId'}
|
||||
post:
|
||||
operationId: uploadDispatchEvidence
|
||||
summary: 上传本排车的车辆或司机证据
|
||||
parameters:
|
||||
- name: X-Operator-Id
|
||||
in: header
|
||||
required: true
|
||||
description: Lastleg 已认证操作者的正数 Long ID
|
||||
schema: {$ref: '#/components/schemas/PositiveLongString'}
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
multipart/form-data:
|
||||
schema:
|
||||
type: object
|
||||
required: [file]
|
||||
properties:
|
||||
file:
|
||||
type: string
|
||||
format: binary
|
||||
description: 非空且不超过10485760字节;application/pdf、image/jpeg或image/png,并校验对应内容签名
|
||||
responses:
|
||||
'200': {$ref: '#/components/responses/MetadataOrError'}
|
||||
/internal/file/v1/business-files/{tenantId}/{businessType}/{businessId}/{fileId}:
|
||||
parameters:
|
||||
- {$ref: '#/components/parameters/TenantId'}
|
||||
- {$ref: '#/components/parameters/BusinessType'}
|
||||
- {$ref: '#/components/parameters/BusinessId'}
|
||||
- {$ref: '#/components/parameters/FileId'}
|
||||
get:
|
||||
operationId: readDispatchEvidenceMetadata
|
||||
summary: 按本排车与证据类别联合校验并读取元数据
|
||||
responses:
|
||||
'200': {$ref: '#/components/responses/MetadataOrError'}
|
||||
/internal/file/v1/business-files/{tenantId}/{businessType}/{businessId}/{fileId}/content:
|
||||
parameters:
|
||||
- {$ref: '#/components/parameters/TenantId'}
|
||||
- {$ref: '#/components/parameters/BusinessType'}
|
||||
- {$ref: '#/components/parameters/BusinessId'}
|
||||
- {$ref: '#/components/parameters/FileId'}
|
||||
get:
|
||||
operationId: downloadDispatchEvidence
|
||||
summary: 按完整复合归属读取文件内容
|
||||
responses:
|
||||
'200':
|
||||
description: >-
|
||||
成功返回真实文件;错误返回 application/json 统一业务错误。
|
||||
A0400 表示作用域、ID或文件格式无效,A0403 表示内部令牌无效,
|
||||
A0404 表示文件不存在、非有效文件或复合归属不匹配。
|
||||
headers:
|
||||
Cache-Control: {schema: {type: string, enum: [no-store]}}
|
||||
Content-Disposition: {schema: {type: string}, description: 成功时为attachment及UTF-8文件名}
|
||||
Content-Length: {schema: {type: integer, format: int64}, description: 成功时为真实文件字节数}
|
||||
content:
|
||||
application/pdf: {schema: {type: string, format: binary}}
|
||||
image/jpeg: {schema: {type: string, format: binary}}
|
||||
image/png: {schema: {type: string, format: binary}}
|
||||
application/json: {schema: {$ref: '#/components/schemas/ErrorEnvelope'}}
|
||||
components:
|
||||
securitySchemes:
|
||||
InternalServiceToken: {type: apiKey, in: header, name: X-Internal-Service-Token}
|
||||
parameters:
|
||||
TenantId:
|
||||
name: tenantId
|
||||
in: path
|
||||
required: true
|
||||
description: 两类排车证据只属于平台,客户作用域一律拒绝
|
||||
schema: {type: string, enum: ['0']}
|
||||
BusinessType:
|
||||
name: businessType
|
||||
in: path
|
||||
required: true
|
||||
schema: {$ref: '#/components/schemas/DispatchEvidenceType'}
|
||||
BusinessId:
|
||||
name: businessId
|
||||
in: path
|
||||
required: true
|
||||
description: 排车内部正数Long ID,上限9223372036854775807;Lastleg以标准十进制字符串传入
|
||||
schema: {$ref: '#/components/schemas/PositiveLongString'}
|
||||
FileId:
|
||||
name: fileId
|
||||
in: path
|
||||
required: true
|
||||
schema: {$ref: '#/components/schemas/PositiveLongString'}
|
||||
responses:
|
||||
MetadataOrError:
|
||||
description: >-
|
||||
统一JSON响应,业务成功code为200。A0400为无效平台作用域、ID、操作者或文件;
|
||||
A0403为内部服务令牌无效;A0404为文件不存在、非ACTIVE、已删除或复合归属不匹配;
|
||||
S0503为存储不可用,S0500为元数据保存失败等内部异常。
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
oneOf:
|
||||
- {$ref: '#/components/schemas/MetadataEnvelope'}
|
||||
- {$ref: '#/components/schemas/ErrorEnvelope'}
|
||||
schemas:
|
||||
PositiveLongString:
|
||||
type: string
|
||||
pattern: '^[1-9][0-9]*$'
|
||||
maxLength: 19
|
||||
description: 正数Long的十进制字符串,值不得超过9223372036854775807
|
||||
DispatchEvidenceType:
|
||||
type: string
|
||||
enum: [OVERSEAS_DISPATCH_VEHICLE_EVIDENCE, OVERSEAS_DISPATCH_DRIVER_EVIDENCE]
|
||||
MetadataEnvelope:
|
||||
type: object
|
||||
required: [code, data]
|
||||
properties:
|
||||
code: {type: string, enum: ['200']}
|
||||
message: {type: string}
|
||||
data: {$ref: '#/components/schemas/Metadata'}
|
||||
requestId: {type: string, nullable: true}
|
||||
traceId: {type: string, nullable: true}
|
||||
timestamp: {type: string, format: date-time}
|
||||
Metadata:
|
||||
type: object
|
||||
required: [fileId, ownerScope, tenantId, businessType, businessId, fileName, sha256, contentType, sizeBytes, createdAt]
|
||||
properties:
|
||||
fileId: {$ref: '#/components/schemas/PositiveLongString'}
|
||||
ownerScope: {type: string, enum: [PLATFORM]}
|
||||
tenantId: {type: string, enum: ['0']}
|
||||
businessType: {$ref: '#/components/schemas/DispatchEvidenceType'}
|
||||
businessId: {$ref: '#/components/schemas/PositiveLongString'}
|
||||
fileName: {type: string, minLength: 1, description: 清理路径和控制字符后的原始文件名}
|
||||
sha256: {type: string, pattern: '^[0-9a-f]{64}$'}
|
||||
contentType: {type: string, enum: [application/pdf, image/jpeg, image/png]}
|
||||
sizeBytes:
|
||||
type: string
|
||||
pattern: '^[1-9][0-9]*$'
|
||||
description: 实际字节数,范围1到10485760;公共Jackson配置将Long输出为字符串
|
||||
example: '1024'
|
||||
createdAt: {type: string, description: File真实上传时间,LocalDateTime的ISO本地时间表示,无时区偏移}
|
||||
ErrorEnvelope:
|
||||
type: object
|
||||
required: [code, data]
|
||||
properties:
|
||||
code: {type: string, enum: [A0400, A0403, A0404, A0422, S0500, S0503]}
|
||||
message: {type: string}
|
||||
data: {type: object, nullable: true, description: 业务错误为null;参数校验错误可携带字段信息}
|
||||
requestId: {type: string, nullable: true}
|
||||
traceId: {type: string, nullable: true}
|
||||
timestamp: {type: string, format: date-time}
|
||||
Reference in New Issue
Block a user