@@ -0,0 +1,313 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:kaer_with_panels/app/widgets/kr_app_text_style.dart';
|
||||
|
||||
import '../controllers/kr_device_management_controller.dart';
|
||||
|
||||
class KRDeviceManagementView extends GetView<KRDeviceManagementController> {
|
||||
const KRDeviceManagementView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
extendBodyBehindAppBar: true,
|
||||
backgroundColor: Theme.of(context).primaryColor,
|
||||
body: Container(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [
|
||||
Color.fromRGBO(23, 151, 255, 0.15),
|
||||
Color.fromRGBO(23, 151, 255, 0.05),
|
||||
],
|
||||
stops: [0.0, 0.28],
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
// 顶部导航栏
|
||||
AppBar(
|
||||
backgroundColor: Colors.transparent,
|
||||
elevation: 0,
|
||||
leading: IconButton(
|
||||
icon: Icon(
|
||||
Icons.arrow_back_ios,
|
||||
color: Theme.of(context).iconTheme.color,
|
||||
size: 20.w,
|
||||
),
|
||||
onPressed: () => Get.back(),
|
||||
),
|
||||
title: Text(
|
||||
'设备管理',
|
||||
style: KrAppTextStyle(
|
||||
color: Theme.of(context).textTheme.bodyMedium?.color,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
// 内容区域
|
||||
Expanded(
|
||||
child: Obx(() {
|
||||
if (controller.isLoading.value) {
|
||||
return Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}
|
||||
|
||||
if (controller.devices.isEmpty) {
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.devices_other,
|
||||
size: 64.w,
|
||||
color: Theme.of(context).textTheme.bodySmall?.color,
|
||||
),
|
||||
SizedBox(height: 16.w),
|
||||
Text(
|
||||
'暂无登录设备',
|
||||
style: KrAppTextStyle(
|
||||
fontSize: 14,
|
||||
color: Theme.of(context).textTheme.bodySmall?.color,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return RefreshIndicator(
|
||||
onRefresh: () => controller.loadDeviceList(),
|
||||
child: ListView.builder(
|
||||
padding: EdgeInsets.all(16.w),
|
||||
itemCount: controller.devices.length,
|
||||
itemBuilder: (context, index) {
|
||||
return _buildDeviceItem(
|
||||
context,
|
||||
controller.devices[index],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 构建设备项
|
||||
Widget _buildDeviceItem(
|
||||
BuildContext context, Map<String, dynamic> device) {
|
||||
final id = device['id'] ?? '';
|
||||
final identifier = device['identifier'] ?? '';
|
||||
final userAgent = device['device_name'] ?? '未知设备';
|
||||
final isCurrent = device['is_current'] ?? false;
|
||||
final ip = device['ip'] ?? '';
|
||||
final lastLoginRaw = device['last_login'];
|
||||
final String lastLogin = lastLoginRaw?.toString() ?? '';
|
||||
|
||||
// 获取设备类型信息
|
||||
final deviceInfo = controller.getDeviceTypeInfo(userAgent);
|
||||
final deviceType = deviceInfo['type'] as String;
|
||||
final iconName = deviceInfo['icon'] as String;
|
||||
|
||||
return Container(
|
||||
margin: EdgeInsets.only(bottom: 12.w),
|
||||
padding: EdgeInsets.all(16.w),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).cardColor,
|
||||
borderRadius: BorderRadius.circular(12.w),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.03),
|
||||
blurRadius: 10.w,
|
||||
offset: Offset(0, 2.w),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// 设备类型和操作按钮
|
||||
Row(
|
||||
children: [
|
||||
// 设备图标
|
||||
Container(
|
||||
width: 48.w,
|
||||
height: 48.w,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF1797FF).withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(8.w),
|
||||
),
|
||||
child: Icon(
|
||||
_getIconData(iconName),
|
||||
color: const Color(0xFF1797FF),
|
||||
size: 24.w,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 12.w),
|
||||
// 设备信息
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
deviceType,
|
||||
style: KrAppTextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).textTheme.bodyMedium?.color,
|
||||
),
|
||||
),
|
||||
if (isCurrent) ...[
|
||||
SizedBox(width: 8.w),
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 8.w,
|
||||
vertical: 2.w,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.green.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(4.w),
|
||||
),
|
||||
child: Text(
|
||||
'本机',
|
||||
style: KrAppTextStyle(
|
||||
fontSize: 10,
|
||||
color: Colors.green,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
SizedBox(height: 4.w),
|
||||
Text(
|
||||
'ID: ${identifier.substring(0, identifier.length > 12 ? 12 : identifier.length)}...',
|
||||
style: KrAppTextStyle(
|
||||
fontSize: 12,
|
||||
color: Theme.of(context).textTheme.bodySmall?.color,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// 删除按钮
|
||||
TextButton(
|
||||
onPressed: () => controller.deleteDevice(id),
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: Theme.of(context).colorScheme.error,
|
||||
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 8.w),
|
||||
),
|
||||
child: Text(
|
||||
'删除',
|
||||
style: KrAppTextStyle(
|
||||
fontSize: 14,
|
||||
color: Theme.of(context).colorScheme.error,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
// 分隔线
|
||||
if (ip.isNotEmpty || lastLogin.isNotEmpty) ...[
|
||||
SizedBox(height: 12.w),
|
||||
Divider(height: 1, color: Theme.of(context).dividerColor),
|
||||
SizedBox(height: 12.w),
|
||||
],
|
||||
// 详细信息
|
||||
if (ip.isNotEmpty)
|
||||
_buildInfoRow(
|
||||
context,
|
||||
'IP地址',
|
||||
ip,
|
||||
),
|
||||
if (ip.isNotEmpty && lastLogin.isNotEmpty) SizedBox(height: 8.w),
|
||||
if (lastLogin.isNotEmpty)
|
||||
_buildInfoRow(
|
||||
context,
|
||||
'最后登录',
|
||||
_formatDateTime(lastLoginRaw),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 构建信息行
|
||||
Widget _buildInfoRow(BuildContext context, String label, String value) {
|
||||
return Row(
|
||||
children: [
|
||||
Text(
|
||||
'$label: ',
|
||||
style: KrAppTextStyle(
|
||||
fontSize: 12,
|
||||
color: Theme.of(context).textTheme.bodySmall?.color,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
value,
|
||||
style: KrAppTextStyle(
|
||||
fontSize: 12,
|
||||
color: Theme.of(context).textTheme.bodyMedium?.color,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/// 格式化时间
|
||||
String _formatDateTime(dynamic timestamp) {
|
||||
if (timestamp == null) return '未知';
|
||||
|
||||
try {
|
||||
DateTime dateTime;
|
||||
if (timestamp is int) {
|
||||
// 判断是秒级时间戳(10位)还是毫秒级时间戳(13位)
|
||||
if (timestamp > 9999999999) {
|
||||
// 毫秒级时间戳
|
||||
dateTime = DateTime.fromMillisecondsSinceEpoch(timestamp);
|
||||
} else {
|
||||
// 秒级时间戳
|
||||
dateTime = DateTime.fromMillisecondsSinceEpoch(timestamp * 1000);
|
||||
}
|
||||
} else if (timestamp is String) {
|
||||
dateTime = DateTime.parse(timestamp);
|
||||
} else {
|
||||
return '未知';
|
||||
}
|
||||
return '${dateTime.year}-${dateTime.month.toString().padLeft(2, '0')}-${dateTime.day.toString().padLeft(2, '0')} ${dateTime.hour.toString().padLeft(2, '0')}:${dateTime.minute.toString().padLeft(2, '0')}';
|
||||
} catch (e) {
|
||||
return '未知';
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取图标数据
|
||||
IconData _getIconData(String iconName) {
|
||||
switch (iconName) {
|
||||
case 'phone_android':
|
||||
return Icons.phone_android;
|
||||
case 'phone_iphone':
|
||||
return Icons.phone_iphone;
|
||||
case 'tablet':
|
||||
return Icons.tablet_mac;
|
||||
case 'desktop_mac':
|
||||
return Icons.desktop_mac;
|
||||
case 'computer':
|
||||
return Icons.computer;
|
||||
default:
|
||||
return Icons.devices;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user