/// ============================================================ /// 【auth 模块模型】登录相关实体 —— 对照 Vue 项目 src/api/login.ts /// /// LoginRequest → 登录请求体(toJson 提交给服务器) /// LoginResponse → 登录响应(token + 用户信息) /// UserInfo → 用户信息子模型(info 字段) /// /// 高频坑: /// 1. fromJson 全部用 ?? 兜底,字段缺失/类型漂移不会闪崩; /// 2. 数字用 (json['x'] as num?)?.toInt() 防 int/double 不一致; /// 3. 兼容业务响应壳 {code, msg, data: {token, info}}。 /// ============================================================ library; class LoginRequest { const LoginRequest({required this.account, required this.password}); final String account; final String password; Map toJson() { return { 'account': account, 'password': password, }; } } class LoginResponse { const LoginResponse({required this.token, required this.info}); final String token; final UserInfo info; factory LoginResponse.fromJson(Map json) { // 兼容常见包装结构:后端可能直接返回 {token, info}, // 也可能包一层 {code, msg, data: {token, info}}(业务响应通用壳)。 // data 存在就取 data,否则直接用 json,两种都能解析到。 final payload = (json['data'] as Map?) ?? json; return LoginResponse( token: payload['token'] as String? ?? '', info: UserInfo.fromJson( (payload['info'] as Map?) ?? const {}, ), ); } } /// 用户信息(对齐 Vue 端 getUserInfo 的字段,未知的用 ?? 兜底) class UserInfo { const UserInfo({ this.userId = 0, this.userName = '', this.account = '', this.avatar = '', this.phone = '', this.isShowReport = false, this.isShowAfterReport = false, }); final int userId; final String userName; final String account; final String avatar; final String phone; final bool isShowReport; /// 登录响应里的出门测试报告标记(对齐 Vue api/login/type.ts 的 UserInfo) final bool isShowAfterReport; factory UserInfo.fromJson(Map json) { return UserInfo( // userId 可能是字符串(后端统一风格),不能直接 as num userId: _toInt(json['userId']), userName: json['userName'] as String? ?? '', account: json['account'] as String? ?? '', avatar: json['avatar'] as String? ?? '', phone: json['phone'] as String? ?? '', isShowReport: json['isShowReport'] as bool? ?? false, isShowAfterReport: json['isShowAfterReport'] as bool? ?? false, ); } } /// 兼容"字符串数字"(后端 userId 返回 "820466383020136") int _toInt(dynamic v) { if (v is num) return v.toInt(); if (v is String) return int.tryParse(v) ?? 0; return 0; }