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、OVERSEAS_DISPATCH_DRIVER_PHOTO_EVIDENCE,不可互换。司机本人照片DRIVER_PHOTO和排车异常图片EXCEPTION仅支持JPG/PNG;其他两类沿PDF/JPG/PNG。 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, OVERSEAS_DISPATCH_DRIVER_PHOTO_EVIDENCE, OVERSEAS_DISPATCH_EXCEPTION_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}