flutter架 构项目基础

This commit is contained in:
崔宝新
2026-09-04 15:22:20 +08:00
parent 70967229d0
commit 0c5aee59c0
265 changed files with 35484 additions and 0 deletions
+168
View File
@@ -0,0 +1,168 @@
/// ============================================================
/// 【UserModel】用户相关模型
///
/// CurrentUserExtension:GET /api/v1/User/GetCurrentUserExtension 的响应体,
/// 对齐 Vue 端 api/user/type.ts 的 CurrentUserExtension 全部字段(17 个)。
///
/// 一、为什么字段全都要:
/// 登录后要缓存这套信息(user_storage.dart 里存 JSON),
/// "我的"页 / 任务页都可能用到,缺一个就得多调一次接口。
///
/// 二、高频坑:
/// 1. fromJson 全部 ?? 兜底,服务端缺字段/类型漂移不会闪崩;
/// 2. 数字统一 (json['x'] as num?)?.toInt(),防 int/double 不一致;
/// 3. toJson 与 fromJson 必须成对,否则缓存/回填会丢字段。
/// ============================================================
class CurrentUserExtension {
const CurrentUserExtension({
this.userId = 0,
this.userName = '',
this.userPoints = 0.0,
this.levelName = '',
this.avatar = '',
this.className = '',
this.classId = 0,
this.gradeLevel = '',
this.graduationYear = 0,
this.targetConfigId = 0,
this.targetConfigName = '',
this.userAvatarStatus = 0,
this.userAvatarReason = '',
this.isShowGuide = false,
this.isShowReport = false,
this.id = 0,
});
final int userId;
final String userName;
final double userPoints;
final String levelName;
final String avatar;
final String className;
final int classId;
final String gradeLevel;
final int graduationYear;
final int targetConfigId;
final String targetConfigName;
final int userAvatarStatus;
final String userAvatarReason;
final bool isShowGuide;
final bool isShowReport;
final int id;
/// JSON → 对象(服务器响应)
///
/// 两个兼容点(对齐接口真实返回 {code, message, data: {...}}):
/// 1. data 包装:data 存在就取 data,直接返回 {userId,...} 也支持;
/// 2. 字符串数字:后端 userId/classId 返回的是字符串
/// ("820466383020136"),不能直接 as num,用 _toInt 统一转换。
factory CurrentUserExtension.fromJson(Map<String, dynamic> json) {
final payload = (json['data'] as Map<String, dynamic>?) ?? json;
return CurrentUserExtension(
userId: _toInt(payload['userId']),
userName: payload['userName'] as String? ?? '',
userPoints: _toDouble(payload['userPoints']),
levelName: payload['levelName'] as String? ?? '',
avatar: payload['avatar'] as String? ?? '',
className: payload['className'] as String? ?? '',
classId: _toInt(payload['classId']),
gradeLevel: payload['gradeLevel'] as String? ?? '',
graduationYear: _toInt(payload['graduationYear']),
targetConfigId: _toInt(payload['targetConfigId']),
targetConfigName: payload['targetConfigName'] as String? ?? '',
userAvatarStatus: _toInt(payload['userAvatarStatus']),
userAvatarReason: payload['userAvatarReason'] as String? ?? '',
isShowGuide: payload['isShowGuide'] as bool? ?? false,
isShowReport: payload['isShowReport'] as bool? ?? false,
id: _toInt(payload['id']),
);
}
/// 对象 → JSON(写入本地缓存)
Map<String, dynamic> toJson() {
return {
'userId': userId,
'userName': userName,
'userPoints': userPoints,
'levelName': levelName,
'avatar': avatar,
'className': className,
'classId': classId,
'gradeLevel': gradeLevel,
'graduationYear': graduationYear,
'targetConfigId': targetConfigId,
'targetConfigName': targetConfigName,
'userAvatarStatus': userAvatarStatus,
'userAvatarReason': userAvatarReason,
'isShowGuide': isShowGuide,
'isShowReport': isShowReport,
'id': id,
};
}
/// 局部更新(目前只用得上 avatar:头像上传成功后替换 URL)
CurrentUserExtension copyWith({String? avatar}) {
return CurrentUserExtension(
userId: userId,
userName: userName,
userPoints: userPoints,
levelName: levelName,
avatar: avatar ?? this.avatar,
className: className,
classId: classId,
gradeLevel: gradeLevel,
graduationYear: graduationYear,
targetConfigId: targetConfigId,
targetConfigName: targetConfigName,
userAvatarStatus: userAvatarStatus,
userAvatarReason: userAvatarReason,
isShowGuide: isShowGuide,
isShowReport: isShowReport,
id: id,
);
}
}
/// 用户积分等级(GET /api/v1/User/GetUserPointLevel,备用)
class UserPointLevel {
const UserPointLevel({
this.userId = 0,
this.totalPoints = 0,
this.level = 0,
this.levelPoints = 0,
this.levelMaxPoints = 0,
this.levelUpPoints = 0,
});
final int userId;
final int totalPoints;
final int level;
final int levelPoints;
final int levelMaxPoints;
final int levelUpPoints;
factory UserPointLevel.fromJson(Map<String, dynamic> json) {
return UserPointLevel(
userId: (json['userId'] as num?)?.toInt() ?? 0,
totalPoints: (json['totalPoints'] as num?)?.toInt() ?? 0,
level: (json['level'] as num?)?.toInt() ?? 0,
levelPoints: (json['levelPoints'] as num?)?.toInt() ?? 0,
levelMaxPoints: (json['levelMaxPoints'] as num?)?.toInt() ?? 0,
levelUpPoints: (json['levelUpPoints'] as num?)?.toInt() ?? 0,
);
}
}
/// 兼容"字符串数字"(后端 userId/classId 返回 "820466383020136")
int _toInt(dynamic v) {
if (v is num) return v.toInt();
if (v is String) return int.tryParse(v) ?? 0;
return 0;
}
/// 兼容小数积分(后端 userPoints 返回 105.5)
double _toDouble(dynamic v) {
if (v is num) return v.toDouble();
if (v is String) return double.tryParse(v) ?? 0;
return 0;
}