feat(account): 接入个人中心接口模型
This commit is contained in:
1 parent
7d68699523
commit
44f6feb249
6 files changed
+501
No files matched your search
@@ -0,0 +1,40 @@
|
||||
// Author: fruit.com.cn
|
||||
|
||||
import 'json_numbers.dart';
|
||||
|
||||
/// 登录设备列表项;只保留页面展示需要的字段。
|
||||
class AccountDevice {
|
||||
const AccountDevice({
|
||||
required this.id,
|
||||
required this.deviceId,
|
||||
required this.platform,
|
||||
required this.deviceModel,
|
||||
required this.status,
|
||||
this.firstSeenAt,
|
||||
this.lastSeenAt,
|
||||
});
|
||||
|
||||
final String id;
|
||||
final String deviceId;
|
||||
final String platform;
|
||||
final String deviceModel;
|
||||
final String status;
|
||||
final DateTime? firstSeenAt;
|
||||
final DateTime? lastSeenAt;
|
||||
|
||||
/// 兼容 Long 字符串与数字;userId/deleted 不解析、不展示。
|
||||
factory AccountDevice.fromJson(Map<String, dynamic> json) {
|
||||
return AccountDevice(
|
||||
id: jsonToId(json['id']),
|
||||
deviceId: json['deviceId']?.toString() ?? '',
|
||||
platform: json['platform']?.toString() ?? '',
|
||||
deviceModel: json['deviceModel']?.toString() ?? '',
|
||||
status: json['status']?.toString() ?? '',
|
||||
firstSeenAt: _date(json['firstSeenAt']),
|
||||
lastSeenAt: _date(json['lastSeenAt']),
|
||||
);
|
||||
}
|
||||
|
||||
static DateTime? _date(dynamic value) =>
|
||||
DateTime.tryParse(value?.toString() ?? '');
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
// Author: fruit.com.cn
|
||||
|
||||
import 'dart:convert';
|
||||
|
||||
import 'account_device.dart';
|
||||
import 'account_profile.dart';
|
||||
|
||||
/// 导出中的登录凭据摘要。
|
||||
class AccountCredential {
|
||||
const AccountCredential({
|
||||
required this.type,
|
||||
required this.masked,
|
||||
required this.verified,
|
||||
});
|
||||
|
||||
final String type;
|
||||
final String masked;
|
||||
final bool verified;
|
||||
|
||||
factory AccountCredential.fromJson(Map<String, dynamic> json) {
|
||||
return AccountCredential(
|
||||
type: json['type']?.toString() ?? '',
|
||||
masked: json['masked']?.toString() ?? '',
|
||||
verified: json['verified'] == true,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 账号导出数据;`rawJson` 用于复制后端下发的完整内容。
|
||||
class AccountExport {
|
||||
const AccountExport({
|
||||
required this.profile,
|
||||
required this.credentials,
|
||||
required this.consentCount,
|
||||
required this.devices,
|
||||
required this.raw,
|
||||
});
|
||||
|
||||
final AccountProfile profile;
|
||||
final List<AccountCredential> credentials;
|
||||
final int consentCount;
|
||||
final List<AccountDevice> devices;
|
||||
final Map<String, dynamic> raw;
|
||||
|
||||
int get deviceCount => devices.length;
|
||||
String get rawJson => const JsonEncoder.withIndent(' ').convert(raw);
|
||||
|
||||
factory AccountExport.fromJson(Map<String, dynamic> json) {
|
||||
final profile = _map(json['profile']);
|
||||
final credentials = _list(json['credentials']);
|
||||
final consents = _list(json['consents']);
|
||||
final devices = _list(json['devices']);
|
||||
return AccountExport(
|
||||
profile: AccountProfile.fromJson(profile),
|
||||
credentials: [
|
||||
for (final item in credentials) AccountCredential.fromJson(item),
|
||||
],
|
||||
consentCount: consents.length,
|
||||
devices: [for (final item in devices) AccountDevice.fromJson(item)],
|
||||
raw: json,
|
||||
);
|
||||
}
|
||||
|
||||
static Map<String, dynamic> _map(dynamic value) =>
|
||||
value is Map ? value.cast<String, dynamic>() : const {};
|
||||
|
||||
static List<Map<String, dynamic>> _list(dynamic value) {
|
||||
if (value is! List) return const [];
|
||||
return [
|
||||
for (final item in value)
|
||||
if (item is Map) item.cast<String, dynamic>(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
// Author: fruit.com.cn
|
||||
|
||||
import 'auth_session.dart';
|
||||
import 'json_numbers.dart';
|
||||
|
||||
/// 当前账号资料;字段与 `GET/PUT /app/me` 的实际响应一致。
|
||||
class AccountProfile {
|
||||
const AccountProfile({
|
||||
required this.uid,
|
||||
required this.nickname,
|
||||
required this.avatarUrl,
|
||||
required this.gender,
|
||||
required this.countryCode,
|
||||
required this.regionCode,
|
||||
required this.language,
|
||||
required this.timezone,
|
||||
required this.currency,
|
||||
required this.status,
|
||||
required this.maskedTarget,
|
||||
required this.vipLevel,
|
||||
this.createdAt,
|
||||
this.lastLoginAt,
|
||||
this.vipExpireAt,
|
||||
});
|
||||
|
||||
final String uid;
|
||||
final String nickname;
|
||||
final String avatarUrl;
|
||||
final String gender;
|
||||
final String countryCode;
|
||||
final String regionCode;
|
||||
final String language;
|
||||
final String timezone;
|
||||
final String currency;
|
||||
final String status;
|
||||
final String maskedTarget;
|
||||
final int vipLevel;
|
||||
final DateTime? createdAt;
|
||||
final DateTime? lastLoginAt;
|
||||
final DateTime? vipExpireAt;
|
||||
|
||||
/// 解析资料响应;缺失字段按空值处理。
|
||||
factory AccountProfile.fromJson(Map<String, dynamic> json) {
|
||||
return AccountProfile(
|
||||
uid: jsonToId(json['uid']),
|
||||
nickname: json['nickname']?.toString() ?? '',
|
||||
avatarUrl: json['avatarUrl']?.toString() ?? '',
|
||||
gender: json['gender']?.toString() ?? '',
|
||||
countryCode: json['countryCode']?.toString() ?? '',
|
||||
regionCode: json['regionCode']?.toString() ?? '',
|
||||
language: json['language']?.toString() ?? '',
|
||||
timezone: json['timezone']?.toString() ?? '',
|
||||
currency: json['currency']?.toString() ?? '',
|
||||
status: json['status']?.toString() ?? '',
|
||||
maskedTarget: json['maskedTarget']?.toString() ?? '',
|
||||
vipLevel: jsonToInt(json['vipLevel']),
|
||||
createdAt: _date(json['createdAt']),
|
||||
lastLoginAt: _date(json['lastLoginAt']),
|
||||
vipExpireAt: _date(json['vipExpireAt']),
|
||||
);
|
||||
}
|
||||
|
||||
static DateTime? _date(dynamic value) =>
|
||||
DateTime.tryParse(value?.toString() ?? '');
|
||||
|
||||
/// 转为本地登录态摘要;只同步登录态实际使用的三项。
|
||||
AuthUser toAuthUser() =>
|
||||
AuthUser(uid: uid, nickname: nickname, avatarUrl: avatarUrl);
|
||||
}
|
||||
|
||||
/// 资料更新请求;null 字段不会进入请求体。
|
||||
class AccountProfileUpdate {
|
||||
const AccountProfileUpdate({
|
||||
this.nickname,
|
||||
this.avatarUrl,
|
||||
this.gender,
|
||||
this.birthday,
|
||||
this.language,
|
||||
this.timezone,
|
||||
this.regionCode,
|
||||
});
|
||||
|
||||
final String? nickname;
|
||||
final String? avatarUrl;
|
||||
final String? gender;
|
||||
final String? birthday;
|
||||
final String? language;
|
||||
final String? timezone;
|
||||
final String? regionCode;
|
||||
|
||||
/// 只发送本次有值的字段。
|
||||
Map<String, dynamic> toJson() => {
|
||||
if (nickname != null) 'nickname': nickname,
|
||||
if (avatarUrl != null) 'avatarUrl': avatarUrl,
|
||||
if (gender != null) 'gender': gender,
|
||||
if (birthday != null) 'birthday': birthday,
|
||||
if (language != null) 'language': language,
|
||||
if (timezone != null) 'timezone': timezone,
|
||||
if (regionCode != null) 'regionCode': regionCode,
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user