This commit is contained in:
sjk
2025-11-17 13:39:05 +08:00
commit d4cfe2b9de
479 changed files with 109324 additions and 0 deletions

View File

@@ -0,0 +1,121 @@
/// API响应基础模型
class ApiResponse<T> {
final bool success;
final String message;
final T? data;
final int? code;
final Map<String, dynamic>? errors;
const ApiResponse({
required this.success,
required this.message,
this.data,
this.code,
this.errors,
});
factory ApiResponse.success({
required String message,
T? data,
int? code,
}) {
return ApiResponse<T>(
success: true,
message: message,
data: data,
code: code ?? 200,
);
}
factory ApiResponse.error({
required String message,
int? code,
Map<String, dynamic>? errors,
}) {
return ApiResponse<T>(
success: false,
message: message,
code: code ?? 400,
errors: errors,
);
}
factory ApiResponse.fromJson(
Map<String, dynamic> json,
T Function(dynamic)? fromJsonT,
) {
return ApiResponse<T>(
success: json['success'] ?? false,
message: json['message'] ?? '',
data: json['data'] != null && fromJsonT != null
? fromJsonT(json['data'])
: json['data'],
code: json['code'],
errors: json['errors'],
);
}
Map<String, dynamic> toJson() {
return {
'success': success,
'message': message,
'data': data,
'code': code,
'errors': errors,
};
}
@override
String toString() {
return 'ApiResponse{success: $success, message: $message, data: $data, code: $code}';
}
}
/// 分页响应模型
class PaginatedResponse<T> {
final List<T> data;
final int total;
final int page;
final int pageSize;
final int totalPages;
final bool hasNext;
final bool hasPrevious;
const PaginatedResponse({
required this.data,
required this.total,
required this.page,
required this.pageSize,
required this.totalPages,
required this.hasNext,
required this.hasPrevious,
});
factory PaginatedResponse.fromJson(
Map<String, dynamic> json,
T Function(Map<String, dynamic>) fromJsonT,
) {
final List<dynamic> dataList = json['data'] ?? [];
return PaginatedResponse<T>(
data: dataList.map((item) => fromJsonT(item)).toList(),
total: json['total'] ?? 0,
page: json['page'] ?? 1,
pageSize: json['page_size'] ?? 10,
totalPages: json['total_pages'] ?? 0,
hasNext: json['has_next'] ?? false,
hasPrevious: json['has_previous'] ?? false,
);
}
Map<String, dynamic> toJson() {
return {
'data': data,
'total': total,
'page': page,
'page_size': pageSize,
'total_pages': totalPages,
'has_next': hasNext,
'has_previous': hasPrevious,
};
}
}

View File

