- pet_models.dart:pets 域 DTO 逐字段对齐冻结契约(宠物/品种/体重/ 疫苗目录/疫苗/健康事件/照护提醒/聚合摘要 + cursor 分页信封), 枚举严格解析,请求体部分更新语义(缺席字段不出现) - pets_repository.dart:PetsRepository 抽象 + ApiPetsRepository, 12 路径 18 操作全覆盖;四个 POST 携带 Idempotency-Key; 复用既有 ApiClient token 拦截与单飞刷新重放 - pet_exceptions.dart:新 8 错误码映射为类型化异常 (40300/40401/40402/40902/40903/40904/42201/42202), 仍可按 ApiBusinessException 基类捕获 - pets_controller.dart:宠物档案状态自 AppState 拆出 (Controller → Repository → API Client 分层,四态就绪供 T2-12) - money.dart:元/分换算工具(DTO 层保持整数分,UI 层 T2-14 使用) - api_client.dart:新增 patbondPetApiBaseUrl(:8083,--dart-define 可覆盖)与 query 参数支持;api_exception.dart 补 pets 域错误码 - 测试 64 → 126:DTO 映射、错误类型化映射、请求线路 (路径/方法/鉴权/分页/幂等键/tz)、控制器状态机、金额换算 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -17,6 +17,14 @@ const String patbondUserApiBaseUrl = String.fromEnvironment(
|
||||
defaultValue: 'http://127.0.0.1:8082',
|
||||
);
|
||||
|
||||
/// pet 服务基地址(/api/v1/pets、/api/v1/breeds、/api/v1/vaccine-catalog 等
|
||||
/// pets 域 12 路径):沿用 auth :8081 / user :8082 的分端口直连模式,
|
||||
/// `--dart-define=PATBOND_PET_API_BASE_URL=...` 注入。
|
||||
const String patbondPetApiBaseUrl = String.fromEnvironment(
|
||||
'PATBOND_PET_API_BASE_URL',
|
||||
defaultValue: 'http://127.0.0.1:8083',
|
||||
);
|
||||
|
||||
/// 构建全局共用的 Dio 实例。
|
||||
///
|
||||
/// `validateStatus` 放行所有状态码:错误信封由 [ApiClient] 统一解析成
|
||||
@@ -82,6 +90,7 @@ class ApiClient {
|
||||
String path, {
|
||||
String method = 'POST',
|
||||
Object? body,
|
||||
Map<String, Object?>? query,
|
||||
Map<String, Object?>? headers,
|
||||
bool requiresAuth = false,
|
||||
}) async {
|
||||
@@ -89,6 +98,7 @@ class ApiClient {
|
||||
path,
|
||||
method: method,
|
||||
body: body,
|
||||
query: query,
|
||||
headers: headers,
|
||||
requiresAuth: requiresAuth,
|
||||
);
|
||||
@@ -99,6 +109,7 @@ class ApiClient {
|
||||
path,
|
||||
method: method,
|
||||
body: body,
|
||||
query: query,
|
||||
headers: headers,
|
||||
requiresAuth: requiresAuth,
|
||||
);
|
||||
@@ -116,12 +127,14 @@ class ApiClient {
|
||||
required String method,
|
||||
required bool requiresAuth,
|
||||
Object? body,
|
||||
Map<String, Object?>? query,
|
||||
Map<String, Object?>? headers,
|
||||
}) async {
|
||||
try {
|
||||
return await _dio.request<Object?>(
|
||||
path,
|
||||
data: body,
|
||||
queryParameters: query,
|
||||
options: Options(
|
||||
method: method,
|
||||
headers: headers,
|
||||
|
||||
@@ -22,6 +22,32 @@ abstract final class ApiCodes {
|
||||
|
||||
/// 登录失败次数过多,账号临时锁定(HTTP 423,见 openapi.yaml)。
|
||||
static const loginLocked = 42300;
|
||||
|
||||
// ------ pets 域(契约 v1.2.0 冻结,M2 第二波定型 8 个)------
|
||||
|
||||
/// 对可见宠物无相应操作权限(viewer 写记录、caregiver/viewer 改档案)。
|
||||
static const petAccessDenied = 40300;
|
||||
|
||||
/// 宠物不存在 / 已软删 / 与调用者无关系(防枚举,三种情况响应一致)。
|
||||
static const petNotFound = 40401;
|
||||
|
||||
/// 记录不存在或记录所属宠物对调用者不可见(记录级防枚举)。
|
||||
static const recordNotFound = 40402;
|
||||
|
||||
/// 乐观锁版本冲突(提交的 version 已过期;提醒的条件更新守卫落空同码)。
|
||||
static const versionConflict = 40902;
|
||||
|
||||
/// 芯片号已被登记(跨用户唯一)。
|
||||
static const microchipTaken = 40903;
|
||||
|
||||
/// 同宠物同疫苗同系列同剂次的非 cancelled 疫苗记录已存在。
|
||||
static const vaccinationDoseExists = 40904;
|
||||
|
||||
/// 疫苗状态机 / 状态-日期规则违反(HTTP 422)。
|
||||
static const vaccinationRuleViolation = 42201;
|
||||
|
||||
/// 提醒状态机 / completed-completedAt 一致性违反(HTTP 422)。
|
||||
static const careReminderRuleViolation = 42202;
|
||||
}
|
||||
|
||||
/// API 调用的类型化异常。页面按类型映射为三层错误呈现
|
||||
@@ -43,7 +69,8 @@ final class ApiNetworkException extends ApiException {
|
||||
}
|
||||
|
||||
/// 业务错误:错误信封 code != 0(40000/40100/40900/40901 等)。
|
||||
final class ApiBusinessException extends ApiException {
|
||||
/// 领域层可按错误码细分子类型(见 features/pets/pet_exceptions.dart)。
|
||||
class ApiBusinessException extends ApiException {
|
||||
const ApiBusinessException({required this.code, required String message})
|
||||
: super(message);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user