Files
patbond-flutter/lib/core/network/api_exception.dart
T
lixi 8d890c0424 feat: 落地登录纵切——网络层、认证会话与登录/注册/Splash 三页(ADR-003/ADR-004)
- 新增 lib/core/network/:ApiClient(dio 封装,错误信封→类型化异常,base URL 经 --dart-define=PATBOND_API_BASE_URL 注入)、AuthInterceptor(Bearer + 设备标识)、TokenRefresher(单飞刷新,401/40101 重放一次,仅 40102/再 401 清会话)
- 新增 lib/features/auth/:SessionManager(token 只进 flutter_secure_storage)、AuthRepository(login/register/refresh/logout/me,注册带 Idempotency-Key)、Splash(500ms 最短停留/5s 超时/错误态重试+改用账号登录)、登录页与注册页(照 12 号组装稿,错误三层映射,预留区不渲染)
- App 根组件改为认证状态机驱动(Splash↔登录↔主壳 300ms fade);个人中心退出登录接入真实 logout
- 顺带修复:FIX-1 促销卡渐变改 [primaryStrong, primary]、FIX-2 补 helperStyle: muted、README dart format 命令补 --output=none
- 新增依赖:dio ^5.11.1、flutter_secure_storage ^11.0.0、uuid ^4.6.0
- 门禁:dart format(0 changed)/ flutter analyze(No issues)/ flutter test(30 passed,其中新增 23:TokenRefresher 5 + AuthRepository 10 + 登录页 4 + 注册页 4)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-04 11:52:51 +08:00

60 lines
2.0 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/// 服务端错误信封 `{code, message, data}` 的业务码常量(接口契约冻结稿)。
abstract final class ApiCodes {
static const ok = 0;
/// 参数错误。
static const paramError = 40000;
/// 用户名或密码错误。
static const badCredentials = 40100;
/// access token 无效或过期。
static const accessTokenInvalid = 40101;
/// refresh token 已失效。
static const refreshTokenInvalid = 40102;
/// 用户名重复。
static const usernameTaken = 40900;
/// 手机号重复。
static const phoneTaken = 40901;
}
/// API 调用的类型化异常。页面按类型映射为三层错误呈现
/// (字段级 / 表单横幅 / SnackBar,见 12 号组装稿 §4),
/// 服务端原始 message 一律不直接透出给用户。
sealed class ApiException implements Exception {
const ApiException(this.message);
/// 服务端返回的原始 message(仅用于日志排查,不上屏)。
final String message;
@override
String toString() => '$runtimeType: $message';
}
/// 系统错误:超时、断网、5xx、响应无法解析。归瞬态层(SnackBar + 重试)。
final class ApiNetworkException extends ApiException {
const ApiNetworkException([super.message = '网络或服务不可用']);
}
/// 业务错误:错误信封 code != 040000/40100/40900/40901 等)。
final class ApiBusinessException extends ApiException {
const ApiBusinessException({required this.code, required String message})
: super(message);
final int code;
}
/// 限流(HTTP 429):映射为横幅「尝试次数过多,请稍后再试」。
final class ApiRateLimitException extends ApiException {
const ApiRateLimitException([super.message = '请求过于频繁']);
}
/// 会话已失效:refresh token 失效(40102)或刷新重放后仍 401。
/// 抛出前本地会话已被清除,应用会自动回到登录页。
final class SessionExpiredException extends ApiException {
const SessionExpiredException([super.message = '会话已失效']);
}