@@ -0,0 +1,280 @@
import 'package:json_annotation/json_annotation.dart';
part 'user_model.g.dart';
/// 用户模型
@JsonSerializable()
class User {
final String id;
final String username;
final String email;
final String? phone;
final String? avatar;
final DateTime createdAt;
final DateTime updatedAt;
final UserProfile? profile;
final UserSettings? settings;
const User({
required this.id,
required this.username,
required this.email,
this.phone,
this.avatar,
required this.createdAt,
required this.updatedAt,
this.profile,
this.settings,
});
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this);
User copyWith({
String? id,
String? username,
String? email,
String? phone,
String? avatar,
DateTime? createdAt,
DateTime? updatedAt,
UserProfile? profile,
UserSettings? settings,
}) {
return User(
id: id ?? this.id,
username: username ?? this.username,
email: email ?? this.email,
phone: phone ?? this.phone,
avatar: avatar ?? this.avatar,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
profile: profile ?? this.profile,
settings: settings ?? this.settings,
);
}
}
/// 用户资料
@JsonSerializable()
class UserProfile {
final String? firstName;
final String? lastName;
final String? phone;
final String? bio;
final String? avatar;
final String? realName;
final String? gender;
final DateTime? birthday;
final String? location;
final String? occupation;
final String? education;
final List<String>? interests;
final LearningGoal? learningGoal;
final EnglishLevel? currentLevel;
final EnglishLevel? targetLevel;
final EnglishLevel? englishLevel;
final UserSettings? settings;
const UserProfile({
this.firstName,
this.lastName,
this.phone,
this.bio,
this.avatar,
this.realName,
this.gender,
this.birthday,
this.location,
this.occupation,
this.education,
this.interests,
this.learningGoal,
this.currentLevel,
this.targetLevel,
this.englishLevel,
this.settings,
});
factory UserProfile.fromJson(Map<String, dynamic> json) => _$UserProfileFromJson(json);
Map<String, dynamic> toJson() => _$UserProfileToJson(this);
UserProfile copyWith({
String? firstName,
String? lastName,
String? phone,
String? bio,
String? avatar,
String? realName,
String? gender,
DateTime? birthday,
String? location,
String? occupation,
String? education,
List<String>? interests,
LearningGoal? learningGoal,
EnglishLevel? currentLevel,
EnglishLevel? targetLevel,
EnglishLevel? englishLevel,
UserSettings? settings,
}) {
return UserProfile(
firstName: firstName ?? this.firstName,
lastName: lastName ?? this.lastName,
phone: phone ?? this.phone,
bio: bio ?? this.bio,
avatar: avatar ?? this.avatar,
realName: realName ?? this.realName,
gender: gender ?? this.gender,
birthday: birthday ?? this.birthday,
location: location ?? this.location,
occupation: occupation ?? this.occupation,
education: education ?? this.education,
interests: interests ?? this.interests,
learningGoal: learningGoal ?? this.learningGoal,
currentLevel: currentLevel ?? this.currentLevel,
targetLevel: targetLevel ?? this.targetLevel,
englishLevel: englishLevel ?? this.englishLevel,
settings: settings ?? this.settings,
);
}
}
/// 用户设置
@JsonSerializable()
class UserSettings {
final bool notificationsEnabled;
final bool soundEnabled;
final bool vibrationEnabled;
final String language;
final String theme;
final int dailyGoal;
final int dailyWordGoal;
final int dailyStudyMinutes;
final List<String> reminderTimes;
final bool autoPlayAudio;
final double audioSpeed;
final bool showTranslation;
final bool showPronunciation;
const UserSettings({
this.notificationsEnabled = true,
this.soundEnabled = true,
this.vibrationEnabled = true,
this.language = 'zh-CN',
this.theme = 'system',
this.dailyGoal = 30,
this.dailyWordGoal = 20,
this.dailyStudyMinutes = 30,
this.reminderTimes = const ['09:00', '20:00'],
this.autoPlayAudio = true,
this.audioSpeed = 1.0,
this.showTranslation = true,
this.showPronunciation = true,
});
factory UserSettings.fromJson(Map<String, dynamic> json) => _$UserSettingsFromJson(json);
Map<String, dynamic> toJson() => _$UserSettingsToJson(this);
UserSettings copyWith({
bool? notificationsEnabled,
bool? soundEnabled,
bool? vibrationEnabled,
String? language,
String? theme,
int? dailyGoal,
int? dailyWordGoal,
int? dailyStudyMinutes,
List<String>? reminderTimes,
bool? autoPlayAudio,
double? audioSpeed,
bool? showTranslation,
bool? showPronunciation,
}) {
return UserSettings(
notificationsEnabled: notificationsEnabled ?? this.notificationsEnabled,
soundEnabled: soundEnabled ?? this.soundEnabled,
vibrationEnabled: vibrationEnabled ?? this.vibrationEnabled,
language: language ?? this.language,
theme: theme ?? this.theme,
dailyGoal: dailyGoal ?? this.dailyGoal,
dailyWordGoal: dailyWordGoal ?? this.dailyWordGoal,
dailyStudyMinutes: dailyStudyMinutes ?? this.dailyStudyMinutes,
reminderTimes: reminderTimes ?? this.reminderTimes,
autoPlayAudio: autoPlayAudio ?? this.autoPlayAudio,
audioSpeed: audioSpeed ?? this.audioSpeed,
showTranslation: showTranslation ?? this.showTranslation,
showPronunciation: showPronunciation ?? this.showPronunciation,
);
}
}
/// 学习目标
enum LearningGoal {
@JsonValue('daily_communication')
dailyCommunication,
@JsonValue('business_english')
businessEnglish,
@JsonValue('academic_study')
academicStudy,
@JsonValue('exam_preparation')
examPreparation,
@JsonValue('travel')
travel,
@JsonValue('hobby')
hobby,
}
/// 英语水平
enum EnglishLevel {
@JsonValue('beginner')
beginner,
@JsonValue('elementary')
elementary,
@JsonValue('intermediate')
intermediate,
@JsonValue('upper_intermediate')
upperIntermediate,
@JsonValue('advanced')
advanced,
@JsonValue('proficient')
proficient,
@JsonValue('expert')
expert,
}
/// 认证响应
@JsonSerializable()
class AuthResponse {
final User user;
final String token;
final String? refreshToken;
final DateTime expiresAt;
const AuthResponse({
required this.user,
required this.token,
this.refreshToken,
required this.expiresAt,
});
factory AuthResponse.fromJson(Map<String, dynamic> json) => _$AuthResponseFromJson(json);
Map<String, dynamic> toJson() => _$AuthResponseToJson(this);
}
/// Token刷新响应
@JsonSerializable()
class TokenRefreshResponse {
final String token;
final String? refreshToken;
final DateTime expiresAt;
const TokenRefreshResponse({
required this.token,
this.refreshToken,
required this.expiresAt,
});
factory TokenRefreshResponse.fromJson(Map<String, dynamic> json) => _$TokenRefreshResponseFromJson(json);
Map<String, dynamic> toJson() => _$TokenRefreshResponseToJson(this);
}

