feat(lastleg): reuse fleet photos and support multiple loading images
This commit is contained in:
@@ -7,6 +7,8 @@ import java.util.Arrays;
|
||||
|
||||
/** File-owned storage policy. Business visibility and lifecycle remain in the calling service. */
|
||||
enum BusinessFileCategory {
|
||||
FLEET_VEHICLE_PHOTO(false, FormatPolicy.IMAGE, Limits.STANDARD, BusinessIdPolicy.POSITIVE_LONG),
|
||||
FLEET_DRIVER_PHOTO(false, FormatPolicy.IMAGE, Limits.STANDARD, BusinessIdPolicy.POSITIVE_LONG),
|
||||
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),
|
||||
@@ -90,7 +92,7 @@ enum BusinessFileCategory {
|
||||
if (this == FINANCE_VEHICLE_VOUCHER && tenantId != 0) {
|
||||
throw new BizException(ResultCode.BAD_REQUEST, "公司车辆付款凭证必须归属平台");
|
||||
}
|
||||
if (this == FLEET_VEHICLE_RECORD_PHOTO && tenantId != 0) {
|
||||
if ((this == FLEET_VEHICLE_RECORD_PHOTO || this == FLEET_VEHICLE_PHOTO || this == FLEET_DRIVER_PHOTO) && tenantId != 0) {
|
||||
throw new BizException(ResultCode.BAD_REQUEST, "车辆运维照片必须归属平台");
|
||||
}
|
||||
if (this == FLEET_DRIVER_LICENSE && tenantId != 0) {
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: 车辆与司机档案照片内部文件契约
|
||||
version: 1.0.0
|
||||
description: >-
|
||||
复用InternalBusinessFileController,固定平台tenantId=0、businessType=FLEET_VEHICLE_PHOTO或FLEET_DRIVER_PHOTO、
|
||||
businessId=对应车辆或司机内部ID。Lastleg负责档案存在性、列表/维护权限、版本关联和历史可见性;
|
||||
File校验内部服务令牌、平台复合归属、真实非空文件、MIME与签名。最大10MiB,仅JPG/PNG。
|
||||
上传只生成不可变对象,不改变驾驶证审核结论,不生成公开URL,排车保存时复制为本趟证据,后续档案替换不改历史排车。
|
||||
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:
|
||||
summary: 上传车辆或司机档案照片
|
||||
parameters:
|
||||
- {name: X-Operator-Id, in: header, required: true, schema: {type: string, pattern: '^[1-9][0-9]*$'}}
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
multipart/form-data:
|
||||
schema:
|
||||
type: object
|
||||
required: [file]
|
||||
properties:
|
||||
file: {type: string, format: binary}
|
||||
responses:
|
||||
'200': {$ref: '#/components/responses/Metadata'}
|
||||
'403': {description: 内部服务令牌无效}
|
||||
/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:
|
||||
summary: 校验归属并读取元数据
|
||||
responses:
|
||||
'200': {$ref: '#/components/responses/Metadata'}
|
||||
'403': {description: 内部服务令牌无效}
|
||||
/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:
|
||||
summary: 校验归属并下载真实文件
|
||||
responses:
|
||||
'200':
|
||||
description: 文件内容,业务错误按JSON code识别
|
||||
content:
|
||||
image/jpeg: {schema: {type: string, format: binary}}
|
||||
image/png: {schema: {type: string, format: binary}}
|
||||
'403': {description: 内部服务令牌无效}
|
||||
components:
|
||||
securitySchemes:
|
||||
InternalServiceToken: {type: apiKey, in: header, name: X-Internal-Service-Token}
|
||||
parameters:
|
||||
TenantId: {name: tenantId, in: path, required: true, schema: {type: string, enum: ['0']}}
|
||||
BusinessType: {name: businessType, in: path, required: true, schema: {type: string, enum: [FLEET_VEHICLE_PHOTO, FLEET_DRIVER_PHOTO]}}
|
||||
BusinessId: {name: businessId, in: path, required: true, schema: {type: string, pattern: '^[1-9][0-9]*$'}}
|
||||
FileId: {name: fileId, in: path, required: true, schema: {type: string, pattern: '^[1-9][0-9]*$'}}
|
||||
responses:
|
||||
Metadata:
|
||||
description: 统一响应;业务成功code为200,复合归属不匹配按业务错误返回
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
code: {type: string}
|
||||
message: {type: string, nullable: true}
|
||||
data:
|
||||
type: object
|
||||
properties:
|
||||
fileId: {type: string}
|
||||
tenantId: {type: string, enum: ['0']}
|
||||
businessType: {type: string, enum: [FLEET_VEHICLE_PHOTO, FLEET_DRIVER_PHOTO]}
|
||||
businessId: {type: string}
|
||||
fileName: {type: string}
|
||||
sha256: {type: string, pattern: '^[0-9a-f]{64}$'}
|
||||
contentType: {type: string, enum: [image/jpeg, image/png]}
|
||||
sizeBytes: {type: integer, format: int64, minimum: 1, maximum: 10485760}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.baiyue.file.service;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
class FleetResourcePhotoCategoryTest {
|
||||
@Test void profilePhotosOnlyAllowPlatformImagesAndPositiveResourceIdentities() {
|
||||
for(var category : new BusinessFileCategory[]{BusinessFileCategory.FLEET_VEHICLE_PHOTO,BusinessFileCategory.FLEET_DRIVER_PHOTO}) {
|
||||
category.validateOwner(0);
|
||||
assertThatThrownBy(() -> category.validateOwner(1)).hasMessageContaining("平台");
|
||||
assertThat(category.formatPolicy()).isEqualTo(BusinessFileCategory.FormatPolicy.IMAGE);
|
||||
assertThat(category.maxSizeBytes()).isEqualTo(10L*1024*1024);
|
||||
assertThatThrownBy(() -> category.storageBusinessId("not-a-resource")).isInstanceOf(RuntimeException.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user