90f318e246
Deploy Client / build-windows (push) Failing after 21s
Deploy Client / build-client-web (push) Successful in 42s
Deploy Client / build-macos (push) Successful in 2m8s
Deploy Client / build-android (push) Successful in 1m25s
Deploy Client / build-ios (push) Successful in 2m47s
Deploy Client / release-deploy-client (push) Has been skipped
设备/状态管理屏(查看本店在线设备/会话,管理员可强制下线)、登录携带设备信息、 会话心跳(/auth/ping)、被踢下线/会话失效提示、顶栏精简 + 用户名移至左侧栏底部。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
84 lines
2.3 KiB
Dart
84 lines
2.3 KiB
Dart
/// 在线会话/设备(对应后端 service.SessionView)。
|
|
class DeviceSession {
|
|
final int id;
|
|
final int userId;
|
|
final String username;
|
|
final String realName;
|
|
final String platform;
|
|
final String platformClass;
|
|
final String deviceName;
|
|
final String ip;
|
|
final DateTime? createdAt;
|
|
final DateTime? lastSeenAt;
|
|
final bool online;
|
|
final bool isCurrent;
|
|
|
|
const DeviceSession({
|
|
required this.id,
|
|
required this.userId,
|
|
required this.username,
|
|
required this.realName,
|
|
required this.platform,
|
|
required this.platformClass,
|
|
required this.deviceName,
|
|
required this.ip,
|
|
required this.createdAt,
|
|
required this.lastSeenAt,
|
|
required this.online,
|
|
required this.isCurrent,
|
|
});
|
|
|
|
factory DeviceSession.fromJson(Map<String, dynamic> json) {
|
|
DateTime? parse(String? s) =>
|
|
(s == null || s.isEmpty) ? null : DateTime.tryParse(s)?.toLocal();
|
|
return DeviceSession(
|
|
id: (json['id'] as num).toInt(),
|
|
userId: (json['user_id'] as num?)?.toInt() ?? 0,
|
|
username: json['username'] as String? ?? '',
|
|
realName: json['real_name'] as String? ?? '',
|
|
platform: json['platform'] as String? ?? '',
|
|
platformClass: json['platform_class'] as String? ?? '',
|
|
deviceName: json['device_name'] as String? ?? '',
|
|
ip: json['ip'] as String? ?? '',
|
|
createdAt: parse(json['created_at'] as String?),
|
|
lastSeenAt: parse(json['last_seen_at'] as String?),
|
|
online: json['online'] as bool? ?? false,
|
|
isCurrent: json['is_current'] as bool? ?? false,
|
|
);
|
|
}
|
|
|
|
/// 平台中文显示名。
|
|
String get platformLabel {
|
|
switch (platform) {
|
|
case 'windows':
|
|
return 'Windows';
|
|
case 'macos':
|
|
return 'macOS';
|
|
case 'linux':
|
|
return 'Linux';
|
|
case 'android':
|
|
return 'Android';
|
|
case 'ios':
|
|
return 'iOS';
|
|
case 'web':
|
|
return '网页版';
|
|
default:
|
|
return platform.isEmpty ? '未知' : platform;
|
|
}
|
|
}
|
|
|
|
/// 平台类中文显示名。
|
|
String get platformClassLabel {
|
|
switch (platformClass) {
|
|
case 'desktop':
|
|
return '桌面端';
|
|
case 'mobile':
|
|
return '移动端';
|
|
case 'web':
|
|
return '网页端';
|
|
default:
|
|
return platformClass;
|
|
}
|
|
}
|
|
}
|