View File

@@ -0,0 +1,172 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'user_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
User _$UserFromJson(Map<String, dynamic> json) => User(
id: json['id'] as String,
username: json['username'] as String,
email: json['email'] as String,
phone: json['phone'] as String?,
avatar: json['avatar'] as String?,
createdAt: DateTime.parse(json['createdAt'] as String),
updatedAt: DateTime.parse(json['updatedAt'] as String),
profile: json['profile'] == null
? null
: UserProfile.fromJson(json['profile'] as Map<String, dynamic>),
settings: json['settings'] == null
? null
: UserSettings.fromJson(json['settings'] as Map<String, dynamic>),
);
Map<String, dynamic> _$UserToJson(User instance) => <String, dynamic>{
'id': instance.id,
'username': instance.username,
'email': instance.email,
'phone': instance.phone,
'avatar': instance.avatar,
'createdAt': instance.createdAt.toIso8601String(),
'updatedAt': instance.updatedAt.toIso8601String(),
'profile': instance.profile,
'settings': instance.settings,
};
UserProfile _$UserProfileFromJson(Map<String, dynamic> json) => UserProfile(
firstName: json['firstName'] as String?,
lastName: json['lastName'] as String?,
phone: json['phone'] as String?,
bio: json['bio'] as String?,
avatar: json['avatar'] as String?,
realName: json['realName'] as String?,
gender: json['gender'] as String?,
birthday: json['birthday'] == null
? null
: DateTime.parse(json['birthday'] as String),
location: json['location'] as String?,
occupation: json['occupation'] as String?,
education: json['education'] as String?,
interests: (json['interests'] as List<dynamic>?)
?.map((e) => e as String)
.toList(),
learningGoal:
$enumDecodeNullable(_$LearningGoalEnumMap, json['learningGoal']),
currentLevel:
$enumDecodeNullable(_$EnglishLevelEnumMap, json['currentLevel']),
targetLevel:
$enumDecodeNullable(_$EnglishLevelEnumMap, json['targetLevel']),
englishLevel:
$enumDecodeNullable(_$EnglishLevelEnumMap, json['englishLevel']),
settings: json['settings'] == null
? null
: UserSettings.fromJson(json['settings'] as Map<String, dynamic>),
);
Map<String, dynamic> _$UserProfileToJson(UserProfile instance) =>
<String, dynamic>{
'firstName': instance.firstName,
'lastName': instance.lastName,
'phone': instance.phone,
'bio': instance.bio,
'avatar': instance.avatar,
'realName': instance.realName,
'gender': instance.gender,
'birthday': instance.birthday?.toIso8601String(),
'location': instance.location,
'occupation': instance.occupation,
'education': instance.education,
'interests': instance.interests,
'learningGoal': _$LearningGoalEnumMap[instance.learningGoal],
'currentLevel': _$EnglishLevelEnumMap[instance.currentLevel],
'targetLevel': _$EnglishLevelEnumMap[instance.targetLevel],
'englishLevel': _$EnglishLevelEnumMap[instance.englishLevel],
'settings': instance.settings,
};
const _$LearningGoalEnumMap = {
LearningGoal.dailyCommunication: 'daily_communication',
LearningGoal.businessEnglish: 'business_english',
LearningGoal.academicStudy: 'academic_study',
LearningGoal.examPreparation: 'exam_preparation',
LearningGoal.travel: 'travel',
LearningGoal.hobby: 'hobby',
};
const _$EnglishLevelEnumMap = {
EnglishLevel.beginner: 'beginner',
EnglishLevel.elementary: 'elementary',
EnglishLevel.intermediate: 'intermediate',
EnglishLevel.upperIntermediate: 'upper_intermediate',
EnglishLevel.advanced: 'advanced',
EnglishLevel.proficient: 'proficient',
EnglishLevel.expert: 'expert',
};
UserSettings _$UserSettingsFromJson(Map<String, dynamic> json) => UserSettings(
notificationsEnabled: json['notificationsEnabled'] as bool? ?? true,
soundEnabled: json['soundEnabled'] as bool? ?? true,
vibrationEnabled: json['vibrationEnabled'] as bool? ?? true,
language: json['language'] as String? ?? 'zh-CN',
theme: json['theme'] as String? ?? 'system',
dailyGoal: (json['dailyGoal'] as num?)?.toInt() ?? 30,
dailyWordGoal: (json['dailyWordGoal'] as num?)?.toInt() ?? 20,
dailyStudyMinutes: (json['dailyStudyMinutes'] as num?)?.toInt() ?? 30,
reminderTimes: (json['reminderTimes'] as List<dynamic>?)
?.map((e) => e as String)
.toList() ??
const ['09:00', '20:00'],
autoPlayAudio: json['autoPlayAudio'] as bool? ?? true,
audioSpeed: (json['audioSpeed'] as num?)?.toDouble() ?? 1.0,
showTranslation: json['showTranslation'] as bool? ?? true,
showPronunciation: json['showPronunciation'] as bool? ?? true,
);
Map<String, dynamic> _$UserSettingsToJson(UserSettings instance) =>
<String, dynamic>{
'notificationsEnabled': instance.notificationsEnabled,
'soundEnabled': instance.soundEnabled,
'vibrationEnabled': instance.vibrationEnabled,
'language': instance.language,
'theme': instance.theme,
'dailyGoal': instance.dailyGoal,
'dailyWordGoal': instance.dailyWordGoal,
'dailyStudyMinutes': instance.dailyStudyMinutes,
'reminderTimes': instance.reminderTimes,
'autoPlayAudio': instance.autoPlayAudio,
'audioSpeed': instance.audioSpeed,
'showTranslation': instance.showTranslation,
'showPronunciation': instance.showPronunciation,
};
AuthResponse _$AuthResponseFromJson(Map<String, dynamic> json) => AuthResponse(
user: User.fromJson(json['user'] as Map<String, dynamic>),
token: json['token'] as String,
refreshToken: json['refreshToken'] as String?,
expiresAt: DateTime.parse(json['expiresAt'] as String),
);
Map<String, dynamic> _$AuthResponseToJson(AuthResponse instance) =>
<String, dynamic>{
'user': instance.user,
'token': instance.token,
'refreshToken': instance.refreshToken,
'expiresAt': instance.expiresAt.toIso8601String(),
};
TokenRefreshResponse _$TokenRefreshResponseFromJson(
Map<String, dynamic> json) =>
TokenRefreshResponse(
token: json['token'] as String,
refreshToken: json['refreshToken'] as String?,
expiresAt: DateTime.parse(json['expiresAt'] as String),
);
Map<String, dynamic> _$TokenRefreshResponseToJson(
TokenRefreshResponse instance) =>
<String, dynamic>{
'token': instance.token,
'refreshToken': instance.refreshToken,
'expiresAt': instance.expiresAt.toIso8601String(),
};