This commit is contained in:
2026-09-20 14:26:03 +08:00
parent b9e0c8ea2f
commit b3162c6d69
4 changed files with 84 additions and 2 deletions
+1
View File
@@ -26,6 +26,7 @@
| 派送单三类资料 | `src/main/resources/openapi/delivery-files-v1.yaml`;依次为装车照片 `DELIVERY_LOADING_PHOTO`、BOL文件(含签名)`DELIVERY_BOL`、签收文件(POD签收/快递签收)`DELIVERY_RECEIPT`,按客户、派送内部ID、类别隔离,任意格式单文件50MiB;Lastleg持有分类绑定、保存、替换删除和历史可见性,按非空类别计数x/3,不强制必传或识别签名;File保留不可变对象与真实createdAt |
| 下游 OCR | `client/WeightOcrClient.java` |
| SQL/配置 | `src/main/resources/db/file.sql`、`application.yml` |
| 国内/海外 PDA 版本 | `controller/PdaReleaseController.java`、`service/PdaReleaseService.java`、`service/PdaPackageStorage.java`、`src/main/resources/openapi/pda-releases-v1.yaml`;平台上传草稿、发布和停发,匿名清单与包下载只暴露当前已发布/历史未停发文件;国内和海外 AppID、指针独立 |
| 测试/验证 | `src/test/java/com/baiyue/file/`;`mvn -pl file -am test` |
## 修改约束
@@ -42,7 +42,8 @@ public class PdaPackageStorage {
Files.createDirectories(target.getParent());
file.transferTo(target);
try (ZipFile zip = new ZipFile(target.toFile())) {
if (zip.size() == 0) throw new IOException("empty archive");
String required = type.equals("apk") ? "AndroidManifest.xml" : "manifest.json";
if (zip.getEntry(required) == null) throw new IOException("missing " + required);
}
return new Stored(key, Files.size(target), sha256(target));
} catch (IOException | IllegalStateException exception) {
@@ -0,0 +1,77 @@
openapi: 3.0.3
info:
title: PDA version releases
version: 1.0.0
description: Domestic and overseas PDA packages have independent AppIDs and publication pointers.
paths:
/api/platform/v1/files/pda-releases/{app}:
parameters:
- $ref: '#/components/parameters/app'
get:
summary: List recent releases for one PDA application
security: [{ bearerAuth: [] }]
description: Requires platform:pda-release:list and PLATFORM membership.
responses:
'200': { description: ApiResponse containing release records and current flags }
post:
summary: Upload a draft APK or WGT (does not publish)
security: [{ bearerAuth: [] }]
description: Requires platform:pda-release:manage and PLATFORM membership. Maximum 200 MiB.
requestBody:
required: true
content:
multipart/form-data:
schema:
type: object
required: [packageType, versionName, versionCode, minAppVersionCode, file]
properties:
packageType: { type: string, enum: [apk, wgt] }
versionName: { type: string, example: 0.0.4 }
versionCode: { type: integer, minimum: 1 }
minAppVersionCode: { type: integer, minimum: 1 }
mandatory: { type: boolean }
releaseNotes: { type: string, maxLength: 1000 }
file: { type: string, format: binary }
responses:
'200': { description: ApiResponse containing a DRAFT release }
/api/platform/v1/files/pda-releases/{id}/publish:
post:
summary: Publish a draft and switch the current package pointer
security: [{ bearerAuth: [] }]
description: Requires platform:pda-release:manage and PLATFORM membership.
parameters: [{ $ref: '#/components/parameters/id' }]
responses:
'200': { description: ApiResponse containing the published release }
/api/platform/v1/files/pda-releases/{id}/withdraw:
post:
summary: Stop serving an active release
security: [{ bearerAuth: [] }]
description: Requires platform:pda-release:manage and PLATFORM membership.
parameters: [{ $ref: '#/components/parameters/id' }]
responses:
'200': { description: ApiResponse containing the withdrawn release }
/api/pda-updates/{app}/latest:
get:
summary: Anonymous update manifest for one PDA application
parameters:
- $ref: '#/components/parameters/app'
- { name: appid, in: query, required: true, schema: { type: string } }
- { name: platform, in: query, required: true, schema: { type: string, enum: [android] } }
- { name: appVersionCode, in: query, required: true, schema: { type: integer, minimum: 1 } }
- { name: wgtVersion, in: query, required: true, schema: { type: string } }
responses:
'200':
description: Plain JSON with update=false or an APK/WGT manifest including appid and minAppVersionCode.
/api/pda-updates/{app}/{id}/package:
get:
summary: Download a published package
parameters: [{ $ref: '#/components/parameters/app' }, { $ref: '#/components/parameters/id' }]
responses:
'200': { description: APK or WGT binary }
'404': { description: Draft or withdrawn package is not available }
components:
securitySchemes:
bearerAuth: { type: http, scheme: bearer, bearerFormat: JWT }
parameters:
app: { name: app, in: path, required: true, schema: { type: string, enum: [domestic, overseas] } }
id: { name: id, in: path, required: true, schema: { type: string, format: uuid } }
+4 -1
View File
@@ -105,7 +105,10 @@ test('Controller prefixes route to their owning service; internal prefixes stay
? [overseas] : ['file', 'print'].includes(module) ? [domestic, overseas] : [domestic]
for (const file of javaFiles(resolve(root, module, 'src/main/java'))) {
for (const path of controllerPaths(readFileSync(file, 'utf8'), file)) {
for (const table of tables) verify(path, service, table, file)
// PDA release metadata lives in the domestic File control plane. Both
// PDA apps use the domestic Gateway for update checks and downloads.
const targetTables = path.startsWith('/api/pda-updates/') ? [domestic] : tables
for (const table of targetTables) verify(path, service, table, file)
count++
}
}