feat(app): wire server dedup - force passthrough + PHOTO_DUPLICATE classification & l10n
Task 8: close the gap between server-side duplicate detection (90dcc58)
and the app.
- ApiClient.mapDioException: normalize 409 wire body reusing
VALIDATION_FAILED with message=PHOTO_DUPLICATE to
ErrorCodes.photoDuplicate (message-based; auto-compat if the contract
later adds a dedicated code)
- l10n zh/en errorPhotoDuplicate; error_l10n maps the code (queue page
inherits via fallback)
- UploadEngine._classifyFailure: PHOTO_DUPLICATE joins the no-auto-retry
bucket (retrying the same init body would 409 again); force to skip
dedup travels only through the enqueue path
- UploadTasks drift table +force column (schema v2, addColumn migration;
legacy rows default false); UploadTaskDraft/UploadTask/prepare carry it
- enqueueForUpload +forcePaths; duplicate dialog "全部上传" (capture page
+ album detail page) now returns DuplicateDialogChoice so confirmed
duplicates enqueue with force=true (server adjudicates owner/admin)
- engine init body carries force only when true (absent otherwise)
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -137,6 +137,18 @@ class ApiClient {
|
||||
final Object? message = data['message'];
|
||||
final Object? requestId = data['requestId'];
|
||||
if (code is String && message is String) {
|
||||
// P0-1 服务端查重拒绝(Task 8):409 的 wire code 复用
|
||||
// VALIDATION_FAILED,按 message=PHOTO_DUPLICATE 识别归一——所有
|
||||
// 调用方(上传引擎分类/l10n 文案)据此走查重分支;契约日后若设
|
||||
// 独立 code,此处识别与透传均兼容。
|
||||
if (status == 409 && message.contains(ErrorCodes.photoDuplicate)) {
|
||||
return AppException(
|
||||
code: ErrorCodes.photoDuplicate,
|
||||
message: message,
|
||||
requestId: requestId is String ? requestId : null,
|
||||
statusCode: status,
|
||||
);
|
||||
}
|
||||
return AppException(
|
||||
code: code,
|
||||
message: message,
|
||||
|
||||
@@ -68,6 +68,12 @@ abstract final class ErrorCodes {
|
||||
|
||||
// ── 以下为客户端本地伪码(契约外,见类注释) ──
|
||||
|
||||
/// 照片疑似重复(409,服务端查重拒绝)。P0-1 契约现状:wire 体 code
|
||||
/// 复用 VALIDATION_FAILED、靠 message=PHOTO_DUPLICATE 识别——ApiClient
|
||||
/// 归一为本码(若契约日后设独立 code,归一自动兼容)。skip 服务端查重
|
||||
/// 的 force 请求仅 owner/admin 生效(服务端裁决)。
|
||||
static const String photoDuplicate = 'PHOTO_DUPLICATE';
|
||||
|
||||
/// 网络连接失败(DNS/握手/断网等连接层错误)。
|
||||
static const String networkError = 'NETWORK_ERROR';
|
||||
|
||||
|
||||
@@ -26,6 +26,8 @@ extension AppLocalizationsErrorX on AppLocalizations {
|
||||
return errorAuthTokenExpired;
|
||||
case ErrorCodes.validationFailed:
|
||||
return errorValidation;
|
||||
case ErrorCodes.photoDuplicate: // P0-1 服务端查重拒绝(409 归一码)。
|
||||
return errorPhotoDuplicate;
|
||||
case ErrorCodes.networkError:
|
||||
return errorNetwork;
|
||||
case ErrorCodes.networkTimeout:
|
||||
|
||||
Reference in New Issue
Block a user